From d96a1b8a5f3756d6841b177f035b128b26c6ee8a Mon Sep 17 00:00:00 2001 From: Lukas Neubert Date: Sun, 10 Jan 2021 17:39:37 +0100 Subject: [PATCH] fmt: intelligent newlines for trailing arg syntax (#7748) --- vlib/v/fmt/fmt.v | 105 ++++++++++-------- .../fmt/tests/fn_trailing_arg_syntax_keep.vv | 12 +- vlib/v/parser/struct.v | 6 +- vlib/vweb/tests/vweb_test.v | 7 +- 4 files changed, 72 insertions(+), 58 deletions(-) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 928882d1d5..dd4f9970ad 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -19,34 +19,35 @@ const ( pub struct Fmt { pub mut: - table &table.Table - out_imports strings.Builder - out strings.Builder - out_save strings.Builder - indent int - empty_line bool - line_len int - buffering bool // expressions will be analyzed later by adjust_complete_line() before finally written - expr_bufs []string // and stored here in the meantime (expr_bufs.len-1 = penalties.len = precedences.len) - penalties []int // how hard should it be to break line after each expression - precedences []int // operator/parenthese precedences for operator at end of each expression - par_level int // how many parentheses are put around the current expression - array_init_break []bool // line breaks after elements in hierarchy level of multi dimensional array - array_init_depth int // current level of hierarchie in array init - single_line_if bool - cur_mod string - file ast.File - did_imports bool - is_assign bool - auto_imports []string // automatically inserted imports that the user does not need to specify - import_pos int // position of the imports in the resulting string for later autoimports insertion - used_imports []string // to remove unused imports - is_debug bool - mod2alias map[string]string // for `import time as t`, will contain: 'time'=>'t' - use_short_fn_args bool - it_name string // the name to replace `it` with - inside_lambda bool - is_mbranch_expr bool // math a { x...y { } } + table &table.Table + out_imports strings.Builder + out strings.Builder + out_save strings.Builder + indent int + empty_line bool + line_len int + buffering bool // expressions will be analyzed later by adjust_complete_line() before finally written + expr_bufs []string // and stored here in the meantime (expr_bufs.len-1 = penalties.len = precedences.len) + penalties []int // how hard should it be to break line after each expression + precedences []int // operator/parenthese precedences for operator at end of each expression + par_level int // how many parentheses are put around the current expression + array_init_break []bool // line breaks after elements in hierarchy level of multi dimensional array + array_init_depth int // current level of hierarchie in array init + single_line_if bool + cur_mod string + file ast.File + did_imports bool + is_assign bool + auto_imports []string // automatically inserted imports that the user forgot to specify + import_pos int // position of the imports in the resulting string for later autoimports insertion + used_imports []string // to remove unused imports + is_debug bool + mod2alias map[string]string // for `import time as t`, will contain: 'time'=>'t' + use_short_fn_args bool + single_line_fields bool // should struct fields be on a single line + it_name string // the name to replace `it` with + inside_lambda bool + is_mbranch_expr bool // math a { x...y { } } } pub fn fmt(file ast.File, table &table.Table, is_debug bool) string { @@ -1263,6 +1264,7 @@ pub fn (mut f Fmt) wrap_long_line(penalty_idx int, add_indent bool) bool { } pub fn (mut f Fmt) call_args(args []ast.CallArg) { + f.single_line_fields = true for i, arg in args { if arg.is_mut { f.write(arg.share.str() + ' ') @@ -1275,6 +1277,7 @@ pub fn (mut f Fmt) call_args(args []ast.CallArg) { f.write(', ') } } + f.single_line_fields = false } pub fn (mut f Fmt) or_expr(or_block ast.OrExpr) { @@ -1646,8 +1649,8 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) { old_short_arg_state := f.use_short_fn_args f.use_short_fn_args = false if node.args.len > 0 && node.args.last().expr is ast.StructInit { - struct_typ := (node.args.last().expr as ast.StructInit).typ - if struct_typ == table.void_type { + struct_expr := node.args.last().expr as ast.StructInit + if struct_expr.typ == table.void_type { f.use_short_fn_args = true } } @@ -2068,17 +2071,23 @@ pub fn (mut f Fmt) struct_init(it ast.StructInit) { } else { use_short_args := f.use_short_fn_args f.use_short_fn_args = false - mut multiline_short_args := it.pre_comments.len > 0 + mut single_line_fields := f.single_line_fields + f.single_line_fields = false + if it.pos.line_nr < it.pos.last_line || it.pre_comments.len > 0 { + single_line_fields = false + } if !use_short_args { - f.writeln('$name{') - } else { - if multiline_short_args { - f.writeln('') + f.write('$name{') + if single_line_fields { + f.write(' ') } } - init_start := f.out.len - f.indent++ - short_args_loop: for { + fields_start := f.out.len + fields_loop: for { + if !single_line_fields { + f.writeln('') + f.indent++ + } f.comments(it.pre_comments, inline: true, has_nl: true, level: .keep) if it.has_update_expr { f.write('...') @@ -2090,7 +2099,7 @@ pub fn (mut f Fmt) struct_init(it ast.StructInit) { f.write('$field.name: ') f.prefix_expr_cast_expr(field.expr) f.comments(field.comments, inline: true, has_nl: false, level: .indent) - if use_short_args && !multiline_short_args { + if single_line_fields { if i < it.fields.len - 1 { f.write(', ') } @@ -2098,21 +2107,25 @@ pub fn (mut f Fmt) struct_init(it ast.StructInit) { f.writeln('') } f.comments(field.next_comments, inline: false, has_nl: true, level: .keep) - if use_short_args && !multiline_short_args && + if single_line_fields && (field.comments.len > 0 || field.next_comments.len > 0 || !expr_is_single_line(field.expr) || f.line_len > max_len.last()) { - multiline_short_args = true - f.out.go_back_to(init_start) - f.line_len = init_start + single_line_fields = false + f.out.go_back_to(fields_start) + f.line_len = fields_start f.remove_new_line() - f.writeln('') - continue short_args_loop + continue fields_loop } } break } - f.indent-- + if !single_line_fields { + f.indent-- + } if !use_short_args { + if single_line_fields { + f.write(' ') + } f.write('}') } } diff --git a/vlib/v/fmt/tests/fn_trailing_arg_syntax_keep.vv b/vlib/v/fmt/tests/fn_trailing_arg_syntax_keep.vv index cf0f3a08c1..7341b29718 100644 --- a/vlib/v/fmt/tests/fn_trailing_arg_syntax_keep.vv +++ b/vlib/v/fmt/tests/fn_trailing_arg_syntax_keep.vv @@ -13,10 +13,14 @@ struct Baz { fn main() { bar_func(x: 'bar', y: 13, z: 42) + bar_func( + x: 'bar' + y: 13 + z: 42 + ) foo_func(Baz{ x: 'Baz as Foo sumtype' }) - bar_func(x: 'bar', y: 2, z: 3, a: 4) func_from_other_file(val: 'something') bar_func( // pre comment @@ -43,8 +47,6 @@ fn main() { ) } -fn bar_func(bar Bar) { -} +fn bar_func(bar Bar) {} -fn foo_func(f Foo) { -} +fn foo_func(f Foo) {} diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 28fb9b6b92..e693c25d65 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -408,11 +408,7 @@ fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit { update_expr: update_expr update_expr_comments: update_expr_comments has_update_expr: has_update_expr - pos: token.Position{ - line_nr: first_pos.line_nr - pos: first_pos.pos - len: last_pos.pos - first_pos.pos + last_pos.len - } + pos: first_pos.extend_with_last_line(last_pos, p.tok.line_nr) is_short: no_keys pre_comments: pre_comments } diff --git a/vlib/vweb/tests/vweb_test.v b/vlib/vweb/tests/vweb_test.v index 9fac04b8db..4ab7558b90 100644 --- a/vlib/vweb/tests/vweb_test.v +++ b/vlib/vweb/tests/vweb_test.v @@ -197,9 +197,12 @@ fn test_http_client_shutdown_does_not_work_without_a_cookie() { fn testsuite_end() { // This test is guaranteed to be called last. // It sends a request to the server to shutdown. - x := http.fetch('http://127.0.0.1:$sport/shutdown', method: .get, cookies: { + x := http.fetch('http://127.0.0.1:$sport/shutdown', + method: .get + cookies: { 'skey': 'superman' - }) or { + } + ) or { assert err == '' return }