Releases: atelico/gdstyle
v0.1.7
gdstyle 0.1.7
Editor plugin patch release fixing a startup file-lock warning on
Windows.
Fixed
-
Godot plugin no longer fails to write
settings.jsonon startup.
Reported on Windows as "Unable to write to file 'settings.json',
file in use, locked or lacking permissions", with an orphan
settings.json#######.tmpleft behind every project startup.Cause:
_load_settingsopened the file for READ, then assigned
_auto_lint_check.button_pressed = Xand
_auto_format_check.button_pressed = X. Those assignments fire
thetoggledsignal synchronously, the handler calls
_save_settings, and_save_settingsopens the same file for
WRITE while the READ handle is still alive on the call stack. On
Windows file locks are exclusive so the WRITE open fails, Godot's
atomic-save rename orphans the.tmp, and the warning surfaces.The plugin now uses
set_pressed_no_signal()for both checkboxes
during load (the idiomatic Godot fix), wraps the load body in a
_loading_settingsguard flag, and adds an explicitfile.close()
plus apush_warningon open failure so a future regression
surfaces with a real error instead of silence.Reported in #6.
How to upgrade
After installing v0.1.7, delete any leftover
settings.json#######.tmp files in addons/gdstyle/ (Godot left
them behind from previous startups because the rename kept failing),
then restart Godot.
Install
CLI from crates.io:
cargo install gdstyleOr grab a prebuilt binary from this release page, drop it on your
PATH, and run gdstyle in your project directory.
For the Godot editor plugin: download gdstyle-godot-plugin.zip from
this release, extract the addons/gdstyle/ folder into your Godot
project, then enable the plugin in Project > Project Settings >
Plugins.
For the pre-commit framework, bump your
config to:
- repo: https://github.com/atelico/gdstyle
rev: v0.1.7
hooks:
- id: gdstyle
- id: gdstyle-fmtor run pre-commit autoupdate.
Full documentation, rule list, configuration reference, and the
GDExtension API live in the README.
Full Changelog: v0.1.6...v0.1.7
v0.1.6
gdstyle 0.1.6
Patch release fixing a parser bug that caused order/class-member-order
false positives on inner classes whose first body line was a comment.
Fixed
-
order/class-member-orderno longer fires on every inner-class
member when the inner class body starts with a comment-only line
(#or##on its own line, e.g. a leading doc comment). The lexer
was preserving the indent stack on any comment-only line, so the
parser saw noIndentat the start of the body, returned an empty
inner class, and the followingvar/functokens fell back to the
outer parse loop. Every inner-class member then looked like a
sibling of the inner class and tripped the ordering rule.The lexer now splits comment-only line handling into three cases
by relative indent: same indent preserves the stack (unchanged),
shallower indent uses the existing peek-ahead to disambiguate
boundary vs mid-body noise (unchanged), and deeper indent falls
through toIndentemission so the leading comment opens the new
block.Reported in #5 with
a full root-cause trace from the reporter.
Install
CLI from crates.io:
cargo install gdstyleOr grab a prebuilt binary from this release page, drop it on your
PATH, and run gdstyle in your project directory.
For the Godot editor plugin: download gdstyle-godot-plugin.zip from
this release, extract the addons/gdstyle/ folder into your Godot
project, then enable the plugin in Project > Project Settings >
Plugins.
For the pre-commit framework, bump your
config to:
- repo: https://github.com/atelico/gdstyle
rev: v0.1.6
hooks:
- id: gdstyle
- id: gdstyle-fmtor run pre-commit autoupdate.
Full documentation, rule list, configuration reference, and the
GDExtension API live in the README.
Full Changelog: v0.1.5...v0.1.6
v0.1.5
gdstyle 0.1.5
Patch release fixing a formatter explosion on @abstract (and any
other unrecognised class-level annotation).
Fixed
-
gdstyle fmtno longer duplicates@abstract/class_name
blocks. When an unrecognised top-level annotation
(@abstractin Godot 4.6+, also@experimentaland@deprecated)
appeared aboveclass_name/extendswith a function later in the
file, the parser held it in pending state and silently attached it
to that function. The formatter then treated lines 1..N as part of
the function's "block" and re-emitted them on every pass — the
multi-pass loop could blow the file up to 30+ duplicate
@abstract\nclass_name Pickup\nchunks before stabilising.The parser now flushes pending unknown annotations into a new
class-levelClassAnnotationnode at six boundary points where the
pending annotation can't legitimately attach:
class_name,extends,signal,enum,const, innerclass,
and end-of-file.Function-level
@abstract(@abstract\nfunc to_implement():) still
attaches to its method as before — abstract method declarations are
unaffected.Reported in #4.
Behaviour notes
- The fix is structural (by member kind), not name-based. Any future
Godot annotation that lands at the top of a file will sort with
@tool/@icon/@static_unloadautomatically without a code change. - A trailing top-level annotation at EOF with no following declaration
used to be silently dropped; it now survives a round-trip through
gdstyle fmt. - A leading annotation directly above an inner
class Inner:is
attributed to the OUTER class (the AST doesn't yet model
inner-class annotations). If that becomes a practical issue, file
one and we'll wire annotation slots through inner-class parsing.
Install
CLI from crates.io:
cargo install gdstyleOr grab a prebuilt binary from this release page, drop it on your
PATH, and run gdstyle in your project directory.
For the Godot editor plugin: download gdstyle-godot-plugin.zip from
this release, extract the addons/gdstyle/ folder into your Godot
project, then enable the plugin in Project > Project Settings >
Plugins.
For the pre-commit framework, bump your
config to:
- repo: https://github.com/atelico/gdstyle
rev: v0.1.5
hooks:
- id: gdstyle
- id: gdstyle-fmtor run pre-commit autoupdate.
Full documentation, rule list, configuration reference, and the
GDExtension API live in the README.
Full Changelog: v0.1.4...v0.1.5
v0.1.4
gdstyle 0.1.4
Adds file-scope suppression so class- and file-level rules can be
silenced cleanly.
Added
-
# gdstyle:ignore-filedirective for file-scope suppression.# gdstyle:ignore-file=quality/max-public-methods,quality/max-class-variables class_name OrchestrationFacade extends Node # ... 25 public methods follow
Anchor it at the top of the file by convention, but the parser
accepts it anywhere. A bare# gdstyle:ignore-file(no=...)
suppresses every rule in the file — for generated code or
third-party drops.This is the right tool for the four rules whose diagnostic anchors
at the class header or line 1 of the file and which previously
couldn't be silenced without uglifying the signature:
quality/max-public-methods,quality/max-class-variables,
quality/max-inner-classes,quality/max-file-length.Per-line
# gdstyle:ignoreis unchanged and remains the right tool
for spot exemptions on a single line.
Documentation
- README's Inline suppression section is now Suppressing
diagnostics with a directive/scope table, separate per-line and
per-file subsections, and a "when to use which" guide.
Install
CLI from crates.io:
cargo install gdstyleOr grab a prebuilt binary from this release page, drop it on your
PATH, and run gdstyle in your project directory.
For the Godot editor plugin: download gdstyle-godot-plugin.zip from
this release, extract the addons/gdstyle/ folder into your Godot
project, then enable the plugin in Project > Project Settings >
Plugins.
For the pre-commit framework, bump your
config to:
- repo: https://github.com/atelico/gdstyle
rev: v0.1.4
hooks:
- id: gdstyle
- id: gdstyle-fmtor run pre-commit autoupdate.
Full documentation, rule list, configuration reference, and the
GDExtension API live in the README.
Full Changelog: v0.1.3...v0.1.4
v0.1.3
gdstyle 0.1.3
Patch release fixing a false positive in quality/unreachable-code.
Fixed
-
quality/unreachable-codeno longer flags the closing)of a
multi-linereturnstatement as unreachable. The previous
implementation was line-based and walked forward from each
return/break/continuelooking for any same-indent non-blank
line. The closing)ofreturn floori(\n\t\t1.2\n\t)lands at the
same indent asreturn, so it was wrongly reported.The rule now tracks open-bracket depth (
([{) and backslash
continuation across lines, masking delimiters inside string literals
and trailing#comments. While areturnstatement is still
syntactically open, subsequent lines are treated as continuation of
that same statement. True positives — actual code at the same indent
AFTER the statement closes — are still flagged.Reported in #3.
Install
CLI from crates.io:
cargo install gdstyleOr grab a prebuilt binary from this release page, drop it on your
PATH, and run gdstyle in your project directory.
For the Godot editor plugin: download gdstyle-godot-plugin.zip from
this release, extract the addons/gdstyle/ folder into your Godot
project, then enable the plugin in Project > Project Settings >
Plugins.
For the pre-commit framework, bump your
config to:
- repo: https://github.com/atelico/gdstyle
rev: v0.1.3
hooks:
- id: gdstyle
- id: gdstyle-fmtor run pre-commit autoupdate.
Full documentation, rule list, configuration reference, and the
GDExtension API live in the README.
Full Changelog: v0.1.2...v0.1.3
v0.1.2
gdstyle 0.1.2
Patch release focused on one user-reported formatter bug. The fix is
under the hood in the lexer, so existing CI and editor workflows pick
it up automatically — no config changes required.
Fixed
-
Formatter no longer detaches
## docstrings from their function
when the previous function's body ended with a nested indented block
(e.g. a top-levelifafter amatch, leaving two open indent
levels at the body's tail). The lexer was emitting the doc comment
token before the dedents that close the previous body, so the parser
consumed the doc as part of the wrong function. The formatter then
inserted its canonical between-functions blank-line gap between the
orphan doc and the function it actually documents — visible to users
as docstrings that the Godot editor tooltip and theclass_docs
export no longer recognised.Fixed in the lexer with read-only peek-ahead: when a comment sits at
shallower indent than the current block, look at the next real line
(skipping blanks and more comments). If that line is deeper than the
comment, the comment is mid-body noise and the block continues; if
it's at the comment's indent or lower, it's a true boundary and
dedents fire correctly.The fix also tightens spacing between inner-class methods: when the
previous formatter was confused about member boundaries it was
inflating single blank lines to double; member-aware spacing now
produces the canonical PEP-8 / Godot-style single blank between
methods within a class.
Install
CLI from crates.io:
cargo install gdstyleOr grab a prebuilt binary from this release page, drop it on your
PATH, and run gdstyle in your project directory.
For the Godot editor plugin: download gdstyle-godot-plugin.zip from
this release, extract the addons/gdstyle/ folder into your Godot
project, then enable the plugin in Project > Project Settings >
Plugins.
For the pre-commit framework, bump your
config to:
- repo: https://github.com/atelico/gdstyle
rev: v0.1.2
hooks:
- id: gdstyle
- id: gdstyle-fmtor run pre-commit autoupdate.
Full documentation, rule list, configuration reference, and the
GDExtension API live in the README.
Full Changelog: v0.1.1...v0.1.2
v0.1.1
gdstyle 0.1.1
Small follow-up to the initial release: one false-positive fix and a
pre-commit integration that came out of community feedback.
Fixes
quality/no-self-assignno longer flagsobj.field = fieldstyle
assignments. The previous implementation compared one identifier on
each side of=, somoon.size = size * 0.5matchedsize == size
even though the LHS is the propertymoon.sizeand the RHS is the
localsize. Same bug hitself.position = positionand
x = x + 1. The rule now compares full dotted paths (including
self./super.heads) and only flags when the assignment ends
at a statement terminator. True positives like
obj.foo = obj.fooandself.player.health = self.player.health
still trigger.
Added
-
Pre-commit framework integration. gdstyle now ships a
.pre-commit-hooks.yamlat the repo root, exposing two hooks for
pre-commit:gdstyle(lint) and
gdstyle-fmt(format in place). Drop this into your project's
.pre-commit-config.yaml:repos: - repo: https://github.com/atelico/gdstyle rev: v0.1.1 hooks: - id: gdstyle - id: gdstyle-fmt
Then
pre-commit install. First run builds gdstyle from source via
cargo (Rust toolchain required); subsequent runs are cached.
Install
CLI from crates.io:
cargo install gdstyleOr grab a prebuilt binary from this release page, drop it on your PATH,
and run gdstyle in your project directory.
For the Godot editor plugin: download gdstyle-godot-plugin.zip from
this release, extract the addons/gdstyle/ folder into your Godot
project, then enable the plugin in Project > Project Settings > Plugins.
Full documentation, rule list, configuration reference, and the
GDExtension API live in the README.
Full Changelog: https://github.com/atelico/gdstyle/commits/v0.1.1
v0.1.0
gdstyle 0.1.0
First public release. gdstyle is a fast, opinionated linter and formatter for
GDScript (Godot 4.x), written in Rust, that ships as a single static binary
plus an optional Godot editor plugin.
We've been using it inside the studio for a while and figured the wider Godot
community might get the same mileage out of it. Open-sourcing it under MIT.
What's in the box
- CLI: prebuilt binaries for Linux, macOS (Intel + Apple Silicon), and
Windows. No Python, no Rust toolchain, no Godot install required to run it. - Lint: 54 rules across syntax, naming, formatting, ordering, and code
quality. Most are safely auto-fixable. - Format: in-place, idempotent, member-aware. Same input always produces
the same output. - Scene-aware autofix:
--unsafe-fixfollows renamed signals and methods
into.tscnand.tresfiles, so a refactor doesn't quietly break editor
wiring. - Godot editor plugin: bottom panel with clickable diagnostics, single
right-click fixes, Lint/Format on save. Uses the GDExtension when present,
falls back to the CLI binary otherwise. - TOML config (
gdstyle.toml): per-rule severity overrides, limit knobs,
exclude patterns. gdstyle searches up from the file's directory so each
subproject or vendored addon can carry its own rules.
What it draws on
The defaults follow the official Godot GDScript style guide
and the conventions Nathan Lovato and GDQuest
have done so much to popularise. Scony's gdtoolkit
and GDQuest's GDScript Formatter
got there first and are still excellent options; gdstyle owes them a debt.
Heads up for a first release
It's young, and almost certainly wrong about something on a codebase that
isn't ours. We validated it against 30+ open-source Godot projects before
this release, which covers a lot of ground, but the wild is much bigger than
that. If you run gdstyle on your project and it flags something it shouldn't
(or misses something it should), an issue or PR is the most useful thing you
can send our way. Rule suggestions welcome too.
Install
CLI from crates.io:
cargo install gdstyleOr grab a prebuilt binary from this release page, drop it on your PATH, and
run gdstyle in your project directory.
For the Godot editor plugin: download gdstyle-godot-plugin.zip from this
release, extract the addons/gdstyle/ folder into your Godot project, then
enable the plugin in Project > Project Settings > Plugins.
Full documentation, rule list, configuration reference, and the GDExtension
API live in the README.
Full Changelog: https://github.com/atelico/gdstyle/commits/v0.1.0