fmt: fix interface fields/methods alignment (#22055)

This commit is contained in:
yuyi 2024-08-16 16:35:53 +08:00 committed by GitHub
parent 384b5c466f
commit 38e23a76f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 51 additions and 41 deletions

View file

@ -30,13 +30,13 @@ pub:
pub interface Reporter { pub interface Reporter {
mut: mut:
session_start(message string, mut ts TestSession) // called once per test session, in the main thread, suitable for setting up supporting infrastructure. session_start(message string, mut ts TestSession) // called once per test session, in the main thread, suitable for setting up supporting infrastructure.
session_stop(message string, mut ts TestSession) // called once per test session, in the main thread, after everything else, suitable for summaries, creating .xml reports, uploads etc. session_stop(message string, mut ts TestSession) // called once per test session, in the main thread, after everything else, suitable for summaries, creating .xml reports, uploads etc.
worker_threads_start(files []string, mut ts TestSession) // called once per test session, in the main thread, right before all the worker threads start worker_threads_start(files []string, mut ts TestSession) // called once per test session, in the main thread, right before all the worker threads start
worker_threads_finish(mut ts TestSession) // called once per test session, in the main thread, right after all the worker threads finish worker_threads_finish(mut ts TestSession) // called once per test session, in the main thread, right after all the worker threads finish
// //
report(index int, log_msg LogMessage) // called once per each message, that will be shown (ok/fail/skip etc), only in the reporting thread. report(index int, log_msg LogMessage) // called once per each message, that will be shown (ok/fail/skip etc), only in the reporting thread.
report_stop() // called just once after all messages are processed, only in the reporting thread, but before stop_session. report_stop() // called just once after all messages are processed, only in the reporting thread, but before stop_session.
// //
// TODO: reconsider, whether the next methods, should be kept for all reporters, or just moved inside the normal reporter, to simplify the interface // TODO: reconsider, whether the next methods, should be kept for all reporters, or just moved inside the normal reporter, to simplify the interface
progress(index int, message string) progress(index int, message string)

View file

@ -1400,27 +1400,36 @@ pub fn (mut f Fmt) interface_decl(node ast.InterfaceDecl) {
} }
mut type_align := new_field_align() mut type_align := new_field_align()
mut comment_align := new_field_align() mut comment_align := new_field_align(use_threshold: true)
mut default_expr_align := new_field_align() mut default_expr_align := new_field_align(use_threshold: true)
mut attr_align := new_field_align() mut attr_align := new_field_align(use_threshold: true)
mut field_types := []string{cap: node.fields.len} mut field_types := []string{cap: node.fields.len}
// Calculate the alignments first // Calculate the alignments first
f.calculate_alignment(node.fields, mut type_align, mut comment_align, mut default_expr_align, mut f.calculate_alignment(node.fields, mut type_align, mut comment_align, mut default_expr_align, mut
attr_align, mut field_types) attr_align, mut field_types)
mut method_comment_align := new_field_align(use_threshold: true)
for method in node.methods {
end_comments := method.comments.filter(it.pos.pos > method.pos.pos)
if end_comments.len > 0 {
method_str := f.table.stringify_fn_decl(&method, f.cur_mod, f.mod2alias, false).all_after_first('fn ')
method_comment_align.add_info(method_str.len, method.pos.line_nr)
}
}
// TODO: alignment, comments, etc. // TODO: alignment, comments, etc.
for field in immut_fields { for field in immut_fields {
if field.has_prev_newline { if field.has_prev_newline {
f.writeln('') f.writeln('')
} }
f.interface_field(field, type_align.max_len(field.pos.line_nr)) f.interface_field(field, mut type_align, mut comment_align)
} }
for method in immut_methods { for method in immut_methods {
if method.has_prev_newline { if method.has_prev_newline {
f.writeln('') f.writeln('')
} }
f.interface_method(method) f.interface_method(method, mut method_comment_align)
} }
if mut_fields.len + mut_methods.len > 0 { if mut_fields.len + mut_methods.len > 0 {
f.writeln('mut:') f.writeln('mut:')
@ -1428,13 +1437,13 @@ pub fn (mut f Fmt) interface_decl(node ast.InterfaceDecl) {
if field.has_prev_newline { if field.has_prev_newline {
f.writeln('') f.writeln('')
} }
f.interface_field(field, type_align.max_len(field.pos.line_nr)) f.interface_field(field, mut type_align, mut comment_align)
} }
for method in mut_methods { for method in mut_methods {
if method.has_prev_newline { if method.has_prev_newline {
f.writeln('') f.writeln('')
} }
f.interface_method(method) f.interface_method(method, mut method_comment_align)
} }
} }
f.writeln('}\n') f.writeln('}\n')
@ -1497,7 +1506,7 @@ pub fn (mut f Fmt) calculate_alignment(fields []ast.StructField, mut type_align
} }
} }
pub fn (mut f Fmt) interface_field(field ast.StructField, max_len int) { pub fn (mut f Fmt) interface_field(field ast.StructField, mut type_align FieldAlign, mut comment_align FieldAlign) {
ft := f.no_cur_mod(f.table.type_to_str_using_aliases(field.typ, f.mod2alias)) ft := f.no_cur_mod(f.table.type_to_str_using_aliases(field.typ, f.mod2alias))
mut pre_cmts, mut end_cmts, mut next_line_cmts := []ast.Comment{}, []ast.Comment{}, []ast.Comment{} mut pre_cmts, mut end_cmts, mut next_line_cmts := []ast.Comment{}, []ast.Comment{}, []ast.Comment{}
for cmt in field.comments { for cmt in field.comments {
@ -1507,11 +1516,9 @@ pub fn (mut f Fmt) interface_field(field ast.StructField, max_len int) {
else { end_cmts << cmt } else { end_cmts << cmt }
} }
} }
before_len := f.line_len
if pre_cmts.len > 0 { if pre_cmts.len > 0 {
f.comments(pre_cmts, level: .indent) f.comments(pre_cmts, level: .indent)
} }
comments_len := f.line_len - before_len
sym := f.table.sym(field.typ) sym := f.table.sym(field.typ)
if sym.info is ast.Struct { if sym.info is ast.Struct {
@ -1525,10 +1532,12 @@ pub fn (mut f Fmt) interface_field(field ast.StructField, max_len int) {
f.write('\t${field.name} ') f.write('\t${field.name} ')
} }
if !(sym.info is ast.Struct && sym.info.is_anon) { if !(sym.info is ast.Struct && sym.info.is_anon) {
f.write(strings.repeat(` `, max_len - field.name.len - comments_len)) f.write(strings.repeat(` `, type_align.max_len(field.pos.line_nr) - field.name.len))
f.write(ft) f.write(ft)
} }
if end_cmts.len > 0 { if end_cmts.len > 0 {
f.write(strings.repeat(` `, comment_align.max_len(field.pos.line_nr) - ft.len))
f.write(' ')
f.comments(end_cmts, level: .indent) f.comments(end_cmts, level: .indent)
} else { } else {
f.writeln('') f.writeln('')
@ -1539,16 +1548,22 @@ pub fn (mut f Fmt) interface_field(field ast.StructField, max_len int) {
f.mark_types_import_as_used(field.typ) f.mark_types_import_as_used(field.typ)
} }
pub fn (mut f Fmt) interface_method(method ast.FnDecl) { pub fn (mut f Fmt) interface_method(method ast.FnDecl, mut comment_align FieldAlign) {
before_comments := method.comments.filter(it.pos.pos < method.pos.pos) before_comments := method.comments.filter(it.pos.pos < method.pos.pos)
end_comments := method.comments.filter(it.pos.pos > method.pos.pos) end_comments := method.comments.filter(it.pos.pos > method.pos.pos)
if before_comments.len > 0 { if before_comments.len > 0 {
f.comments(before_comments, level: .indent) f.comments(before_comments, level: .indent)
} }
f.write('\t') f.write('\t')
f.write(f.table.stringify_fn_decl(&method, f.cur_mod, f.mod2alias, false).all_after_first('fn ')) method_str := f.table.stringify_fn_decl(&method, f.cur_mod, f.mod2alias, false).all_after_first('fn ')
f.comments(end_comments, same_line: true, has_nl: false, level: .indent) f.write(method_str)
f.writeln('') if end_comments.len > 0 {
f.write(strings.repeat(` `, comment_align.max_len(method.pos.line_nr) - method_str.len))
f.write(' ')
f.comments(end_comments, level: .indent)
} else {
f.writeln('')
}
f.comments(method.next_comments, level: .indent) f.comments(method.next_comments, level: .indent)
for param in method.params { for param in method.params {
f.mark_types_import_as_used(param.typ) f.mark_types_import_as_used(param.typ)

View file

@ -1,6 +1,6 @@
pub interface ReaderWriter { pub interface ReaderWriter {
read(mut buf []u8) ?int // from Reader read(mut buf []u8) ?int // from Reader
write(buf []u8) ?int // from Writer write(buf []u8) ?int // from Writer
} }
interface Speaker { interface Speaker {
@ -38,10 +38,10 @@ mut:
assert_fails u64 assert_fails u64
test_fn_info &TestFnMetaInfo // filled in by generated code, before .fn_start() is called. test_fn_info &TestFnMetaInfo // filled in by generated code, before .fn_start() is called.
start(ntests int) // called before all tests, you can initialise private data here. ntests is the number of test functions in the _test.v file. start(ntests int) // called before all tests, you can initialise private data here. ntests is the number of test functions in the _test.v file.
finish() // called after all tests are finished, you should free all the private data here. finish() // called after all tests are finished, you should free all the private data here.
// //
fn_start() // called at the start of each test_ function fn_start() // called at the start of each test_ function
fn_pass() // called at the end of each test_ function, with no failed assertion fn_pass() // called at the end of each test_ function, with no failed assertion
fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) // called only for `fn test_xyz() ? { return error('message') }` fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) // called only for `fn test_xyz() ? { return error('message') }`
fn_fail() // called at the end of each test_ function, with a failed assertion, *or* returning an error fn_fail() // called at the end of each test_ function, with a failed assertion, *or* returning an error
// //

View file

@ -13,29 +13,28 @@ __global test_runner TestRunner
interface TestRunner { interface TestRunner {
mut: mut:
file_test_info VTestFileMetaInfo // filled in by generated code, before .start() is called. file_test_info VTestFileMetaInfo // filled in by generated code, before .start() is called.
fn_test_info VTestFnMetaInfo // filled in by generated code, before .fn_start() is called. fn_test_info VTestFnMetaInfo // filled in by generated code, before .fn_start() is called.
fn_assert_passes u64 // reset this to 0 in .fn_start(), increase it in .assert_pass() fn_assert_passes u64 // reset this to 0 in .fn_start(), increase it in .assert_pass()
fn_passes u64 // increase this in .fn_pass() fn_passes u64 // increase this in .fn_pass()
fn_fails u64 // increase this in .fn_fails() fn_fails u64 // increase this in .fn_fails()
total_assert_passes u64 // increase this in .assert_pass() total_assert_passes u64 // increase this in .assert_pass()
total_assert_fails u64 // increase this in .assert_fail() total_assert_fails u64 // increase this in .assert_fail()
start(ntests int) // called before all tests, you can initialise private data here. ntests is the number of test functions in the _test.v file. start(ntests int) // called before all tests, you can initialise private data here. ntests is the number of test functions in the _test.v file.
finish() // called after all tests are finished, you can print some stats if you want here. finish() // called after all tests are finished, you can print some stats if you want here.
exit_code() int // called right after finish(), it should return the exit code, that the test program will exit with. exit_code() int // called right after finish(), it should return the exit code, that the test program will exit with.
//
fn_start() bool // called before the start of each test_ function. Return false, if the function should be skipped. fn_start() bool // called before the start of each test_ function. Return false, if the function should be skipped.
fn_pass() // called after the end of each test_ function, with NO failed assertion. fn_pass() // called after the end of each test_ function, with NO failed assertion.
fn_fail() // called after the end of each test_ function, with a failed assertion, *or* returning an error. fn_fail() // called after the end of each test_ function, with a failed assertion, *or* returning an error.
fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) // called only for `fn test_xyz() ? { return error('message') }`, before .fn_fail() is called. fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) // called only for `fn test_xyz() ? { return error('message') }`, before .fn_fail() is called.
//
assert_pass(i &VAssertMetaInfo) // called after each `assert true`. assert_pass(i &VAssertMetaInfo) // called after each `assert true`.
assert_fail(i &VAssertMetaInfo) // called after each `assert false`. assert_fail(i &VAssertMetaInfo) // called after each `assert false`.
//
free() // you should free all the private data of your runner here. free() // you should free all the private data of your runner here.
} }
//
struct VTestFileMetaInfo { struct VTestFileMetaInfo {
file string file string
tests int tests int
@ -57,8 +56,6 @@ fn (i &VTestFileMetaInfo) free() {
} }
} }
//
struct VTestFnMetaInfo { struct VTestFnMetaInfo {
name string name string
mod string mod string
@ -85,8 +82,6 @@ fn (i &VTestFnMetaInfo) free() {
} }
} }
//
@[typedef] @[typedef]
pub struct C.main__TestRunner { pub struct C.main__TestRunner {
mut: mut: