@@ -6,6 +6,14 @@ module fmt
66import v.ast
77
88pub fn (mut f Fmt) attrs (attrs []ast.Attr) {
9+ if attrs_have_call_syntax (attrs) {
10+ f.call_syntax_attrs (attrs)
11+ return
12+ }
13+ f.legacy_attrs (attrs)
14+ }
15+
16+ fn (mut f Fmt) legacy_attrs (attrs []ast.Attr) {
917 mut sorted_attrs := attrs.clone ()
1018 // Sort the attributes. The ones with arguments come first
1119 sorted_attrs.sort_with_compare (fn (a & ast.Attr, b & ast.Attr) int {
@@ -21,6 +29,24 @@ pub fn (mut f Fmt) attrs(attrs []ast.Attr) {
2129 }
2230}
2331
32+ fn (mut f Fmt) call_syntax_attrs (attrs []ast.Attr) {
33+ mut i := 0
34+ for i < attrs.len {
35+ if attrs[i].call_name.len > 0 {
36+ group , next_idx := attr_call_group (attrs, i)
37+ f.writeln ('@[${attr_call_group_str (group )}]' )
38+ i = next_idx
39+ continue
40+ }
41+ mut j := i
42+ for j < attrs.len && attrs[j].call_name.len == 0 {
43+ j++
44+ }
45+ f.legacy_attrs (attrs[i..j])
46+ i = j
47+ }
48+ }
49+
2450@[params]
2551pub struct AttrsOptions {
2652pub :
@@ -31,6 +57,22 @@ pub fn (mut f Fmt) single_line_attrs(attrs []ast.Attr, options AttrsOptions) {
3157 if attrs.len == 0 {
3258 return
3359 }
60+ if attrs_have_call_syntax (attrs) {
61+ if options.same_line {
62+ f.write (' ' )
63+ }
64+ f.write ('@[' )
65+ f.write (single_line_attrs_text (attrs))
66+ f.write (']' )
67+ if ! options.same_line {
68+ f.writeln ('' )
69+ }
70+ return
71+ }
72+ f.legacy_single_line_attrs (attrs, options)
73+ }
74+
75+ fn (mut f Fmt) legacy_single_line_attrs (attrs []ast.Attr, options AttrsOptions) {
3476 mut sorted_attrs := attrs.clone ()
3577 sorted_attrs.sort (a.name < b.name)
3678 if options.same_line {
@@ -53,13 +95,75 @@ fn inline_attrs_len(attrs []ast.Attr) int {
5395 if attrs.len == 0 {
5496 return 0
5597 }
56- mut n := 2 // ' ['.len
57- for i, attr in attrs {
58- if i > 0 {
59- n + = 2 // '; '.len
98+ return 3 + single_line_attrs_text (attrs).len // ' [' + ']'.len
99+ }
100+
101+ fn attrs_have_call_syntax (attrs []ast.Attr) bool {
102+ return attrs.any (it .call_name.len > 0 )
103+ }
104+
105+ fn single_line_attrs_text (attrs []ast.Attr) string {
106+ if ! attrs_have_call_syntax (attrs) {
107+ mut sorted_attrs := attrs.clone ()
108+ sorted_attrs.sort (a.name < b.name)
109+ mut parts := []string {cap: sorted_attrs.len}
110+ for attr in sorted_attrs {
111+ parts << '${attr }'
112+ }
113+ return parts.join ('; ' )
114+ }
115+ mut parts := []string {}
116+ mut i := 0
117+ for i < attrs.len {
118+ if attrs[i].call_name.len > 0 {
119+ group , next_idx := attr_call_group (attrs, i)
120+ parts << attr_call_group_str (group)
121+ i = next_idx
122+ continue
123+ }
124+ parts << '${attrs [i ]}'
125+ i++
126+ }
127+ return parts.join ('; ' )
128+ }
129+
130+ fn attr_call_group (attrs []ast.Attr, start int ) ([]ast.Attr, int ) {
131+ first := attrs[start]
132+ mut end := start + 1
133+ for end < attrs.len && attrs[end].call_name == first.call_name
134+ && attrs[end].pos.pos == first.pos.pos {
135+ end++
136+ }
137+ return attrs[start..end], end
138+ }
139+
140+ fn attr_call_group_str (attrs []ast.Attr) string {
141+ if attrs.len == 0 {
142+ return ''
143+ }
144+ mut args := []string {}
145+ for attr in attrs {
146+ if ! attr.has_arg {
147+ continue
148+ }
149+ mut arg := ''
150+ if attr.call_arg_name.len > 0 {
151+ arg + = '${attr .call_arg_name }: '
60152 }
61- n + = '${attr }' .len
153+ arg + = attr_value_str (attr)
154+ args << arg
155+ }
156+ if args.len == 0 {
157+ return '${attrs [0 ].call_name }()'
158+ }
159+ return '${attrs [0 ].call_name }(${args .join (', ')})'
160+ }
161+
162+ fn attr_value_str (attr ast.Attr) string {
163+ quote := if attr.quote == `"` { '"' } else { "'" }
164+ return match attr.kind {
165+ .plain, .number, .bool { attr.arg }
166+ .string { '${quote }${attr .arg }${quote }' }
167+ .comptime_define { 'if ${attr .arg }' }
62168 }
63- n++ // ']'.len
64- return n
65169}
0 commit comments