fmt: align struct field comments (#7632)

pull/7844/head^2
zakuro 2021-01-04 05:10:25 +09:00 committed by GitHub
parent 095857d59b
commit dd516858d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 267 additions and 162 deletions

View File

@ -580,6 +580,60 @@ pub fn (mut f Fmt) type_decl(node ast.TypeDecl) {
f.writeln('\n') f.writeln('\n')
} }
const (
threshold_to_align_struct = 8
)
struct CommentAndExprAlignInfo {
mut:
max_attrs_len int
max_type_len int
first_line int
last_line int
}
fn (mut list []CommentAndExprAlignInfo) add_new_info(attrs_len int, type_len int, line int) {
list << CommentAndExprAlignInfo{
max_attrs_len: attrs_len
max_type_len: type_len
first_line: line
last_line: line
}
}
[inline]
fn abs(v int) int {
return if v >= 0 {
v
} else {
-v
}
}
fn (mut list []CommentAndExprAlignInfo) add_info(attrs_len int, type_len int, line int) {
if list.len == 0 {
list.add_new_info(attrs_len, type_len, line)
return
}
i := list.len - 1
if line - list[i].last_line > 1 {
list.add_new_info(attrs_len, type_len, line)
return
}
d_len := abs(list[i].max_attrs_len - attrs_len) + abs(list[i].max_type_len - type_len)
if !(d_len < threshold_to_align_struct) {
list.add_new_info(attrs_len, type_len, line)
return
}
list[i].last_line = line
if attrs_len > list[i].max_attrs_len {
list[i].max_attrs_len = attrs_len
}
if type_len > list[i].max_type_len {
list[i].max_type_len = type_len
}
}
pub fn (mut f Fmt) struct_decl(node ast.StructDecl) { pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
f.attrs(node.attrs) f.attrs(node.attrs)
if node.is_pub { if node.is_pub {
@ -605,14 +659,28 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
} }
f.writeln(' {') f.writeln(' {')
mut max := 0 mut max := 0
mut max_type := 0 mut max_type_len := 0
mut comment_aligns := []CommentAndExprAlignInfo{}
mut default_expr_aligns := []CommentAndExprAlignInfo{}
mut field_types := []string{cap: node.fields.len} mut field_types := []string{cap: node.fields.len}
for field in node.fields { for i, field in node.fields {
mut ft := f.no_cur_mod(f.table.type_to_str(field.typ))
if !ft.contains('C.') && !ft.contains('JS.') && !ft.contains('fn (') {
ft = f.short_module(ft)
}
field_types << ft
if ft.len > max_type_len {
max_type_len = ft.len
}
attrs_len := inline_attrs_len(field.attrs)
end_pos := field.pos.pos + field.pos.len end_pos := field.pos.pos + field.pos.len
mut comments_len := 0 // Length of comments between field name and type mut comments_len := 0 // Length of comments between field name and type
for comment in field.comments { for comment in field.comments {
if comment.pos.pos >= end_pos { if comment.pos.pos >= end_pos {
break if comment.pos.line_nr == field.pos.line_nr {
comment_aligns.add_info(attrs_len, field_types[i].len, comment.pos.line_nr)
}
continue
} }
if comment.pos.pos > field.pos.pos { if comment.pos.pos > field.pos.pos {
comments_len += '/* $comment.text */ '.len comments_len += '/* $comment.text */ '.len
@ -621,19 +689,16 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
if comments_len + field.name.len > max { if comments_len + field.name.len > max {
max = comments_len + field.name.len max = comments_len + field.name.len
} }
mut ft := f.no_cur_mod(f.table.type_to_str(field.typ)) if field.has_default_expr {
if !ft.contains('C.') && !ft.contains('JS.') && !ft.contains('fn (') { default_expr_aligns.add_info(attrs_len, field_types[i].len, field.pos.line_nr)
ft = f.short_module(ft)
}
field_types << ft
if ft.len > max_type {
max_type = ft.len
} }
} }
for embed in node.embeds { for embed in node.embeds {
styp := f.table.type_to_str(embed.typ) styp := f.table.type_to_str(embed.typ)
f.writeln('\t$styp') f.writeln('\t$styp')
} }
mut comment_align_i := 0
mut default_expr_align_i := 0
for i, field in node.fields { for i, field in node.fields {
if i == node.mut_pos { if i == node.mut_pos {
f.writeln('mut:') f.writeln('mut:')
@ -665,11 +730,21 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
} }
f.write(strings.repeat(` `, max - field.name.len - comments_len)) f.write(strings.repeat(` `, max - field.name.len - comments_len))
f.write(field_types[i]) f.write(field_types[i])
if field.attrs.len > 0 { after_type_pad_len := max_type_len - field_types[i].len
f.write(strings.repeat(` `, max_type - field_types[i].len)) attrs_len := inline_attrs_len(field.attrs)
has_attrs := field.attrs.len > 0
if has_attrs {
f.write(strings.repeat(` `, after_type_pad_len))
f.inline_attrs(field.attrs) f.inline_attrs(field.attrs)
} }
if field.has_default_expr { if field.has_default_expr {
mut align := default_expr_aligns[default_expr_align_i]
if align.last_line < field.pos.line_nr {
default_expr_align_i++
align = default_expr_aligns[default_expr_align_i]
}
pad_len := align.max_attrs_len - attrs_len + align.max_type_len - field_types[i].len
f.write(strings.repeat(` `, pad_len))
f.write(' = ') f.write(' = ')
f.prefix_expr_cast_expr(field.default_expr) f.prefix_expr_cast_expr(field.default_expr)
} }
@ -678,6 +753,15 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
if comments[comm_idx].pos.line_nr > field.pos.line_nr { if comments[comm_idx].pos.line_nr > field.pos.line_nr {
f.writeln('') f.writeln('')
} else { } else {
if !field.has_default_expr {
mut align := comment_aligns[comment_align_i]
if align.last_line < field.pos.line_nr {
comment_align_i++
align = comment_aligns[comment_align_i]
}
pad_len := align.max_attrs_len - attrs_len + align.max_type_len - field_types[i].len
f.write(strings.repeat(` `, pad_len))
}
f.write(' ') f.write(' ')
} }
f.comments(comments[comm_idx..], level: .indent) f.comments(comments[comm_idx..], level: .indent)
@ -1230,6 +1314,21 @@ fn (mut f Fmt) inline_attrs(attrs []table.Attr) {
f.write(']') f.write(']')
} }
fn inline_attrs_len(attrs []table.Attr) int {
if attrs.len == 0 {
return 0
}
mut n := 2 // ' ['.len
for i, attr in attrs {
if i > 0 {
n += 2 // '; '.len
}
n += '$attr'.len
}
n++ // ']'.len
return n
}
enum CommentsLevel { enum CommentsLevel {
keep keep
indent indent

View File

@ -1,15 +1,18 @@
struct User { struct User {
name string name string // name
name2 ustring // name2
very_long_field bool very_long_field bool
age int age int // age
very_long_type_field1 very_looooog_type // long
very_long_type_field2 very_loooooooong_type // long
} }
struct Foo { struct Foo {
field1 int field1 int // f1
field2 string field2 string // f2
pub: pub:
public_field1 int public_field1 int // f1
public_field2 f64 public_field2 f64 // f2
mut: mut:
mut_field string mut_field string
pub mut: pub mut:

View File

@ -1,15 +1,18 @@
struct User { struct User {
name string name string // name
name2 ustring // name2
very_long_field bool very_long_field bool
age int age int // age
very_long_type_field1 very_looooog_type // long
very_long_type_field2 very_loooooooong_type // long
} }
struct Foo { struct Foo {
field1 int field1 int // f1
field2 string field2 string // f2
pub: pub:
public_field1 int public_field1 int // f1
public_field2 f64 public_field2 f64 // f2
mut: mut:
mut_field string mut_field string
pub mut: pub mut: