You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/specification_formatter.md
+303Lines changed: 303 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -81,3 +81,306 @@ create_tween() \
81
81
```
82
82
83
83
Anything other than these three continuation layouts is treated as a regular vertical layout and should not be subject to continuation layout rules.
84
+
85
+
## 1. General Rules
86
+
87
+
### 1.1. Line width is a loose target
88
+
89
+
The formatter should keep code at or below `max_line_length` when it can safely add a line break.
90
+
91
+
The max line length is not a strict limit, though. Strings, node path, identifiers, values, or comments are indivisible content and may cause a line to remain longer than the target.
All parts of the codebase including the renderer and linter should use the same, consistent width measurement. The measurement should account for the current visual column, indentation, tabs, Unicode width, spaces added by the formatter, commas, backslashes, and more generally any characters inserted by the formatter.
98
+
99
+
### 1.2. Prefer flat layout when the code fits one line
100
+
101
+
The formatter should use flat layout when a construct fits and no syntax or comment requires a line break.
102
+
103
+
Input:
104
+
105
+
```gdscript
106
+
var names = [
107
+
"Ana",
108
+
"Bao",
109
+
"Chidi",
110
+
]
111
+
```
112
+
113
+
Output:
114
+
115
+
```gdscript
116
+
var names = ["Ana", "Bao", "Chidi"]
117
+
```
118
+
119
+
Note: This is a change from the previous implementation of the formatter. The previous formatter preserved many source line breaks because it did not wrap lines automatically (it used line breaks as a hint to lay lines vertically). This new formatter should be as hands-off as possible: it should wrap lines when needed and merge them again when the user removes something and the code fits on one line.
120
+
121
+
The following cases may stay multiline even when their text would fit as a single line:
122
+
123
+
- Enums, because the official style guide requires one member per line.
124
+
- Constructs that contain comments that need to be on separate lines.
125
+
- Code that includes an unavoidable hard line break, like a multiline string or a lambda with a multiline body.
126
+
- Code inside a `# fmt: off` region.
127
+
128
+
### 1.3. Existing line breaks do not force broken layout
129
+
130
+
In the first pass of the formatter, source line breaks are not formatting instructions.
131
+
132
+
Input:
133
+
134
+
```gdscript
135
+
call(
136
+
first,
137
+
second,
138
+
)
139
+
```
140
+
141
+
Output:
142
+
143
+
```gdscript
144
+
call(first, second)
145
+
```
146
+
147
+
## 2. Indentation
148
+
149
+
### 2.1. Vertical items use one extra indentation level
150
+
151
+
Items in vertical layout use one level more than the line that opens the construct.
152
+
153
+
```gdscript
154
+
func move_character():
155
+
update_velocity(
156
+
input_direction,
157
+
maximum_speed,
158
+
acceleration,
159
+
)
160
+
```
161
+
162
+
This rule applies to arrays, dictionaries, parameters, arguments, annotation arguments, and other comma-separated items inside delimiters.
163
+
164
+
```gdscript
165
+
enum Element {
166
+
EARTH,
167
+
WATER,
168
+
AIR,
169
+
FIRE,
170
+
}
171
+
var party = [
172
+
"Godot",
173
+
"Godette",
174
+
"Steve",
175
+
]
176
+
var character = {
177
+
"name": "Bob",
178
+
"job": "Mechanic",
179
+
}
180
+
181
+
182
+
func configure_character():
183
+
var settings = {
184
+
"speed": 300.0,
185
+
"acceleration": 1200.0,
186
+
}
187
+
```
188
+
189
+
### 2.2. Continuation layouts use two extra indentation levels
190
+
191
+
Continuation layouts use two extra indentation levels. Conditionals:
192
+
193
+
```gdscript
194
+
if (
195
+
position.x > 200 and position.x < 400
196
+
and position.y > 300 and position.y < 400
197
+
):
198
+
pass
199
+
```
200
+
201
+
Backslash continuations:
202
+
203
+
```gdscript
204
+
var total = base_value \
205
+
+ equipment_bonus \
206
+
+ status_bonus
207
+
```
208
+
209
+
This would also apply to the following case (arguments continuing on hanging lines), although the formatter currently does not produce this kind of packing:
When a construct uses broken layout with delimiters, its first item should start on the next line.
222
+
223
+
```gdscript
224
+
effect.interpolate_property(
225
+
sprite,
226
+
"transform/scale",
227
+
sprite.get_scale(),
228
+
Vector2(2.0, 2.0),
229
+
0.3,
230
+
Tween.TRANS_QUAD,
231
+
Tween.EASE_OUT,
232
+
)
233
+
```
234
+
235
+
The formatter should normalize hanging input to this vertical layout when the construct must wrap.
236
+
237
+
### 3.1.1. Keep a fitting call prefix before broken arguments
238
+
239
+
Method-call arguments own their layout independently from the attribute or method chain that contains the call. When the receiver, method name, and opening parenthesis fit on the current line, the formatter should keep them there even when the arguments require broken layout.
In particular, a multiline lambda argument or ordinary overlong argument list breaks its nearest argument list after the opening parenthesis. It must not by itself break the enclosing attribute chain at every dot.
250
+
251
+
```gdscript
252
+
f.args.map(
253
+
func(arg: Dictionary) -> Dictionary:
254
+
arg.erase("name")
255
+
return arg
256
+
)
257
+
```
258
+
259
+
```gdscript
260
+
mob.velocity = mob.velocity.move_toward(
261
+
desired_velocity,
262
+
velocity_distance * acceleration_factor * delta
263
+
)
264
+
```
265
+
266
+
### 3.2. Put the closing delimiter on its own line
267
+
268
+
The closing parenthesis, bracket, or brace of a broken construct should always be on its own line.
269
+
270
+
```gdscript
271
+
var colors = [
272
+
Color.RED,
273
+
Color.GREEN,
274
+
]
275
+
```
276
+
277
+
**Do not** produce this layout:
278
+
279
+
```gdscript
280
+
var colors = [
281
+
Color.RED,
282
+
Color.GREEN,]
283
+
```
284
+
285
+
### 3.3. Put one item on each line by default
286
+
287
+
Arrays, dictionaries, function parameters, function arguments, annotation arguments, and similar comma-separated constructs should use one item per line when broken by default. Examples:
288
+
289
+
```gdscript
290
+
var values = [
291
+
10,
292
+
20,
293
+
30,
294
+
40,
295
+
]
296
+
```
297
+
298
+
```gdscript
299
+
func spawn_character(
300
+
position: Vector2,
301
+
direction: Vector2,
302
+
speed: float,
303
+
) -> CharacterBody2D:
304
+
pass
305
+
```
306
+
307
+
```gdscript
308
+
spawn_character(
309
+
spawn_position,
310
+
Vector2.RIGHT,
311
+
300.0,
312
+
)
313
+
```
314
+
315
+
```gdscript
316
+
@export_custom(
317
+
PROPERTY_HINT_RANGE,
318
+
"0,100,1",
319
+
)
320
+
var health := 100
321
+
```
322
+
323
+
```gdscript
324
+
# For dictionaries, put one key-value pair per line when broken.
325
+
var character = {
326
+
"name": "Bob",
327
+
"age": 27,
328
+
"job": "Mechanic",
329
+
}
330
+
```
331
+
332
+
### 3.4. Always format enums vertically
333
+
334
+
Every enum member should be on its own line, even when the enum would fit on one line.
335
+
336
+
Input:
337
+
338
+
```gdscript
339
+
enum Element { EARTH, WATER, AIR, FIRE }
340
+
```
341
+
342
+
Output:
343
+
344
+
```gdscript
345
+
enum Element {
346
+
EARTH,
347
+
WATER,
348
+
AIR,
349
+
FIRE,
350
+
}
351
+
```
352
+
353
+
This rule follows the official GDScript style guide.
354
+
355
+
### 3.5. Add a trailing comma to multiline constructs
356
+
357
+
The formatter should add a trailing comma to every multiline comma-separated construct where the GDScript grammar accepts it.
358
+
359
+
```gdscript
360
+
call(
361
+
first,
362
+
second,
363
+
)
364
+
```
365
+
366
+
```gdscript
367
+
func combine(
368
+
first: String,
369
+
second: String,
370
+
) -> String:
371
+
return first + second
372
+
```
373
+
374
+
The formatter should remove the trailing comma when the construct collapses to one line.
375
+
376
+
```gdscript
377
+
call(first, second)
378
+
```
379
+
380
+
**Exception 1:** The `preload()` function must not have a trailing comma; GDScript does not allow it:
0 commit comments