renpy-language-server 0.2.0__tar.gz
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.
Potentially problematic release.
This version of renpy-language-server might be problematic. Click here for more details.
- renpy_language_server-0.2.0/LICENSE +21 -0
- renpy_language_server-0.2.0/NOTICE.md +41 -0
- renpy_language_server-0.2.0/PKG-INFO +434 -0
- renpy_language_server-0.2.0/README.md +403 -0
- renpy_language_server-0.2.0/pyproject.toml +68 -0
- renpy_language_server-0.2.0/pyproject.toml.orig +59 -0
- renpy_language_server-0.2.0/src/renpy_language_server/__init__.py +6 -0
- renpy_language_server-0.2.0/src/renpy_language_server/__main__.py +5 -0
- renpy_language_server-0.2.0/src/renpy_language_server/analysis.py +230 -0
- renpy_language_server-0.2.0/src/renpy_language_server/assets.py +104 -0
- renpy_language_server-0.2.0/src/renpy_language_server/builtins.py +54 -0
- renpy_language_server-0.2.0/src/renpy_language_server/cli.py +190 -0
- renpy_language_server-0.2.0/src/renpy_language_server/code_actions.py +130 -0
- renpy_language_server-0.2.0/src/renpy_language_server/completion.py +1191 -0
- renpy_language_server-0.2.0/src/renpy_language_server/completion_data.py +74 -0
- renpy_language_server-0.2.0/src/renpy_language_server/dap.py +824 -0
- renpy_language_server-0.2.0/src/renpy_language_server/data/__init__.py +1 -0
- renpy_language_server-0.2.0/src/renpy_language_server/data/completion.json +756 -0
- renpy_language_server-0.2.0/src/renpy_language_server/data/renpy_api.json +8073 -0
- renpy_language_server-0.2.0/src/renpy_language_server/definition.py +77 -0
- renpy_language_server-0.2.0/src/renpy_language_server/diagnostics.py +895 -0
- renpy_language_server-0.2.0/src/renpy_language_server/docs.py +21 -0
- renpy_language_server-0.2.0/src/renpy_language_server/edits.py +70 -0
- renpy_language_server-0.2.0/src/renpy_language_server/folding.py +107 -0
- renpy_language_server-0.2.0/src/renpy_language_server/formatter.py +288 -0
- renpy_language_server-0.2.0/src/renpy_language_server/hover.py +238 -0
- renpy_language_server-0.2.0/src/renpy_language_server/index.py +1002 -0
- renpy_language_server-0.2.0/src/renpy_language_server/positions.py +28 -0
- renpy_language_server-0.2.0/src/renpy_language_server/py.typed +0 -0
- renpy_language_server-0.2.0/src/renpy_language_server/python_format.py +141 -0
- renpy_language_server-0.2.0/src/renpy_language_server/python_index.py +371 -0
- renpy_language_server-0.2.0/src/renpy_language_server/quotes.py +143 -0
- renpy_language_server-0.2.0/src/renpy_language_server/references.py +40 -0
- renpy_language_server-0.2.0/src/renpy_language_server/rename.py +293 -0
- renpy_language_server-0.2.0/src/renpy_language_server/resolve.py +807 -0
- renpy_language_server-0.2.0/src/renpy_language_server/scanner.py +86 -0
- renpy_language_server-0.2.0/src/renpy_language_server/semantic.py +488 -0
- renpy_language_server-0.2.0/src/renpy_language_server/server.py +770 -0
- renpy_language_server-0.2.0/src/renpy_language_server/settings.py +187 -0
- renpy_language_server-0.2.0/src/renpy_language_server/signature.py +371 -0
- renpy_language_server-0.2.0/src/renpy_language_server/spacing.py +261 -0
- renpy_language_server-0.2.0/src/renpy_language_server/strings.py +86 -0
- renpy_language_server-0.2.0/src/renpy_language_server/symbols.py +163 -0
- renpy_language_server-0.2.0/src/renpy_language_server/targets.py +51 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oleksandr (rockettap)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
## Ren'Py API data
|
|
4
|
+
|
|
5
|
+
`src/renpy_language_server/data/renpy_api.json` is derived from the `src/renpy.json` file in
|
|
6
|
+
[`renpy/vscode-language-renpy`](https://github.com/renpy/vscode-language-renpy).
|
|
7
|
+
|
|
8
|
+
The original data was converted from nested categories into a flat table, and
|
|
9
|
+
each entry keeps only its name, kind, argument list, Python type, category and
|
|
10
|
+
documentation. Names, signatures and documentation are otherwise unchanged.
|
|
11
|
+
|
|
12
|
+
`src/renpy_language_server/data/completion.json` also includes the `keyword_values` table
|
|
13
|
+
from `src/renpyauto.json` in the same project. The surrounding screen-element,
|
|
14
|
+
property, transform and transition lists are a curated snapshot of Ren'Py's
|
|
15
|
+
public screen language.
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
The MIT License
|
|
19
|
+
|
|
20
|
+
Original work Copyright (c) 2018 Daniel Luque <danielluque14@gmail.com>
|
|
21
|
+
Modified work Copyright (c) 2024 Tom Rothamel <pytom@bishoujo.us>
|
|
22
|
+
|
|
23
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
24
|
+
a copy of this software and associated documentation files (the
|
|
25
|
+
"Software"), to deal in the Software without restriction, including
|
|
26
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
27
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
28
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
29
|
+
the following conditions:
|
|
30
|
+
|
|
31
|
+
The above copyright notice and this permission notice shall be
|
|
32
|
+
included in all copies or substantial portions of the Software.
|
|
33
|
+
|
|
34
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
35
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
36
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
37
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
38
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
39
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
40
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
41
|
+
```
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: renpy-language-server
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Language server and formatter for Ren'Py scripts
|
|
5
|
+
Keywords: renpy,lsp,language-server,formatter
|
|
6
|
+
Author: Олександр
|
|
7
|
+
Author-email: Олександр <67645530+rockettap@users.noreply.github.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
License-File: NOTICE.md
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Text Editors :: Integrated Development Environments (IDE)
|
|
21
|
+
Requires-Dist: pygls>=2.1,<3
|
|
22
|
+
Requires-Dist: typer>=0.27,<1
|
|
23
|
+
Requires-Dist: ruff>=0.16,<1 ; extra == 'python-format'
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Project-URL: Homepage, https://github.com/rockettap/renpy-language-server
|
|
26
|
+
Project-URL: Repository, https://github.com/rockettap/renpy-language-server
|
|
27
|
+
Project-URL: Issues, https://github.com/rockettap/renpy-language-server/issues
|
|
28
|
+
Project-URL: Changelog, https://github.com/rockettap/renpy-language-server/releases
|
|
29
|
+
Provides-Extra: python-format
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# renpy-language-server
|
|
33
|
+
|
|
34
|
+
Language server and formatter for [Ren'Py](https://www.renpy.org) scripts, built with
|
|
35
|
+
[pygls](https://github.com/openlawlibrary/pygls) and managed with [uv](https://docs.astral.sh/uv/).
|
|
36
|
+
Part of [renpy-zed](https://github.com/rockettap/renpy-zed) (Ren'Py support
|
|
37
|
+
for Zed), but it speaks standard LSP and works with any client.
|
|
38
|
+
|
|
39
|
+
Requires Python 3.10 or newer.
|
|
40
|
+
|
|
41
|
+
> Unofficial project, not affiliated with Ren'Py.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- `textDocument/formatting` and `textDocument/rangeFormatting`, returned as
|
|
46
|
+
minimal line edits (the cursor does not jump)
|
|
47
|
+
- `textDocument/completion` for statements, labels, images (including automatic
|
|
48
|
+
images from `game/images`), screens, characters, transforms, transitions,
|
|
49
|
+
audio channels/assets and the bundled Ren'Py API namespaces. Screen bodies
|
|
50
|
+
complete elements, properties and property values, dialogue completes image
|
|
51
|
+
attributes, and `$` / conditions / declarations complete Python keywords and
|
|
52
|
+
built-ins
|
|
53
|
+
- `textDocument/documentSymbol` for labels, screens, transforms, images,
|
|
54
|
+
characters, styles, layered images, `define` / `default` variables, and for
|
|
55
|
+
Python classes, functions, methods, properties, fields, stores, persistent
|
|
56
|
+
variables, test cases and translations. Class and store members are nested in
|
|
57
|
+
the outline
|
|
58
|
+
- `textDocument/definition` for labels, screens, transforms, images, layered
|
|
59
|
+
images, characters, styles and variables, including local labels (`.local`)
|
|
60
|
+
resolved against the most recent global label and images after `show` /
|
|
61
|
+
`scene` / `hide` (declared images or automatic image files)
|
|
62
|
+
- Definition also follows Python member access where it is unambiguous:
|
|
63
|
+
`self.field`, `Class.member`, `persistent.value`, `store.value` and class
|
|
64
|
+
base names
|
|
65
|
+
- `textDocument/hover` for labels, screens, transforms, images, characters and
|
|
66
|
+
other declarations, for references such as `jump`, `show`, `use` and `at`,
|
|
67
|
+
for automatic images from `game/images`, and for the bundled Ren'Py API
|
|
68
|
+
(signature, documentation and source location)
|
|
69
|
+
- Hover includes comment-block documentation above a declaration and works for
|
|
70
|
+
references across files
|
|
71
|
+
- `textDocument/prepareRename` and `textDocument/rename` for labels (global,
|
|
72
|
+
dotted and local), screens, transforms, images, layered images, characters,
|
|
73
|
+
styles and `define` / `default` variables, across every indexed file.
|
|
74
|
+
Class/function/member rename is deliberately deferred
|
|
75
|
+
- `textDocument/documentHighlight` for the symbol under the cursor, so Zed
|
|
76
|
+
shades declarations and references while editing and renaming
|
|
77
|
+
- `textDocument/references` for the same families as rename, across every
|
|
78
|
+
indexed file, with `includeDeclaration` respected
|
|
79
|
+
- `workspace/symbol` for workspace-wide symbol search across labels, screens,
|
|
80
|
+
images, characters, styles, variables, classes, members, stores, persistent
|
|
81
|
+
variables, test cases and translations
|
|
82
|
+
- `textDocument/signatureHelp` for bundled Ren'Py API calls, labels, screens,
|
|
83
|
+
user classes/functions and `self.` / `Class.` methods
|
|
84
|
+
- `textDocument/codeAction` quick fixes for comparison typos, stray `$`,
|
|
85
|
+
leading tabs and unknown labels
|
|
86
|
+
- `textDocument/semanticTokens/full` (opt-in) for declarations, references,
|
|
87
|
+
built-ins, obsolete APIs, keywords, parameters and literals
|
|
88
|
+
- Completion of class members after `Class.` and `self.`, persistent fields
|
|
89
|
+
after `persistent.`, variables after `store.`, and API names after
|
|
90
|
+
`renpy.`, `renpy.music.`, `renpy.audio.`, `config.` and `gui.`
|
|
91
|
+
- Callable built-ins insert their parentheses (`Character()`), and completion
|
|
92
|
+
is available from spaces, `.`, `(`, `@` and `-`
|
|
93
|
+
- Completion documentation is sent as Markdown, so signature fences and inline
|
|
94
|
+
code render as code blocks in the editor
|
|
95
|
+
- configurable diagnostics for indentation, tabs, filenames, variable names,
|
|
96
|
+
comparisons, stray `$`, obsolete APIs, unknown labels and images, undefined
|
|
97
|
+
screens, persistent/store variables and duplicate labels, with per-rule
|
|
98
|
+
severity and open-file or workspace modes (see [Settings](#settings))
|
|
99
|
+
- `textDocument/foldingRange` for labels, menus, menu choices, screens,
|
|
100
|
+
transforms and other indented blocks
|
|
101
|
+
- `renpy-language-server dap`, a launch-only Debug Adapter Protocol server that starts a
|
|
102
|
+
project through an installed Ren'Py SDK, supports `warp`, streams output and
|
|
103
|
+
terminates the game. Breakpoints, stepping, variables and attach are not
|
|
104
|
+
implemented yet
|
|
105
|
+
- `renpy-language-server format` command for scripts and CI (`--check`, `--diff`)
|
|
106
|
+
- Safe formatting by default: whitespace and quote delimiters only, never
|
|
107
|
+
string values or program behaviour
|
|
108
|
+
- Inline spacing for Python-ish statements (`$ points=1` becomes
|
|
109
|
+
`$ points = 1`) and inside `python:` blocks
|
|
110
|
+
- Single-quoted strings become double-quoted unless the value contains an
|
|
111
|
+
unescaped `"` (`--no-quotes` / `normalize_quotes: false` disables it)
|
|
112
|
+
- Optional Ruff formatting for `python:` block bodies
|
|
113
|
+
|
|
114
|
+
## Demo
|
|
115
|
+
|
|
116
|
+

|
|
117
|
+
|
|
118
|
+
## Install
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv tool install renpy-language-server
|
|
122
|
+
uv tool install "renpy-language-server[python-format]" # with optional Ruff formatting
|
|
123
|
+
# for development, from a clone:
|
|
124
|
+
uv tool install --editable .
|
|
125
|
+
uv tool install --editable ".[python-format]"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Use
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
renpy-language-server format game/ # format every .rpy under game/ in place
|
|
132
|
+
renpy-language-server format --check game/ # exit 1 if anything would change (CI)
|
|
133
|
+
renpy-language-server format --diff script.rpy
|
|
134
|
+
renpy-language-server format --python game/ # also format python: blocks with Ruff
|
|
135
|
+
cat script.rpy | renpy-language-server format -
|
|
136
|
+
renpy-language-server # start the language server on stdio
|
|
137
|
+
renpy-language-server dap # start the launch-only debug adapter on stdio
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Debug adapter
|
|
141
|
+
|
|
142
|
+
`renpy-language-server dap` speaks DAP over stdin/stdout. It is normally launched by the
|
|
143
|
+
`renpy-zed` Zed extension, but any DAP client can start it. A launch
|
|
144
|
+
configuration accepts:
|
|
145
|
+
|
|
146
|
+
| Field | Default | Meaning |
|
|
147
|
+
| --------- | ------- | ------------------------------------------------------------- |
|
|
148
|
+
| `request` | launch | Only `launch` is accepted |
|
|
149
|
+
| `sdk` | auto | SDK directory or a launcher inside it |
|
|
150
|
+
| `project` | auto | Directory containing `game/`; inferred from `warp` or the cwd |
|
|
151
|
+
| `warp` | none | `file:line`, made project-relative when possible |
|
|
152
|
+
| `command` | `run` | Ren'Py CLI command (`run`, `lint`, `compile`, ...) |
|
|
153
|
+
| `args` | `[]` | Extra arguments appended to the Ren'Py command line |
|
|
154
|
+
| `env` | `{}` | Extra environment variables for the game process |
|
|
155
|
+
|
|
156
|
+
The SDK is resolved from `sdk`, then `RENPY_SDK`, then `renpy-*-sdk`
|
|
157
|
+
directories in the home directory, `Documents`, `Downloads`, `Desktop`,
|
|
158
|
+
`Applications` and `/Applications`, newest version first. `RENPY_SDK` may name
|
|
159
|
+
the SDK directory or a launcher inside it.
|
|
160
|
+
|
|
161
|
+
`terminate` and `disconnect` stop the game, escalating to a forced kill after
|
|
162
|
+
three seconds. `setBreakpoints` reports the requested lines as unverified and
|
|
163
|
+
stepping, pause and evaluate return a clear "launch-only" error. `attach` is
|
|
164
|
+
rejected.
|
|
165
|
+
|
|
166
|
+
### In Zed
|
|
167
|
+
|
|
168
|
+
Until the renpy-zed extension is published, point Zed at the binary
|
|
169
|
+
(`which renpy-language-server`) in `settings.json`:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"lsp": {
|
|
174
|
+
"renpy-language-server": {
|
|
175
|
+
"binary": { "path": "/home/you/.local/bin/renpy-language-server" }
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The language itself (`.rpy` files) must be registered by the extension first.
|
|
182
|
+
|
|
183
|
+
Zed uses LSP folding ranges only when its `document_folding_ranges` setting is
|
|
184
|
+
enabled. Without it, Zed falls back to indentation-based folding, which can
|
|
185
|
+
attach a menu choice's fold to the next choice:
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"languages": {
|
|
190
|
+
"Ren'Py": { "document_folding_ranges": "on" }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Settings
|
|
196
|
+
|
|
197
|
+
The server accepts settings from the language client's `initializationOptions`
|
|
198
|
+
(under `renpyLanguageServer`, or flat) and from
|
|
199
|
+
`workspace/didChangeConfiguration`:
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"renpyLanguageServer": {
|
|
204
|
+
"indent": 4,
|
|
205
|
+
"max_blank_lines": 2,
|
|
206
|
+
"align_equals": true,
|
|
207
|
+
"normalize_spacing": true,
|
|
208
|
+
"normalize_quotes": true,
|
|
209
|
+
"format_python": false,
|
|
210
|
+
"diagnostics": true,
|
|
211
|
+
"code_actions": true,
|
|
212
|
+
"unknown_label_diagnostics": true,
|
|
213
|
+
"diagnostics_mode": "open",
|
|
214
|
+
"diagnostic_rules": {
|
|
215
|
+
"indentation": "warning",
|
|
216
|
+
"tabs": "warning",
|
|
217
|
+
"unknown_label": "warning"
|
|
218
|
+
},
|
|
219
|
+
"completion": true,
|
|
220
|
+
"automatic_assets": true,
|
|
221
|
+
"semantic_tokens": false,
|
|
222
|
+
"workspace_symbols": true,
|
|
223
|
+
"hover": true,
|
|
224
|
+
"rename": true,
|
|
225
|
+
"references": true,
|
|
226
|
+
"highlight": true,
|
|
227
|
+
"signature": true,
|
|
228
|
+
"extended_index": true,
|
|
229
|
+
"member_references": true
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
| Setting | Default | Meaning |
|
|
235
|
+
| --------------------------- | --------- | ------------------------------------------------------------- |
|
|
236
|
+
| `indent` | `4` | Fallback spaces per indentation level |
|
|
237
|
+
| `max_blank_lines` | `2` | Maximum consecutive blank lines |
|
|
238
|
+
| `align_equals` | `true` | Align consecutive assignment `=` |
|
|
239
|
+
| `normalize_spacing` | `true` | Inline operator spacing |
|
|
240
|
+
| `normalize_quotes` | `true` | Rewrite single-quoted strings to double quotes |
|
|
241
|
+
| `format_python` | `false` | Format `python:` bodies with Ruff |
|
|
242
|
+
| `diagnostics` | `true` | Enable all diagnostics |
|
|
243
|
+
| `code_actions` | `true` | Enable diagnostic quick fixes |
|
|
244
|
+
| `unknown_label_diagnostics` | `true` | Legacy switch for the unknown-label rule |
|
|
245
|
+
| `diagnostics_mode` | `"open"` | Check open files (`open`) or the workspace |
|
|
246
|
+
| `diagnostic_rules` | see below | Per-rule `error`, `warning` or `off` |
|
|
247
|
+
| `completion` | `true` | Enable completion |
|
|
248
|
+
| `automatic_assets` | `true` | Offer images/audio found on disk in completion |
|
|
249
|
+
| `semantic_tokens` | `false` | Enable semantic tokens (opt-in) |
|
|
250
|
+
| `workspace_symbols` | `true` | Enable `workspace/symbol` search |
|
|
251
|
+
| `hover` | `true` | Enable hover information |
|
|
252
|
+
| `rename` | `true` | Enable prepare-rename and rename |
|
|
253
|
+
| `references` | `true` | Enable find-references |
|
|
254
|
+
| `highlight` | `true` | Enable occurrence highlights |
|
|
255
|
+
| `signature` | `true` | Enable signature help |
|
|
256
|
+
| `extended_index` | `true` | Index Python classes, stores and related declaration families |
|
|
257
|
+
| `member_references` | `true` | Index `self.x` / `Class.x` / `persistent.x` / `store.x` |
|
|
258
|
+
|
|
259
|
+
`diagnostic_rules` accepts these keys: `indentation`, `tabs`, `filename`,
|
|
260
|
+
`invalid_variable`, `reserved_names`, `comparison`, `stray_dollar`,
|
|
261
|
+
`obsolete_api`, `undefined_persistent`, `undefined_store`, `duplicate_label`,
|
|
262
|
+
`unknown_label`, `unknown_image` and `undefined_screen`. The two pre-existing
|
|
263
|
+
rules (`indentation`, `unknown_label`) and `tabs` default to `warning`; all
|
|
264
|
+
newer rules default to `off` until they have been validated on real projects.
|
|
265
|
+
Set a rule to `error` for stricter projects, or to `off` to silence it. The
|
|
266
|
+
legacy `unknown_label_diagnostics` flag still maps to the `unknown_label` rule.
|
|
267
|
+
|
|
268
|
+
Semantic tokens are disabled by default because Zed already highlights Ren'Py
|
|
269
|
+
through tree-sitter and the two layers should be validated together. Set
|
|
270
|
+
`semantic_tokens` to `true` to let the server add declaration, reference,
|
|
271
|
+
built-in and obsolete-API tokens; the capability and legend are always
|
|
272
|
+
advertised, and the provider returns an empty stream while disabled.
|
|
273
|
+
|
|
274
|
+
Diagnostics have the source `renpy-language-server` and a stable code such as
|
|
275
|
+
`renpy-language-server.unknown-image`. In `workspace` mode the server publishes diagnostics
|
|
276
|
+
for every indexed file on startup and after configuration, save and watched-file
|
|
277
|
+
events; normal typing only rechecks the current document.
|
|
278
|
+
|
|
279
|
+
Rename follows the indexed references: `jump` / `call`, screen statements,
|
|
280
|
+
`show` / `scene` / `hide`, `at`, dialogue speakers and style parents. Variables
|
|
281
|
+
are renamed in code, dialogue interpolation (`"[var]"`), and across files,
|
|
282
|
+
including declarations with an init priority (`define -1 foo = ...`) and the
|
|
283
|
+
`+=` / `|=` operators.
|
|
284
|
+
|
|
285
|
+
Rename protects Ren'Py syntax: statement and screen-language keywords, audio
|
|
286
|
+
channel names, `with` / `as` / `onlayer` / `behind` clauses, dialogue
|
|
287
|
+
attributes, screen-local `default` variables and ordinary strings. Dynamic
|
|
288
|
+
targets such as `jump expression`, automatic image files and arbitrary
|
|
289
|
+
attribute access are not renamed. Store-qualified declarations such as
|
|
290
|
+
`define config.name`, variable names passed as strings (for example
|
|
291
|
+
`SetVariable("points", ...)`), and local names that shadow a store variable
|
|
292
|
+
inside Python functions are not handled. If several declarations share a name,
|
|
293
|
+
all of them are renamed together.
|
|
294
|
+
|
|
295
|
+
Classes, functions, methods, fields, properties, stores, persistent variables,
|
|
296
|
+
test cases and translations are indexed for navigation and completion, but
|
|
297
|
+
class/function/member rename is intentionally deferred to a later release.
|
|
298
|
+
|
|
299
|
+
Occurrence highlights use Zed's `editor.document_highlight.write_background`
|
|
300
|
+
for declarations and `editor.document_highlight.read_background` for
|
|
301
|
+
references. Adjust those keys in the theme overrides if the shade is too
|
|
302
|
+
subtle.
|
|
303
|
+
|
|
304
|
+
Hover documentation for Ren'Py built-ins comes from the MIT-licensed
|
|
305
|
+
`vscode-language-renpy` data; see [`NOTICE.md`](NOTICE.md).
|
|
306
|
+
|
|
307
|
+
### Logs
|
|
308
|
+
|
|
309
|
+
The server writes logs to stderr, never stdout. Normal runs print only a startup
|
|
310
|
+
line; pygls protocol logs, which include full document contents, are disabled by
|
|
311
|
+
default. To inspect the JSON-RPC traffic, launch Zed with:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
RENPY_LANGUAGE_SERVER_DEBUG=1 zed .
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Formatting rules
|
|
318
|
+
|
|
319
|
+
| Rule | Detail |
|
|
320
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
321
|
+
| Indentation | `tabSize` from the editor (default 4) spaces per level; tabs are expanded |
|
|
322
|
+
| Trailing whitespace | removed |
|
|
323
|
+
| Assignments | the `=` of consecutive assignment lines at the same indentation level is aligned into one column |
|
|
324
|
+
| Inline spacing | assignment and comparison operators in `$`, `define`, `default`, `if`, `elif`, `while`, `return` and `assert` lines |
|
|
325
|
+
| Keyword arguments | spaces around `=` are removed (`color = "#fff"` becomes `color="#fff"`); real assignments keep them |
|
|
326
|
+
| Quotes | single-quoted strings become double-quoted unless the value contains an unescaped `"`; comments and values are untouched |
|
|
327
|
+
| Python blocks | assignment, comparison, arithmetic and bitwise operators inside `python:` blocks |
|
|
328
|
+
| Ruff (opt-in) | `--python` formats `python:` bodies with Ruff, changing more than the default rules |
|
|
329
|
+
| Blank lines | runs capped at 2; none at the start of the file |
|
|
330
|
+
| Block spacing | a blank line before top-level `label`, `screen`, `init`, `transform`; a comment block directly above stays attached |
|
|
331
|
+
| End of file | exactly one newline |
|
|
332
|
+
| Line endings | LF or CRLF is kept as found |
|
|
333
|
+
| Comments | re-indented to the block they sit in; a comment right after `label x:` joins the body |
|
|
334
|
+
|
|
335
|
+
String contents are never edited: a single-quoted literal is only rewritten to
|
|
336
|
+
double quotes when it contains no unescaped `"`, and quoted text in comments is
|
|
337
|
+
skipped. Indentation and alignment rules never touch dialogue, screen
|
|
338
|
+
properties or ATL lines; continuation lines of open brackets or backslashes are
|
|
339
|
+
shifted together with their first line, keeping their relative alignment.
|
|
340
|
+
Keyword and default-parameter `=` inside brackets is the only operator the
|
|
341
|
+
spacing pass tightens; top-level assignment `=` still gets spaces.
|
|
342
|
+
|
|
343
|
+
### Known assumptions and limits
|
|
344
|
+
|
|
345
|
+
- A string opened with a single `"` or `'` that is still open at the end of a
|
|
346
|
+
line is assumed to continue on the next line. A stray, unbalanced quote
|
|
347
|
+
outside a string or comment can therefore make the rest of the file look like
|
|
348
|
+
string content; the formatter leaves that part alone instead of guessing.
|
|
349
|
+
- Inline spacing outside `python:` blocks is limited to assignment and
|
|
350
|
+
comparison operators. Arithmetic spacing is applied inside `python:` blocks,
|
|
351
|
+
but not to every Ren'Py expression. Use `--no-spacing` to disable the pass.
|
|
352
|
+
- Quote normalization is on by default. Use `--no-quotes` or
|
|
353
|
+
`normalize_quotes: false` to keep single quotes. Literals containing an
|
|
354
|
+
unescaped `"` and unterminated literals are left unchanged. Range formatting
|
|
355
|
+
converts a multi-line literal only when both delimiters are in the selected
|
|
356
|
+
lines, so it is never left half-converted.
|
|
357
|
+
- Diagnostics are intentionally conservative. Newer rules are opt-in, and each
|
|
358
|
+
rule can be reduced to a warning or disabled independently.
|
|
359
|
+
- Ruff formatting changes more than whitespace, so it is opt-in and failure-safe.
|
|
360
|
+
|
|
361
|
+
## Development
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
uv sync
|
|
365
|
+
uv run pytest
|
|
366
|
+
uv run ruff check . && uv run ruff format --check .
|
|
367
|
+
uv run pyright
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
- `scanner.py`: tracks strings, comments and brackets across physical lines
|
|
371
|
+
- `analysis.py`: logical lines and the block tree
|
|
372
|
+
- `index.py`: workspace symbol index for Ren'Py declarations, references and
|
|
373
|
+
related declaration families
|
|
374
|
+
- `python_index.py`: conservative indentation parser for `python:` blocks
|
|
375
|
+
- `resolve.py`: shared target and occurrence resolution
|
|
376
|
+
- `references.py`: find-references provider
|
|
377
|
+
- `signature.py`: signature-help provider
|
|
378
|
+
- `completion.py`: context-aware completion for statements, screen bodies,
|
|
379
|
+
API namespaces, audio, dialogue attributes and Python expressions
|
|
380
|
+
- `completion_data.py` and `data/completion.json`: versioned screen, ATL and
|
|
381
|
+
keyword/value vocabulary
|
|
382
|
+
- `strings.py`: physical-line string spans shared by semantic tokens
|
|
383
|
+
- `semantic.py`: opt-in semantic tokens and UTF-16 delta encoding
|
|
384
|
+
- `definition.py`: literal `jump` / `call` target resolution
|
|
385
|
+
- `diagnostics.py`: configurable per-rule diagnostics and workspace publishing
|
|
386
|
+
- `code_actions.py`: safe quick fixes for diagnostics
|
|
387
|
+
- `symbols.py`: LSP document and workspace symbols
|
|
388
|
+
- `positions.py`: client-position conversion helpers
|
|
389
|
+
- `folding.py`: explicit block fold ranges
|
|
390
|
+
- `spacing.py`: inline operator spacing
|
|
391
|
+
- `python_format.py`: optional Ruff bridge
|
|
392
|
+
- `formatter.py`: indentation, blank lines, comments
|
|
393
|
+
- `edits.py`: old text to minimal LSP edits
|
|
394
|
+
- `server.py`: pygls glue (stdout carries the protocol, so log to stderr only)
|
|
395
|
+
- `dap.py`: launch-only Debug Adapter Protocol server, SDK/project discovery,
|
|
396
|
+
output streaming and process termination
|
|
397
|
+
- `tests/test_formatter_renpy.py`: formatter cases, idempotency and
|
|
398
|
+
"only whitespace changed" checks
|
|
399
|
+
- `tests/test_pipeline.py`: scanner, edits and CLI tests
|
|
400
|
+
- `tests/test_server_e2e.py`: starts the real server and formats over stdio
|
|
401
|
+
- `tests/test_dap.py`: launch configuration, SDK discovery and a fixture-SDK
|
|
402
|
+
DAP session over stdio
|
|
403
|
+
|
|
404
|
+
CI runs the test suite on Python 3.10 through 3.14.
|
|
405
|
+
|
|
406
|
+
### Checked against real scripts
|
|
407
|
+
|
|
408
|
+
Run on six files from the `renpy/renpy` repository (`the_question`, `tutorial`,
|
|
409
|
+
`launcher`; about 4,000 lines): in every file only whitespace changed and a
|
|
410
|
+
second pass changed nothing. Four were already formatted and came out unchanged.
|
|
411
|
+
|
|
412
|
+
## Roadmap
|
|
413
|
+
|
|
414
|
+
- [x] Diagnostics: indentation, tabs, filenames, variable names, comparisons,
|
|
415
|
+
obsolete APIs, labels, images, screens and persistent/store variables,
|
|
416
|
+
with per-rule severity and open/workspace modes
|
|
417
|
+
- [x] Document symbols and go to definition for labels, including local labels
|
|
418
|
+
- [x] Workspace-wide completion from an index
|
|
419
|
+
- [x] Completion contexts: labels, screens, images, transforms, transitions,
|
|
420
|
+
audio, API namespaces, screen bodies, dialogue attributes and Python
|
|
421
|
+
expressions
|
|
422
|
+
- [x] Opt-in semantic tokens
|
|
423
|
+
- [x] Launch-only DAP server (`renpy-language-server dap`) with SDK discovery and warp
|
|
424
|
+
- [x] Index Python classes, methods, fields, stores, persistent variables,
|
|
425
|
+
test cases and translations for outline and navigation
|
|
426
|
+
- [x] Inline spacing for Python-ish statements (`$ points=1` to `$ points = 1`)
|
|
427
|
+
- [x] Inline spacing inside `python:` blocks and around arithmetic operators
|
|
428
|
+
- [x] Format `python:` blocks with `ruff` (opt-in)
|
|
429
|
+
- [x] Range formatting
|
|
430
|
+
- [ ] Optional tree-sitter backend (decision pending)
|
|
431
|
+
|
|
432
|
+
## License
|
|
433
|
+
|
|
434
|
+
MIT. See [LICENSE](LICENSE).
|