prettycsharp 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,623 @@
1
+ """Declarations: the file, namespaces, types, members, attributes and directives."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+
7
+ from prettycsharp.doc import HARDLINE, LINE, SOFTLINE, TRIM_INDENT, Doc, group, indent, join
8
+ from prettycsharp.printer.core import split
9
+ from prettycsharp.printer.statements import Statements
10
+ from prettycsharp.rewrites import using_key
11
+ from prettycsharp.syntax import DIRECTIVE_TYPES, Node
12
+
13
+ TYPE_DECLARATIONS = frozenset(
14
+ {
15
+ "class_declaration",
16
+ "struct_declaration",
17
+ "interface_declaration",
18
+ "record_declaration",
19
+ "enum_declaration",
20
+ }
21
+ )
22
+
23
+ MEMBER_DECLARATIONS = frozenset(
24
+ {
25
+ "method_declaration",
26
+ "constructor_declaration",
27
+ "destructor_declaration",
28
+ "operator_declaration",
29
+ "conversion_operator_declaration",
30
+ "property_declaration",
31
+ "indexer_declaration",
32
+ "event_declaration",
33
+ "event_field_declaration",
34
+ "field_declaration",
35
+ "delegate_declaration",
36
+ "local_function_statement",
37
+ }
38
+ )
39
+
40
+ # Children printed after the header: what follows a member's signature.
41
+ _TAIL_FIELDS = ("body", "accessors")
42
+ _NO_SPACE_BEFORE = frozenset(
43
+ {"parameter_list", "bracketed_parameter_list", "type_parameter_list", "argument_list", "bracketed_argument_list"}
44
+ )
45
+
46
+
47
+ class Declarations(Statements):
48
+ # The file -------------------------------------------------------------
49
+
50
+ def p_compilation_unit(self, node: Node) -> Doc:
51
+ items = node.children
52
+ parts: list[Doc] = []
53
+ if items:
54
+ aligned = (
55
+ self.align_runs(items, self.assignment_split, self.top_blank) if self.settings.align_assignments else None
56
+ )
57
+ parts.append(self.print_list(items, self.top_blank, aligned=aligned))
58
+ trailing = self.file.trailing_comments
59
+ if trailing:
60
+ holder = Node(type="eof", text="")
61
+ holder.leading = list(trailing)
62
+ comments = self.leading_comments(holder, first_blank_allowed=False)
63
+ assert isinstance(comments, list)
64
+ while comments and comments[-1] is HARDLINE:
65
+ comments.pop()
66
+ if items:
67
+ parts.append(HARDLINE)
68
+ if trailing[0].newlines_before >= 2 and self.settings.max_blank_lines > 0:
69
+ parts.append(HARDLINE)
70
+ parts.append(comments)
71
+ return parts
72
+
73
+ def top_blank(self, previous: Node, item: Node) -> bool:
74
+ if previous.type == "file_scoped_namespace_declaration":
75
+ return self.settings.max_blank_lines > 0
76
+ if previous.type in DIRECTIVE_TYPES or item.type in DIRECTIVE_TYPES:
77
+ return self.directive_blank(previous, item)
78
+ if previous.type == item.type == "using_directive":
79
+ return self.using_blank(previous, item)
80
+ if previous.type == item.type and previous.type in ("extern_alias_directive", "global_attribute"):
81
+ return False
82
+ if previous.type == "global_statement" and item.type == "global_statement":
83
+ return self.statement_blank(previous, item)
84
+ return self.settings.max_blank_lines > 0
85
+
86
+ def using_blank(self, previous: Node, item: Node) -> bool:
87
+ """Usings stay together, except between groups when the order is grouped."""
88
+ if self.settings.using_order != "system_first_grouped" or self.settings.max_blank_lines == 0:
89
+ return False
90
+ return _using_group(previous) != _using_group(item)
91
+
92
+ def directive_blank(self, previous: Node, item: Node) -> bool:
93
+ if self.settings.regions == "normalize":
94
+ if previous.type == "preproc_region" or item.type == "preproc_endregion":
95
+ return True
96
+ return self.has_blank_before(item)
97
+
98
+ # Directives -----------------------------------------------------------
99
+
100
+ def p_preproc_if(self, node: Node) -> Doc:
101
+ return self.conditional_directive(node)
102
+
103
+ def p_preproc_elif(self, node: Node) -> Doc:
104
+ return self.conditional_directive(node)
105
+
106
+ def p_preproc_else(self, node: Node) -> Doc:
107
+ return self.conditional_directive(node)
108
+
109
+ def conditional_directive(self, node: Node) -> Doc:
110
+ children = node.children
111
+ if not children:
112
+ return self.generic(node)
113
+ condition = node.child("condition")
114
+ header_end = children.index(condition) if condition is not None else 0
115
+ header = self.verbatim_range(children[: header_end + 1])
116
+ blank = self.current_blank()
117
+ parts: list[Doc] = [header]
118
+ # In source order: runs of items, the next branch, and #endif.
119
+ run: list[Node] = []
120
+
121
+ def flush() -> None:
122
+ if run:
123
+ parts.append(self.directive_line(run[0]))
124
+ parts.append(self.print_list(list(run), blank))
125
+ run.clear()
126
+
127
+ for child in children[header_end + 1 :]:
128
+ if child.field == "alternative" or child.text == "#endif":
129
+ flush()
130
+ parts.append(self.directive_line(child))
131
+ parts.append(self.print(child) if child.text is None else self.verbatim_range([child]))
132
+ else:
133
+ run.append(child)
134
+ flush()
135
+ return parts
136
+
137
+ def directive_line(self, node: Node) -> Doc:
138
+ """The line break before a directive line or the first item after one."""
139
+ # A directive written at column 0 stays there; #endif is a bare token.
140
+ at_zero = self.is_column_zero_directive(node) or (
141
+ node.text is not None and node.text.startswith("#") and node.column == 0 and not node.leading
142
+ )
143
+ line: Doc = HARDLINE
144
+ if self.has_blank_before(node):
145
+ line = [HARDLINE, HARDLINE]
146
+ return [line, TRIM_INDENT] if at_zero else line
147
+
148
+ def p_preproc_region(self, node: Node) -> Doc:
149
+ return self.verbatim(node)
150
+
151
+ def p_preproc_endregion(self, node: Node) -> Doc:
152
+ return self.verbatim(node)
153
+
154
+ def p_shebang_directive(self, node: Node) -> Doc:
155
+ return self.verbatim(node)
156
+
157
+ def generic_directive(self, node: Node) -> Doc:
158
+ return self.verbatim(node)
159
+
160
+ p_preproc_define = generic_directive
161
+ p_preproc_undef = generic_directive
162
+ p_preproc_pragma = generic_directive
163
+ p_preproc_nullable = generic_directive
164
+ p_preproc_error = generic_directive
165
+ p_preproc_warning = generic_directive
166
+ p_preproc_line = generic_directive
167
+ p_preproc_if_in_attribute_list = generic_directive
168
+
169
+ # Usings and namespaces --------------------------------------------------
170
+
171
+ def p_using_directive(self, node: Node) -> Doc:
172
+ return self.words(node.children)
173
+
174
+ def p_extern_alias_directive(self, node: Node) -> Doc:
175
+ return self.words(node.children)
176
+
177
+ def words(self, nodes: Sequence[Node]) -> Doc:
178
+ """Nodes separated by spaces, with none before ``;``."""
179
+ parts: list[Doc] = []
180
+ for i, child in enumerate(nodes):
181
+ if i and child.text != ";":
182
+ parts.append(" ")
183
+ parts.append(self.print(child))
184
+ return parts
185
+
186
+ def p_namespace_declaration(self, node: Node) -> Doc:
187
+ body = node.child("body")
188
+ if body is None or body.type != "declaration_list":
189
+ return self.generic(node)
190
+ index = node.children.index(body)
191
+ return [self.words(node.children[:index]), self.declaration_body(body, "namespace"), self.words(node.children[index + 1 :])]
192
+
193
+ def p_file_scoped_namespace_declaration(self, node: Node) -> Doc:
194
+ return self.words(node.children)
195
+
196
+ def declaration_body(self, body: Node, context: str) -> Doc:
197
+ if len(body.children) < 2 or body.verbatim:
198
+ return [" ", self.print(body)]
199
+ open_tok = body.children[0]
200
+ close_tok = body.children[-1]
201
+ items = body.children[1:-1]
202
+ if not items and not close_tok.leading and not open_tok.trailing:
203
+ if self.settings.empty_bodies == "inline":
204
+ return [" ", self.tok(open_tok), " ", self.tok(close_tok)]
205
+ return [self.open_brace(context), self.tok(open_tok), HARDLINE, self.tok(close_tok)]
206
+ inner: Doc = ""
207
+ if items:
208
+ inner = indent([HARDLINE, self.members(items)])
209
+ return [
210
+ self.open_brace(context),
211
+ self.tok(open_tok),
212
+ inner,
213
+ self.close_comments(close_tok),
214
+ HARDLINE,
215
+ self.tok(close_tok, leading=False),
216
+ ]
217
+
218
+ def members(self, items: Sequence[Node]) -> Doc:
219
+ aligned = (
220
+ self.align_runs(items, self.assignment_split, self.member_blank) if self.settings.align_assignments else None
221
+ )
222
+ return self.print_list(items, self.member_blank, aligned=aligned)
223
+
224
+ def member_blank(self, previous: Node, item: Node) -> bool:
225
+ if previous.type in DIRECTIVE_TYPES or item.type in DIRECTIVE_TYPES:
226
+ return self.directive_blank(previous, item)
227
+ if self.settings.max_blank_lines == 0:
228
+ return False
229
+ mode = self.settings.member_blank_lines
230
+ if mode == "preserve":
231
+ return self.has_blank_before(item)
232
+ if mode == "all":
233
+ return True
234
+ if previous.type == item.type == "using_directive":
235
+ return self.using_blank(previous, item)
236
+ if previous.type == item.type == "extern_alias_directive":
237
+ return False
238
+ if (
239
+ self.is_tight(previous)
240
+ and self.is_tight(item)
241
+ and previous.type == item.type
242
+ and not self.has_comments_before(item)
243
+ ):
244
+ return False
245
+ return True
246
+
247
+ def is_tight(self, node: Node) -> bool:
248
+ if node.type in ("field_declaration", "event_field_declaration"):
249
+ return True
250
+ if node.type == "property_declaration":
251
+ accessors = node.child("accessors")
252
+ if accessors is None:
253
+ return True
254
+ return all(a.child("body") is None for a in accessors.children if a.type == "accessor_declaration")
255
+ return False
256
+
257
+ # Types ------------------------------------------------------------------
258
+
259
+ def type_declaration(self, node: Node) -> Doc:
260
+ body = node.child("body")
261
+ if body is None:
262
+ body = node.first_of("declaration_list", "enum_member_declaration_list")
263
+ attributes, header, constraints, tail = self.split_declaration(node, body)
264
+ parts: list[Doc] = [self.attribute_lines(attributes), self.header(header)]
265
+ if constraints:
266
+ parts.append(self.constraints(constraints))
267
+ if body is not None:
268
+ if body.type == "enum_member_declaration_list":
269
+ parts.append(self.enum_body(body))
270
+ else:
271
+ parts.append(self.declaration_body(body, "type"))
272
+ parts.append(self.words(tail) if tail else "")
273
+ return parts
274
+
275
+ p_class_declaration = type_declaration
276
+ p_struct_declaration = type_declaration
277
+ p_interface_declaration = type_declaration
278
+ p_record_declaration = type_declaration
279
+ p_enum_declaration = type_declaration
280
+
281
+ def split_declaration(
282
+ self, node: Node, body: Node | None
283
+ ) -> tuple[list[Node], list[Node], list[Node], list[Node]]:
284
+ """(attribute lists, header, constraint clauses, what follows the body)."""
285
+ attributes: list[Node] = []
286
+ header: list[Node] = []
287
+ constraints: list[Node] = []
288
+ tail: list[Node] = []
289
+ seen_body = False
290
+ for child in node.children:
291
+ if child is body:
292
+ seen_body = True
293
+ elif seen_body:
294
+ tail.append(child)
295
+ elif child.type == "attribute_list" and not header:
296
+ attributes.append(child)
297
+ elif child.type == "type_parameter_constraints_clause":
298
+ constraints.append(child)
299
+ else:
300
+ header.append(child)
301
+ return attributes, header, constraints, tail
302
+
303
+ def attribute_lines(self, attributes: Sequence[Node]) -> Doc:
304
+ return [[self.print(a), HARDLINE] for a in attributes]
305
+
306
+ def header(self, nodes: Sequence[Node]) -> Doc:
307
+ parts: list[Doc] = []
308
+ previous: Node | None = None
309
+ for child in nodes:
310
+ if previous is not None and self.header_space(previous, child):
311
+ parts.append(" ")
312
+ parts.append(self.print(child))
313
+ previous = child
314
+ return parts
315
+
316
+ def header_space(self, previous: Node, child: Node) -> bool:
317
+ if child.type in _NO_SPACE_BEFORE:
318
+ return False
319
+ if previous.text == "~" or previous.type == "explicit_interface_specifier":
320
+ return False
321
+ if child.text == ";":
322
+ return False
323
+ return True
324
+
325
+ def constraints(self, clauses: Sequence[Node]) -> Doc:
326
+ return group(indent([[LINE, self.print(c)] for c in clauses]))
327
+
328
+ def p_base_list(self, node: Node) -> Doc:
329
+ if not node.children or node.children[0].text != ":":
330
+ return self.generic(node)
331
+ colon = node.children[0]
332
+ items, commas = split(node.children[1:])
333
+ docs: list[Doc] = []
334
+ for i, item in enumerate(items):
335
+ doc = self.join_tokens([(c, self.print(c)) for c in item])
336
+ if i < len(commas):
337
+ doc = [doc, self.tok(commas[i])]
338
+ docs.append(doc)
339
+ return group([self.tok(colon), indent([LINE, join(LINE, docs)])]) if len(docs) > 1 else [self.tok(colon), " ", docs[0] if docs else ""]
340
+
341
+ def p_primary_constructor_base_type(self, node: Node) -> Doc:
342
+ return self.join_tokens([(c, self.print(c)) for c in node.children])
343
+
344
+ def p_type_parameter_constraints_clause(self, node: Node) -> Doc:
345
+ colon = node.first_of(":")
346
+ if colon is None:
347
+ return self.generic(node)
348
+ index = node.children.index(colon)
349
+ items, commas = split(node.children[index + 1 :])
350
+ docs: list[Doc] = []
351
+ for i, item in enumerate(items):
352
+ doc = self.generic_sequence(item)
353
+ if i < len(commas):
354
+ doc = [doc, self.tok(commas[i])]
355
+ docs.append(doc)
356
+ return [self.words(node.children[:index]), " ", self.tok(colon), " ", join(" ", docs)]
357
+
358
+ def p_type_parameter_constraint(self, node: Node) -> Doc:
359
+ return self.generic_sequence(node.children)
360
+
361
+ def p_constructor_constraint(self, node: Node) -> Doc:
362
+ return self.join_tokens([(c, self.print(c)) for c in node.children])
363
+
364
+ # Enums ----------------------------------------------------------------
365
+
366
+ def enum_body(self, body: Node) -> Doc:
367
+ if len(body.children) < 2 or any(c.type in DIRECTIVE_TYPES for c in body.children):
368
+ return [" ", self.verbatim(body)]
369
+ open_tok = body.children[0]
370
+ close_tok = body.children[-1]
371
+ items, commas = self.items_and_commas(body)
372
+ if not items and not close_tok.leading:
373
+ if self.settings.empty_bodies == "inline":
374
+ return [" ", self.tok(open_tok), " ", self.tok(close_tok)]
375
+ return [self.open_brace("type"), self.tok(open_tok), HARDLINE, self.tok(close_tok)]
376
+ members = [item[0] for item in items if len(item) == 1]
377
+ if len(members) != len(items):
378
+ return [" ", self.verbatim(body)]
379
+ aligned: dict[int, Doc] = {}
380
+ if self.settings.align_enum_values:
381
+ aligned = self.align_runs(members, self.enum_split, lambda a, b: self.has_blank_before(b)) or {}
382
+ docs: list[Doc] = []
383
+ for i, member in enumerate(members):
384
+ doc = aligned.get(id(member)) or self.print(member)
385
+ if i < len(commas):
386
+ keep = i < len(members) - 1 or self.settings.trailing_commas != "remove"
387
+ if keep:
388
+ doc = [doc, self.tok(commas[i])]
389
+ elif i < len(members) - 1:
390
+ doc = [doc, ","]
391
+ elif self.settings.trailing_commas == "add":
392
+ doc = [doc, ","]
393
+ docs.append(doc)
394
+ lines: list[Doc] = []
395
+ for i, (member, doc) in enumerate(zip(members, docs, strict=True)):
396
+ if i:
397
+ lines.append([HARDLINE, HARDLINE] if self.has_blank_before(member) else HARDLINE)
398
+ lines.append(doc)
399
+ return [
400
+ self.open_brace("type"),
401
+ self.tok(open_tok),
402
+ indent([HARDLINE, lines]),
403
+ self.close_comments(close_tok),
404
+ HARDLINE,
405
+ self.tok(close_tok, leading=False),
406
+ ]
407
+
408
+ def enum_split(self, member: Node) -> tuple[Doc, Node, Node, Doc] | None:
409
+ equals = member.first_of("=")
410
+ value = member.child("value")
411
+ name = member.child("name")
412
+ if equals is None or value is None or name is None or member.first_of("attribute_list") is not None:
413
+ return None
414
+ return (self.print(name), equals, value, "")
415
+
416
+ def p_enum_member_declaration(self, node: Node) -> Doc:
417
+ attributes = [c for c in node.children if c.type == "attribute_list"]
418
+ rest = [c for c in node.children if c.type != "attribute_list"]
419
+ equals = next((c for c in rest if c.text == "="), None)
420
+ if equals is not None and len(rest) == 3 and rest[1] is equals:
421
+ return [self.attribute_lines(attributes), self.rhs(self.print(rest[0]), equals, rest[2])]
422
+ return [self.attribute_lines(attributes), self.words(rest)]
423
+
424
+ # Members ----------------------------------------------------------------
425
+
426
+ def member(self, node: Node) -> Doc:
427
+ body = node.child("body")
428
+ accessors = node.child("accessors")
429
+ arrow_value = node.child("value") if node.type in ("property_declaration", "indexer_declaration") else None
430
+ initializer_start = None
431
+ if node.type == "property_declaration" and accessors is not None:
432
+ equals = next((c for c in node.children if c.text == "=" and not c.named), None)
433
+ if equals is not None:
434
+ initializer_start = node.children.index(equals)
435
+ attributes: list[Node] = []
436
+ header: list[Node] = []
437
+ constraints: list[Node] = []
438
+ ctor_init: Node | None = None
439
+ tail_start = len(node.children)
440
+ for i, child in enumerate(node.children):
441
+ if child is body or child is accessors or (arrow_value is not None and child is arrow_value and child.type == "arrow_expression_clause"):
442
+ tail_start = i
443
+ break
444
+ if child.type == "attribute_list" and not header:
445
+ attributes.append(child)
446
+ elif child.type == "type_parameter_constraints_clause":
447
+ constraints.append(child)
448
+ elif child.type == "constructor_initializer":
449
+ ctor_init = child
450
+ elif child.text == ";" and i == len(node.children) - 1:
451
+ tail_start = i
452
+ break
453
+ else:
454
+ header.append(child)
455
+ parts: list[Doc] = [self.attribute_lines(attributes), self.header(header)]
456
+ if ctor_init is not None:
457
+ parts.append(group(indent([LINE, self.print(ctor_init)])))
458
+ if constraints:
459
+ parts.append(self.constraints(constraints))
460
+ rest = node.children[tail_start:]
461
+ i = 0
462
+ while i < len(rest):
463
+ child = rest[i]
464
+ if child is body and child.type == "block":
465
+ parts.append(self.block(child, "member"))
466
+ elif child.type == "arrow_expression_clause":
467
+ parts.append(self.expression_body(child))
468
+ elif child is accessors:
469
+ parts.append(self.accessor_list(child))
470
+ elif initializer_start is not None and child is node.children[initializer_start]:
471
+ value = rest[i + 1] if i + 1 < len(rest) else None
472
+ if value is not None and value.text != ";":
473
+ parts.append(self.rhs("", child, value))
474
+ i += 2
475
+ continue
476
+ parts.append([" ", self.tok(child)])
477
+ elif child.text == ";":
478
+ parts.append(self.tok(child))
479
+ else:
480
+ parts.append([" ", self.print(child)])
481
+ i += 1
482
+ return parts
483
+
484
+ p_method_declaration = member
485
+ p_constructor_declaration = member
486
+ p_destructor_declaration = member
487
+ p_operator_declaration = member
488
+ p_conversion_operator_declaration = member
489
+ p_property_declaration = member
490
+ p_indexer_declaration = member
491
+ p_event_declaration = member
492
+ p_delegate_declaration = member
493
+ p_local_function_statement = member
494
+
495
+ def p_field_declaration(self, node: Node) -> Doc:
496
+ attributes = [c for c in node.children if c.type == "attribute_list"]
497
+ rest = [c for c in node.children if c.type != "attribute_list"]
498
+ return [self.attribute_lines(attributes), self.words(rest)]
499
+
500
+ p_event_field_declaration = p_field_declaration
501
+
502
+ def p_constructor_initializer(self, node: Node) -> Doc:
503
+ if not node.children or node.children[0].text != ":":
504
+ return self.generic(node)
505
+ rest = node.children[1:]
506
+ return [self.tok(node.children[0]), " ", self.join_tokens([(c, self.print(c)) for c in rest])]
507
+
508
+ def accessor_list(self, node: Node) -> Doc:
509
+ if len(node.children) < 2 or node.verbatim:
510
+ return [" ", self.print(node)]
511
+ open_tok = node.children[0]
512
+ close_tok = node.children[-1]
513
+ accessors = node.children[1:-1]
514
+ simple = all(
515
+ a.type == "accessor_declaration"
516
+ and a.child("body") is None
517
+ and a.first_of("attribute_list") is None
518
+ and not any(t.leading or t.trailing for t in a.tokens())
519
+ for a in accessors
520
+ ) and not close_tok.leading and not open_tok.trailing
521
+ if simple and accessors:
522
+ return [" ", self.tok(open_tok), " ", join(" ", [self.print(a) for a in accessors]), " ", self.tok(close_tok)]
523
+ if not accessors and not close_tok.leading:
524
+ return [" ", self.tok(open_tok), " ", self.tok(close_tok)]
525
+ return [
526
+ self.open_brace("accessor"),
527
+ self.tok(open_tok),
528
+ indent([HARDLINE, self.print_list(accessors, lambda a, b: self.has_blank_before(b))]),
529
+ self.close_comments(close_tok),
530
+ HARDLINE,
531
+ self.tok(close_tok, leading=False),
532
+ ]
533
+
534
+ def p_accessor_list(self, node: Node) -> Doc:
535
+ return self.accessor_list(node)
536
+
537
+ def p_accessor_declaration(self, node: Node) -> Doc:
538
+ body = node.child("body")
539
+ attributes = [c for c in node.children if c.type == "attribute_list"]
540
+ header: list[Node] = []
541
+ rest: list[Node] = []
542
+ for child in node.children:
543
+ if child.type == "attribute_list":
544
+ continue
545
+ if child is body or rest or child.text == ";":
546
+ rest.append(child)
547
+ else:
548
+ header.append(child)
549
+ parts: list[Doc] = [self.attribute_lines(attributes), self.words(header)]
550
+ for child in rest:
551
+ if child is body and child.type == "block":
552
+ parts.append(self.block(child, "accessor"))
553
+ elif child.type == "arrow_expression_clause":
554
+ parts.append(self.expression_body(child))
555
+ else:
556
+ parts.append(self.tok(child))
557
+ return parts
558
+
559
+ def p_arrow_expression_clause(self, node: Node) -> Doc:
560
+ return self.expression_body(node)
561
+
562
+ # Parameters ------------------------------------------------------------
563
+
564
+ def p_parameter_list(self, node: Node) -> Doc:
565
+ return self.parameters(node)
566
+
567
+ def p_bracketed_parameter_list(self, node: Node) -> Doc:
568
+ return self.parameters(node)
569
+
570
+ def parameters(self, node: Node) -> Doc:
571
+ if len(node.children) < 2 or node.children[0].text not in ("(", "["):
572
+ return self.generic(node)
573
+ open_tok = node.children[0]
574
+ close_tok = node.children[-1]
575
+ items, commas = self.items_and_commas(node)
576
+ if not items:
577
+ return [self.tok(open_tok), self.close_comments(close_tok), self.tok(close_tok, leading=False)]
578
+ docs: list[Doc] = []
579
+ for i, item in enumerate(items):
580
+ doc = self.parameter_item(item)
581
+ if i < len(commas):
582
+ doc = [doc, self.tok(commas[i])]
583
+ docs.append(doc)
584
+ style = self.settings.argument_wrap
585
+ if style == "one_per_line" or style not in ("one_per_line_close_on_last", "fill", "align"):
586
+ return group([self.tok(open_tok), indent([SOFTLINE, join(LINE, docs)]), SOFTLINE, self.close_comments(close_tok), self.tok(close_tok, leading=False)])
587
+ return self.argument_layout(open_tok, docs, close_tok, [])
588
+
589
+ def parameter_item(self, item: Sequence[Node]) -> Doc:
590
+ if len(item) == 1:
591
+ return self.print(item[0])
592
+ # A params parameter is not wrapped in a node: params int[] values.
593
+ return self.words(item)
594
+
595
+ def p_parameter(self, node: Node) -> Doc:
596
+ return self.words(node.children)
597
+
598
+ def p_implicit_parameter(self, node: Node) -> Doc:
599
+ return self.generic(node)
600
+
601
+ # Attributes -------------------------------------------------------------
602
+
603
+ def p_attribute_list(self, node: Node) -> Doc:
604
+ parts: list[Doc] = []
605
+ for child in node.children:
606
+ parts.append(self.print(child))
607
+ if child.text in (",", ":") and not child.named or child.type == "attribute_target_specifier":
608
+ parts.append(" ")
609
+ return parts
610
+
611
+ p_global_attribute = p_attribute_list
612
+
613
+ def p_attribute_target_specifier(self, node: Node) -> Doc:
614
+ return [self.print(c) for c in node.children]
615
+
616
+ def p_attribute(self, node: Node) -> Doc:
617
+ return self.join_tokens([(c, self.print(c)) for c in node.children])
618
+
619
+
620
+ def _using_group(node: Node) -> tuple[int, int, str]:
621
+ """global or not, plain, static or alias, and the first part of the name."""
622
+ is_global, kind, _, name = using_key(node, "system_first_grouped")
623
+ return (is_global, kind, name.split(".")[0])