tcl-ls 0.2.1__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.
- tcl_ls-0.2.1.dist-info/METADATA +172 -0
- tcl_ls-0.2.1.dist-info/RECORD +113 -0
- tcl_ls-0.2.1.dist-info/WHEEL +4 -0
- tcl_ls-0.2.1.dist-info/entry_points.txt +4 -0
- tcl_ls-0.2.1.dist-info/licenses/LICENSE +21 -0
- tcl_lsp/__init__.py +7 -0
- tcl_lsp/__main__.py +11 -0
- tcl_lsp/analysis/__init__.py +49 -0
- tcl_lsp/analysis/arity.py +158 -0
- tcl_lsp/analysis/builtins.py +484 -0
- tcl_lsp/analysis/control_flow.py +207 -0
- tcl_lsp/analysis/diagnostics/__init__.py +57 -0
- tcl_lsp/analysis/diagnostics/ambiguous_command.py +25 -0
- tcl_lsp/analysis/diagnostics/ambiguous_variable.py +27 -0
- tcl_lsp/analysis/diagnostics/base.py +74 -0
- tcl_lsp/analysis/diagnostics/duplicate_proc.py +24 -0
- tcl_lsp/analysis/diagnostics/helpers.py +267 -0
- tcl_lsp/analysis/diagnostics/invalid_arguments.py +51 -0
- tcl_lsp/analysis/diagnostics/invalid_regex.py +151 -0
- tcl_lsp/analysis/diagnostics/missing_option_value.py +29 -0
- tcl_lsp/analysis/diagnostics/unknown_option.py +29 -0
- tcl_lsp/analysis/diagnostics/unknown_subcommand.py +28 -0
- tcl_lsp/analysis/diagnostics/unreachable_code.py +350 -0
- tcl_lsp/analysis/diagnostics/unresolved_command.py +25 -0
- tcl_lsp/analysis/diagnostics/unresolved_package.py +27 -0
- tcl_lsp/analysis/diagnostics/unresolved_variable.py +27 -0
- tcl_lsp/analysis/diagnostics/wrong_argument_count.py +90 -0
- tcl_lsp/analysis/embedded_languages.py +528 -0
- tcl_lsp/analysis/facts/__init__.py +3 -0
- tcl_lsp/analysis/facts/collector.py +3143 -0
- tcl_lsp/analysis/facts/lowering.py +1394 -0
- tcl_lsp/analysis/facts/parsing.py +302 -0
- tcl_lsp/analysis/facts/utils.py +300 -0
- tcl_lsp/analysis/flow/__init__.py +25 -0
- tcl_lsp/analysis/flow/exprs.py +388 -0
- tcl_lsp/analysis/flow/variables.py +561 -0
- tcl_lsp/analysis/index.py +361 -0
- tcl_lsp/analysis/metadata_commands.py +1698 -0
- tcl_lsp/analysis/metadata_effects.py +296 -0
- tcl_lsp/analysis/model.py +264 -0
- tcl_lsp/analysis/resolver.py +1196 -0
- tcl_lsp/analysis/signature_matching.py +287 -0
- tcl_lsp/cache.py +42 -0
- tcl_lsp/checker/__init__.py +10 -0
- tcl_lsp/checker/cli.py +116 -0
- tcl_lsp/checker/model.py +31 -0
- tcl_lsp/checker/reporting.py +425 -0
- tcl_lsp/checker/service.py +555 -0
- tcl_lsp/common.py +111 -0
- tcl_lsp/lsp/__init__.py +3 -0
- tcl_lsp/lsp/document_changes.py +138 -0
- tcl_lsp/lsp/features/__init__.py +1 -0
- tcl_lsp/lsp/features/completion.py +941 -0
- tcl_lsp/lsp/features/cursor_context.py +217 -0
- tcl_lsp/lsp/features/document_links.py +81 -0
- tcl_lsp/lsp/features/folding.py +107 -0
- tcl_lsp/lsp/features/highlights.py +76 -0
- tcl_lsp/lsp/features/hover.py +27 -0
- tcl_lsp/lsp/features/navigation.py +310 -0
- tcl_lsp/lsp/features/rename.py +348 -0
- tcl_lsp/lsp/features/signature_help.py +199 -0
- tcl_lsp/lsp/features/symbols.py +124 -0
- tcl_lsp/lsp/features/workspace_symbols.py +125 -0
- tcl_lsp/lsp/semantic_tokens.py +407 -0
- tcl_lsp/lsp/server.py +1255 -0
- tcl_lsp/lsp/state.py +57 -0
- tcl_lsp/lsp/workspace_rebuild.py +576 -0
- tcl_lsp/meta/__init__.py +63 -0
- tcl_lsp/meta/meta.meta.tcl +304 -0
- tcl_lsp/meta/plugins/host.tcl +140 -0
- tcl_lsp/meta/tcl8.6/msgcat.meta.tcl +24 -0
- tcl_lsp/meta/tcl8.6/tcl.meta.tcl +1878 -0
- tcl_lsp/meta/tcl8.6/tcloo.meta.tcl +74 -0
- tcl_lsp/meta/tcl8.6/tcltest.meta.tcl +132 -0
- tcl_lsp/meta/tcl8.6/tk.meta.tcl +114 -0
- tcl_lsp/meta/tcllib/asn.meta.tcl +75 -0
- tcl_lsp/meta/tcllib/clay.meta.tcl +55 -0
- tcl_lsp/meta/tcllib/cmdline.meta.tcl +22 -0
- tcl_lsp/meta/tcllib/doctools/text.meta.tcl +30 -0
- tcl_lsp/meta/tcllib/fileutil.meta.tcl +30 -0
- tcl_lsp/meta/tcllib/json/write.meta.tcl +27 -0
- tcl_lsp/meta/tcllib/json.meta.tcl +9 -0
- tcl_lsp/meta/tcllib/log.meta.tcl +12 -0
- tcl_lsp/meta/tcllib/logger.meta.tcl +35 -0
- tcl_lsp/meta/tcllib/oo/meta.meta.tcl +6 -0
- tcl_lsp/meta/tcllib/struct/set.meta.tcl +56 -0
- tcl_lsp/meta/tcllib/tepam.meta.tcl +7 -0
- tcl_lsp/meta/tcllib/tepam.tcl +68 -0
- tcl_lsp/meta/tcllib/testutilities.meta.tcl +34 -0
- tcl_lsp/meta/tcllib/textutil/adjust.meta.tcl +27 -0
- tcl_lsp/meta/tcllib/textutil/repeat.meta.tcl +9 -0
- tcl_lsp/meta/tcllib/textutil/split.meta.tcl +9 -0
- tcl_lsp/meta/tcllib/textutil/string.meta.tcl +24 -0
- tcl_lsp/meta/tcllib/textutil/tabify.meta.tcl +15 -0
- tcl_lsp/meta/tcllib/textutil/textutil.meta.tcl +78 -0
- tcl_lsp/meta/tcllib/textutil/trim.meta.tcl +18 -0
- tcl_lsp/meta/tcllib/textutil/wcswidth.meta.tcl +12 -0
- tcl_lsp/meta_tools.py +5 -0
- tcl_lsp/metadata_paths.py +122 -0
- tcl_lsp/parser/__init__.py +30 -0
- tcl_lsp/parser/expr.py +452 -0
- tcl_lsp/parser/helpers.py +103 -0
- tcl_lsp/parser/model.py +87 -0
- tcl_lsp/parser/parser.py +758 -0
- tcl_lsp/plugins/__init__.py +1 -0
- tcl_lsp/plugins/host.py +681 -0
- tcl_lsp/project/__init__.py +1 -0
- tcl_lsp/project/config.py +100 -0
- tcl_lsp/project/indexing.py +275 -0
- tcl_lsp/project/paths.py +66 -0
- tcl_lsp/project_config.py +17 -0
- tcl_lsp/tools/tcl_meta.tcl +353 -0
- tcl_lsp/workspace.py +15 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tcl-ls
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Tcl language server, checker, and metadata toolkit.
|
|
5
|
+
Project-URL: Documentation, https://lewis6991.github.io/tcl-ls/
|
|
6
|
+
Project-URL: Homepage, https://github.com/lewis6991/tcl-ls
|
|
7
|
+
Project-URL: Issues, https://github.com/lewis6991/tcl-ls/issues
|
|
8
|
+
Project-URL: Repository, https://github.com/lewis6991/tcl-ls
|
|
9
|
+
Project-URL: Changelog, https://github.com/lewis6991/tcl-ls/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Lewis Russell <lewis6991@gmail.com>
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: language-server,lint,lsp,static-analysis,tcl
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Natural Language :: English
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development
|
|
23
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.14
|
|
26
|
+
Requires-Dist: pygls>=2.1.0
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# tcl-ls
|
|
30
|
+
|
|
31
|
+
A Tcl language server, checker, and metadata toolkit implemented in typed
|
|
32
|
+
Python.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
`tcl-ls` currently targets Python 3.14 or newer.
|
|
37
|
+
|
|
38
|
+
Install from PyPI with:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
python3 -m pip install tcl-ls
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You can also download packaged server archives and editor assets from the
|
|
45
|
+
[GitHub Releases](https://github.com/lewis6991/tcl-ls/releases) page.
|
|
46
|
+
|
|
47
|
+
This installs three command-line entry points:
|
|
48
|
+
|
|
49
|
+
* `tcl-ls` for the stdio language server
|
|
50
|
+
* `tcl-check` for batch diagnostics
|
|
51
|
+
* `tcl-meta` for Tcl metadata-helper workflows
|
|
52
|
+
|
|
53
|
+
For local development from a checkout, sync the environment once and prefer
|
|
54
|
+
`uv run ...` for commands you do not want to install globally:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
uv sync
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Current Scope
|
|
61
|
+
|
|
62
|
+
This is an alpha release aimed at early adopters. The server is already useful
|
|
63
|
+
for diagnostics, navigation, completion, rename, signature help, semantic
|
|
64
|
+
tokens, and metadata-assisted checking, but it still analyzes Tcl
|
|
65
|
+
conservatively and does not try to model the full dynamic runtime.
|
|
66
|
+
|
|
67
|
+
## Documentation
|
|
68
|
+
|
|
69
|
+
Published docs are available at
|
|
70
|
+
<https://lewis6991.github.io/tcl-ls/>.
|
|
71
|
+
|
|
72
|
+
Build the Sphinx docs locally with:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
make docs
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The rendered site is written to `docs/_build/html/index.html` and covers
|
|
79
|
+
getting started, editor and checker workflows, metadata authoring, support,
|
|
80
|
+
and development notes.
|
|
81
|
+
|
|
82
|
+
Editor-specific helpers shipped in this repository:
|
|
83
|
+
|
|
84
|
+
* `editors/vscode` for the VS Code extension
|
|
85
|
+
* `editors/nvim` for the Neovim 0.11+ built-in LSP config
|
|
86
|
+
|
|
87
|
+
## Maintenance
|
|
88
|
+
|
|
89
|
+
Refresh builtin subcommand metadata with:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
python3 scripts/generate_builtin_commands.py
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The generator updates `meta/tcl8.6/tcl.meta.tcl` in place and
|
|
96
|
+
supports `--input`, `--output`, `--doc-root`, `--tcl-doc-series`, and
|
|
97
|
+
`--version-label` for versioned metadata workflows.
|
|
98
|
+
|
|
99
|
+
## Metadata
|
|
100
|
+
|
|
101
|
+
Metadata files use the `*.meta.tcl` suffix and `meta command` entries:
|
|
102
|
+
|
|
103
|
+
```tcl
|
|
104
|
+
meta command regexp {args} {
|
|
105
|
+
option -start value
|
|
106
|
+
option -- stop
|
|
107
|
+
bind after-options 3..
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The optional body is declarative analysis metadata. Current annotations are:
|
|
112
|
+
`option`, `keyword`, `subcommand`, `bind`, `ref`, `script-body`,
|
|
113
|
+
`source`, and `package`.
|
|
114
|
+
|
|
115
|
+
## Diagnostics
|
|
116
|
+
|
|
117
|
+
Install the package first so the CLI entry points are available:
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
python3 -m pip install tcl-ls
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Analyze a Tcl file or project tree with:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
tcl-check path/to/project
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
In an interactive terminal, the checker prepares package-scoped workspaces
|
|
130
|
+
(directories rooted by `pkgIndex.tcl`), then prints final grouped diagnostics
|
|
131
|
+
with source context and a finished summary as each workspace is analyzed. Use
|
|
132
|
+
`--color=always|never|auto` and `--context-lines=N` to tune the terminal
|
|
133
|
+
output.
|
|
134
|
+
|
|
135
|
+
To inspect the current diagnostics emitted for `tcllib`, use:
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
make check-tcllib
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Pass extra checker flags through `make` with:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
make check-tcllib TCL_CHECK_ARGS="--context-lines=1 --fail-on-diagnostics"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Project-local config can live in `tcllsrc.tcl`. Supported commands are:
|
|
148
|
+
|
|
149
|
+
```tcl
|
|
150
|
+
plugin-path .tcl-ls/sample.tcl
|
|
151
|
+
lib-path ../tcllib
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Configured paths are resolved relative to the config file. `lib-path` roots are
|
|
155
|
+
scanned for `pkgIndex.tcl` files so external library trees can satisfy
|
|
156
|
+
`package require` without moving them into the project.
|
|
157
|
+
|
|
158
|
+
To build metadata inside a tool-specific Tcl shell, source the bundled helper
|
|
159
|
+
reported by:
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
tcl-meta helper-path
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Then, inside that tool Tcl shell, write metadata directly with:
|
|
166
|
+
|
|
167
|
+
```tcl
|
|
168
|
+
tcl-meta build-file output.meta.tcl
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
For local development in this repository, use `uv run ...` when you want to
|
|
172
|
+
run the CLI without installing it first.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
tcl_lsp/__init__.py,sha256=Z_jHDkh_mAq0LRipUViJMN0oNTAzHX6neKNuTUnkHGY,147
|
|
2
|
+
tcl_lsp/__main__.py,sha256=2YaqmK33z90UFfgA8BPtYZ9fH1fhiZQwNojFH-iwQeI,151
|
|
3
|
+
tcl_lsp/cache.py,sha256=bRIVwTgiEUcZGRC4eOeQUdKSnTqGXa8C76lZuTOUkyM,1139
|
|
4
|
+
tcl_lsp/common.py,sha256=6Fj3rM05s-VjdkMKH1WO27KZhWMEa8UmE8l-zUaoTYg,2991
|
|
5
|
+
tcl_lsp/meta_tools.py,sha256=RNhFSGZtik7bhXNFMLks74epgRhrmwgugsGvZd6cdUs,134
|
|
6
|
+
tcl_lsp/metadata_paths.py,sha256=oZ1pEuhaC93QmZpXw8ymfLBPlvWQQnAVZLmvw_4M_kM,4277
|
|
7
|
+
tcl_lsp/project_config.py,sha256=qkLYiryXKLh93D_JmTpdmEtchfFt0QeEnWiMSEDkeMs,360
|
|
8
|
+
tcl_lsp/workspace.py,sha256=EZWu5Uu5VT5KB3JRVlOivdu-5ACbV_56upk5fbXUIFQ,321
|
|
9
|
+
tcl_lsp/analysis/__init__.py,sha256=B6YiB56c4OTsBB4O2CUK8vLSVKs8Yrjq7xCZTJfmvig,1057
|
|
10
|
+
tcl_lsp/analysis/arity.py,sha256=bl2YCEPv-wk4xOrJMzOT9jxDOtfcYmAUke9rvTpgACo,5251
|
|
11
|
+
tcl_lsp/analysis/builtins.py,sha256=9VIAYyp3QIA5gsjHR-GkNSkvHV1CDkNXp4xAnEjcuuM,16778
|
|
12
|
+
tcl_lsp/analysis/control_flow.py,sha256=rPKZov0Yhev1ZEJBe3XTt_HmwCJo3lpH1ikAc9FSbAE,6534
|
|
13
|
+
tcl_lsp/analysis/embedded_languages.py,sha256=IL0c_m6ADdbEvv6NZa-Y0sQIv-C3xwsiqrL3Sw5WOKs,18081
|
|
14
|
+
tcl_lsp/analysis/index.py,sha256=T42xz9uw-U1IjWpFrXwNJHxsRyGaT-4uFOoiT1NM3U4,15397
|
|
15
|
+
tcl_lsp/analysis/metadata_commands.py,sha256=WAGpTFF_O18y6jn4mVse5rjWROZeW6NOJhHsRFRJGdM,61729
|
|
16
|
+
tcl_lsp/analysis/metadata_effects.py,sha256=Vkzj60HuFIYrXdVxm3v47CswS7tyCoaiSrLo1zYbkMk,10341
|
|
17
|
+
tcl_lsp/analysis/model.py,sha256=7ueeweDhw69XiFCcPFRwE6rDJJRSecNawtN0Kxl3wOw,5776
|
|
18
|
+
tcl_lsp/analysis/resolver.py,sha256=OX4PQSTmmF3n-UPWL1IGYcPCZUtXUazfW7_3l4mZdO0,44103
|
|
19
|
+
tcl_lsp/analysis/signature_matching.py,sha256=GI7Xtw90FHRyqfUigHROJ8zwjtaH5yZrXB6609cvld8,8488
|
|
20
|
+
tcl_lsp/analysis/diagnostics/__init__.py,sha256=CQzLP8hO2utYjX40bv8GElFYK2ofpvDfhKTbIkwl874,1763
|
|
21
|
+
tcl_lsp/analysis/diagnostics/ambiguous_command.py,sha256=5k3qfA6MslCtglYigjeEYI83i03Qb0FZv7UETGbXJUg,937
|
|
22
|
+
tcl_lsp/analysis/diagnostics/ambiguous_variable.py,sha256=rLnuSFr9GL4qtFKK8G--BtHOcn0mBZS5gIro9hPiC7Y,1004
|
|
23
|
+
tcl_lsp/analysis/diagnostics/base.py,sha256=B5_3UrHglgjooY8J6PrLLh-q_bRs6CwMVST-QwLpaI8,2071
|
|
24
|
+
tcl_lsp/analysis/diagnostics/duplicate_proc.py,sha256=Zf86DcxIjr44zZ5qgrRacr_9_VV_aADIhU4OammVcFE,843
|
|
25
|
+
tcl_lsp/analysis/diagnostics/helpers.py,sha256=UmVonvysV9gxjqbbOp8_s-spDeTbg6o5EYG3AqfKskw,9279
|
|
26
|
+
tcl_lsp/analysis/diagnostics/invalid_arguments.py,sha256=tnMcvs9DsQsVBZPcYpJ8x4bS-4Givze1kQvTcp_NwMw,2023
|
|
27
|
+
tcl_lsp/analysis/diagnostics/invalid_regex.py,sha256=9NFtZqXTidKdBQ5uH2VgikyKXtOWraZGK-v7lupsDkM,4532
|
|
28
|
+
tcl_lsp/analysis/diagnostics/missing_option_value.py,sha256=KLhyGTqzRC84wcgNwmK8Ovb5UMf_Dru2dmXdKiiGoyU,1088
|
|
29
|
+
tcl_lsp/analysis/diagnostics/unknown_option.py,sha256=IzEhFqlZbsRsN9WQVqFHgVJp6IIW0_MczKiq2Zez6AY,1068
|
|
30
|
+
tcl_lsp/analysis/diagnostics/unknown_subcommand.py,sha256=6hWGsRUNsAAURbpEQL3K16m8SFRZkiJ9Q7MYw_bNWMw,1030
|
|
31
|
+
tcl_lsp/analysis/diagnostics/unreachable_code.py,sha256=BRVFxqnjdpCa_z2RGqVLnznrL8pKh8tcP8LxaC9hSak,11033
|
|
32
|
+
tcl_lsp/analysis/diagnostics/unresolved_command.py,sha256=R5gN4A67z_FlJeYyb2gtH5fC7dbJ9oy42HoQTP68CIo,919
|
|
33
|
+
tcl_lsp/analysis/diagnostics/unresolved_package.py,sha256=GUmT_pRVYe9S4XHAg4QDlkRpY87Dou5kCcUs-g8fC34,999
|
|
34
|
+
tcl_lsp/analysis/diagnostics/unresolved_variable.py,sha256=-Q-XTxAAe108twSGAuDhpnqlRaSHhTgFf-PT8JXe8P8,988
|
|
35
|
+
tcl_lsp/analysis/diagnostics/wrong_argument_count.py,sha256=c84SuBJLAjrxZ2C-6V2YiYZVVELynSR1yVFK3KmT1xc,2979
|
|
36
|
+
tcl_lsp/analysis/facts/__init__.py,sha256=P4Qx6dokoG8MK7hlnp9baWqQA-2tCejKGC0Syuse2d4,88
|
|
37
|
+
tcl_lsp/analysis/facts/collector.py,sha256=iLLENMtIq_WqYe_SSUBkLafTMffoQ0CR1RnA9IKUQ-k,112276
|
|
38
|
+
tcl_lsp/analysis/facts/lowering.py,sha256=dqgX2KoquUdeuHDwJ1vlMrsyQaJrS7e3FZWenhCmQ8I,47385
|
|
39
|
+
tcl_lsp/analysis/facts/parsing.py,sha256=qnc-y1rsyjWSm2P7y3TjCjowGMlG9NbTRRpZuEZ2Qdg,9621
|
|
40
|
+
tcl_lsp/analysis/facts/utils.py,sha256=9NA0rwZ3rllSkASrZjIl_YeOjsPb2K6WeZEZ3GL2eZQ,8697
|
|
41
|
+
tcl_lsp/analysis/flow/__init__.py,sha256=8ikNrMKDvjHH0GmQ8Iqj_RID3ZpgsqjbrA8wZoCMzkY,651
|
|
42
|
+
tcl_lsp/analysis/flow/exprs.py,sha256=HifYM4iaaiMIkVEhTyFfW84bQRkqNZUCCa7wkiNHczU,12893
|
|
43
|
+
tcl_lsp/analysis/flow/variables.py,sha256=ZtHNSBnZaARP_FmbfTAqdJrssOt1fvHF_4Qq806u-ug,16579
|
|
44
|
+
tcl_lsp/checker/__init__.py,sha256=8zH7jAyrKmGeg2hNwAa-hccY93JWZjc8ypgR4B1jDkA,304
|
|
45
|
+
tcl_lsp/checker/cli.py,sha256=sDt7AlwT32PrOIv_j67j3VV4d-grXmYs6cS3jpMLqJE,3481
|
|
46
|
+
tcl_lsp/checker/model.py,sha256=1908XxAhwzZNOQgBncwgm7iqet7qQZwUqGCrSafvluk,772
|
|
47
|
+
tcl_lsp/checker/reporting.py,sha256=hNwUOH5r1Wsfixs1a6DIXe2fyl1r6ALdXsf0gq-vrT8,13174
|
|
48
|
+
tcl_lsp/checker/service.py,sha256=Lrx3KutMXhgL8bf-tiwkuLANsXEVmszqIvRLh4xIyfE,17930
|
|
49
|
+
tcl_lsp/lsp/__init__.py,sha256=uFcP3Faz7XRcwAW0hL3YQMkwGiP1LeIl0XJ7shn_4Us,94
|
|
50
|
+
tcl_lsp/lsp/document_changes.py,sha256=HbsVdiDQPeZtTFWeg88irjuDOvyNB8-Wg2otZzL8U2o,5293
|
|
51
|
+
tcl_lsp/lsp/semantic_tokens.py,sha256=ruuzqm0lxNHC5XtZFua8J8BfeJH8FehqicqwL3MqngE,12539
|
|
52
|
+
tcl_lsp/lsp/server.py,sha256=ng5UqLdlY6BifhI0e7cTnSeGruiwtI7WS_SZn2tyToM,44132
|
|
53
|
+
tcl_lsp/lsp/state.py,sha256=ERvfUwYGOLb7kZQ0NDIRjRcxO62r-asK9wDWQX_yArU,1493
|
|
54
|
+
tcl_lsp/lsp/workspace_rebuild.py,sha256=m5UomA9p81eM7K9OqO6nWztL7O2Q7-Kt1oPMe_552wU,21458
|
|
55
|
+
tcl_lsp/lsp/features/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
56
|
+
tcl_lsp/lsp/features/completion.py,sha256=oGiXwUaQLoRAGhWDP-Jbz7AqX0kZTylGvunuaeJM_G8,29996
|
|
57
|
+
tcl_lsp/lsp/features/cursor_context.py,sha256=TsOHN9J7S5Pr32TqlmT9zEsWEZ9ot-6Nxef58YaKxQ8,7051
|
|
58
|
+
tcl_lsp/lsp/features/document_links.py,sha256=S6qi62vR85IFTSdiswbemmZ62f_SkZa1xwbFeiSjT_A,2179
|
|
59
|
+
tcl_lsp/lsp/features/folding.py,sha256=zkWUhmybb59M7x6yCbtpEcM0ZxhtEouLL5odRCTmrPM,3418
|
|
60
|
+
tcl_lsp/lsp/features/highlights.py,sha256=SlNH7uOl6REG0AHGk7RQEAuIz6VAs-S_Cie4uPFVcWU,2105
|
|
61
|
+
tcl_lsp/lsp/features/hover.py,sha256=BuPQ2-tqKGk7XdWK8Jril2oB0kxAdGc_NtVfnFNn1kA,664
|
|
62
|
+
tcl_lsp/lsp/features/navigation.py,sha256=8_1kxmXHU0iD-vjsQXvSRtYlUQxhW6otJleHGWTgG2Q,9532
|
|
63
|
+
tcl_lsp/lsp/features/rename.py,sha256=06rYI8tLKl4MXohgL7vYvmis_xD923eO7eFzihBT4iQ,10769
|
|
64
|
+
tcl_lsp/lsp/features/signature_help.py,sha256=yzcHwkPI4oyBMhwn73juhX3g3ONSh4BzWu4w75G0M-U,6329
|
|
65
|
+
tcl_lsp/lsp/features/symbols.py,sha256=ezX-iztPbsxuKfb0m0cjuk8hneBCNenn-zm2DcUV_-0,4319
|
|
66
|
+
tcl_lsp/lsp/features/workspace_symbols.py,sha256=yFWO5IpQoAvlQbIbRmRndcN3Yk7-raTcQ2AZdthxGjo,4064
|
|
67
|
+
tcl_lsp/meta/__init__.py,sha256=0BQGmFI-DN86Qk3u8sosI4jrqu5zm_WpKkjeWpQ0enY,1843
|
|
68
|
+
tcl_lsp/parser/__init__.py,sha256=Xcn-8Fhc5VrUF7hNQPyZc8iadXkZsowcSqaFZL4H8tI,607
|
|
69
|
+
tcl_lsp/parser/expr.py,sha256=0ME4Xgb7y8N3l5SonQDERYA95_0V7OCpIEZQ3LicKe0,14338
|
|
70
|
+
tcl_lsp/parser/helpers.py,sha256=p3ZO8gNuuDa8YIkwPkLdlr421dCc6EsyzivZxrphegY,2803
|
|
71
|
+
tcl_lsp/parser/model.py,sha256=FXTRIi2XgjZxbtf0P0pk1xo-YVydGa9UajyWwM28tE4,1650
|
|
72
|
+
tcl_lsp/parser/parser.py,sha256=CaSHIFfK2zYTWPeQhU_q2j9gDzu3XCzAjqgZOLmZ5zE,26994
|
|
73
|
+
tcl_lsp/plugins/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
74
|
+
tcl_lsp/plugins/host.py,sha256=VNUsONnD5v8GTr2CmXmMy3L9rIYLBWhEMsf1fhlfYY8,25309
|
|
75
|
+
tcl_lsp/project/__init__.py,sha256=-OIX0tODIsxobWvnL_znXzf9Bc6-pJn14IujHZBGulM,57
|
|
76
|
+
tcl_lsp/project/config.py,sha256=J-6cOlpiTrLf60SvnsJH0yVWAAuLYM8zCNeaunPX5gQ,3497
|
|
77
|
+
tcl_lsp/project/indexing.py,sha256=7g7nfQEgLtnE81FQm4j9CENejY-hXyQtnnAFwyTibLg,9517
|
|
78
|
+
tcl_lsp/project/paths.py,sha256=vNa1gv9G23GAnPtTxWCDs98WgVEZmLTb1MrjxJLNJMo,1828
|
|
79
|
+
tcl_lsp/meta/meta.meta.tcl,sha256=l3Yzbk2ctP4esFeh9drnfL8oOm1GuI2Gt0bSLwrP7WY,10570
|
|
80
|
+
tcl_lsp/meta/plugins/host.tcl,sha256=e-19IW8gTYtDhalP7N0Y61cY0MMN7q3S4kKoINyZNmA,3646
|
|
81
|
+
tcl_lsp/meta/tcl8.6/msgcat.meta.tcl,sha256=N6GfkbhNCehL5CSG21sZmr1jZqWrUirXB_53exoqThs,791
|
|
82
|
+
tcl_lsp/meta/tcl8.6/tcl.meta.tcl,sha256=UNW3jrypZNR29DtYM8hLGyPp85ESMSINHtF1eGlYICE,77898
|
|
83
|
+
tcl_lsp/meta/tcl8.6/tcloo.meta.tcl,sha256=kxHMfZv036lcQ2wOrmfV0ymqhUY10uLu9Qsg2IRZpBA,1844
|
|
84
|
+
tcl_lsp/meta/tcl8.6/tcltest.meta.tcl,sha256=Ywxvd7hlY162kmYJWiSInxXBqPtvWGr-lnSp4MYGbYQ,4331
|
|
85
|
+
tcl_lsp/meta/tcl8.6/tk.meta.tcl,sha256=WmM2eQ3OFe3Ryhw9-sPFUpbS8fDtw8m4dVUYY-hr_UM,2918
|
|
86
|
+
tcl_lsp/meta/tcllib/asn.meta.tcl,sha256=JSuFYV5sE2QzlznPsydoZYg0oLpcAXOk_1qCZCvdd9A,2125
|
|
87
|
+
tcl_lsp/meta/tcllib/clay.meta.tcl,sha256=tI0LJ5SjS6JPhpDrgR9fDm3QnlE-2SLFcXH4xMmhPhU,1747
|
|
88
|
+
tcl_lsp/meta/tcllib/cmdline.meta.tcl,sha256=Dkp3iLNhQ8X2_erqWSgLYCe4sxT0HuEH0zqwIYI6bKw,843
|
|
89
|
+
tcl_lsp/meta/tcllib/fileutil.meta.tcl,sha256=BlQBd4-fmiI3ZJ9hMMiegPuhZ_tWGt8qQEOV1yICX1M,1024
|
|
90
|
+
tcl_lsp/meta/tcllib/json.meta.tcl,sha256=7M5aENYJrwI6eLRop8oR-EwHsBHOhlliXdwqZrSXXx0,331
|
|
91
|
+
tcl_lsp/meta/tcllib/log.meta.tcl,sha256=yKiclBUzACe_SPXHQSoZ3ebGxLYqEcjpNi-cEO2TucI,335
|
|
92
|
+
tcl_lsp/meta/tcllib/logger.meta.tcl,sha256=nMB5gntetkbTp7G4Va8dy1WPk8suoY0m07YkYuM-Bv4,964
|
|
93
|
+
tcl_lsp/meta/tcllib/tepam.meta.tcl,sha256=W7S_WHtCe8RbOJa5pFH9S2FDWDt56ljcfXc2drDOGFU,235
|
|
94
|
+
tcl_lsp/meta/tcllib/tepam.tcl,sha256=KlLM_4Y_537VlSbE1T3YNiC0-CEGpXTvfNr9s093rpA,1763
|
|
95
|
+
tcl_lsp/meta/tcllib/testutilities.meta.tcl,sha256=2pf7mGU7dJIcRceeAHZA1mry5BRGFdKGrGWfS2QxUDI,864
|
|
96
|
+
tcl_lsp/meta/tcllib/doctools/text.meta.tcl,sha256=4gG8qWM_uKFL1A713K5GyXcUA5b1LWuiftjZrokYZZY,881
|
|
97
|
+
tcl_lsp/meta/tcllib/json/write.meta.tcl,sha256=-lz2Mw3i9sp66jlSqmJD0GMNZuIqLsD94xWxTTCGpJo,795
|
|
98
|
+
tcl_lsp/meta/tcllib/oo/meta.meta.tcl,sha256=EUbE8boQ22olznFIArckbCC3FNxrZhpIv9BywTU5tOI,262
|
|
99
|
+
tcl_lsp/meta/tcllib/struct/set.meta.tcl,sha256=s6LGaXx41TziyzD8M4NvzJErzVxMoGdTz_COobI7YcM,1502
|
|
100
|
+
tcl_lsp/meta/tcllib/textutil/adjust.meta.tcl,sha256=SZy3iVa-B1kaVZ37vhwWMPlOITt5Z1MQco5wIMuynzY,881
|
|
101
|
+
tcl_lsp/meta/tcllib/textutil/repeat.meta.tcl,sha256=POfuzlCm18yqDDUUE-mP3pfVhUlzPTrID--b10XTuZ0,338
|
|
102
|
+
tcl_lsp/meta/tcllib/textutil/split.meta.tcl,sha256=gDplp6P__nj-AayBQRJbh5WJNAyBZJRLRugYGS0PQkc,346
|
|
103
|
+
tcl_lsp/meta/tcllib/textutil/string.meta.tcl,sha256=F6_0DP4Pnwcq9YXnLthJqfx1U7CuijsPN3uvAhcC7Uc,850
|
|
104
|
+
tcl_lsp/meta/tcllib/textutil/tabify.meta.tcl,sha256=7LJ9tM-k5ayL8Z4gXKm9dAUtgPMAJnJ4wt9nWicgN9k,574
|
|
105
|
+
tcl_lsp/meta/tcllib/textutil/textutil.meta.tcl,sha256=7E-FPNOv9BCnZF2PBFAI6DMSij0863YGLsK0tGHWnIc,2418
|
|
106
|
+
tcl_lsp/meta/tcllib/textutil/trim.meta.tcl,sha256=vNfJKhvtbM7WhlxW2YMjJs7yivGWBFJ4ZvewVwzrtIQ,690
|
|
107
|
+
tcl_lsp/meta/tcllib/textutil/wcswidth.meta.tcl,sha256=i8ed55gOWRuqTMttOhL7YUfX-2Bn6AGoAI2kI1HZEqk,462
|
|
108
|
+
tcl_lsp/tools/tcl_meta.tcl,sha256=N_maNu6-6O3rjyB4iJVkVpUvGCM1gXplmy7maJB_hzQ,10590
|
|
109
|
+
tcl_ls-0.2.1.dist-info/METADATA,sha256=FWIbSMtU_FvUmKhDGrXFOfU4_u6x1DOBBmDKC1qH_sE,4795
|
|
110
|
+
tcl_ls-0.2.1.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
111
|
+
tcl_ls-0.2.1.dist-info/entry_points.txt,sha256=NskNMhUhsbnrx-F0dLgEbIud05yZn9rUHECWx83T9RQ,111
|
|
112
|
+
tcl_ls-0.2.1.dist-info/licenses/LICENSE,sha256=0IRROPkZlOEEIQsh7ZIPstOEIqUoU1IFm1i5HntE8s8,1070
|
|
113
|
+
tcl_ls-0.2.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lewis Russell
|
|
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.
|
tcl_lsp/__init__.py
ADDED
tcl_lsp/__main__.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from tcl_lsp.analysis.facts import FactExtractor
|
|
2
|
+
from tcl_lsp.analysis.index import WorkspaceIndex
|
|
3
|
+
from tcl_lsp.analysis.model import (
|
|
4
|
+
AnalysisResult,
|
|
5
|
+
AnalysisUncertainty,
|
|
6
|
+
CommandArity,
|
|
7
|
+
CommandCall,
|
|
8
|
+
CommandImport,
|
|
9
|
+
DefinitionTarget,
|
|
10
|
+
DocumentFacts,
|
|
11
|
+
NamespaceScope,
|
|
12
|
+
PackageIndexEntry,
|
|
13
|
+
PackageProvide,
|
|
14
|
+
PackageRequire,
|
|
15
|
+
ParameterDecl,
|
|
16
|
+
ProcDecl,
|
|
17
|
+
ReferenceSite,
|
|
18
|
+
ResolutionResult,
|
|
19
|
+
ResolvedReference,
|
|
20
|
+
SourceDirective,
|
|
21
|
+
VarBinding,
|
|
22
|
+
VariableReference,
|
|
23
|
+
)
|
|
24
|
+
from tcl_lsp.analysis.resolver import Resolver
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
'AnalysisResult',
|
|
28
|
+
'AnalysisUncertainty',
|
|
29
|
+
'CommandArity',
|
|
30
|
+
'CommandCall',
|
|
31
|
+
'CommandImport',
|
|
32
|
+
'DefinitionTarget',
|
|
33
|
+
'DocumentFacts',
|
|
34
|
+
'FactExtractor',
|
|
35
|
+
'NamespaceScope',
|
|
36
|
+
'PackageIndexEntry',
|
|
37
|
+
'PackageProvide',
|
|
38
|
+
'PackageRequire',
|
|
39
|
+
'ParameterDecl',
|
|
40
|
+
'ProcDecl',
|
|
41
|
+
'ReferenceSite',
|
|
42
|
+
'ResolutionResult',
|
|
43
|
+
'ResolvedReference',
|
|
44
|
+
'Resolver',
|
|
45
|
+
'SourceDirective',
|
|
46
|
+
'VarBinding',
|
|
47
|
+
'VariableReference',
|
|
48
|
+
'WorkspaceIndex',
|
|
49
|
+
]
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tcl_lsp.analysis.facts.parsing import ListItem, is_simple_name, split_tcl_list
|
|
4
|
+
from tcl_lsp.analysis.model import CommandArity
|
|
5
|
+
from tcl_lsp.common import Position
|
|
6
|
+
|
|
7
|
+
_ZERO_POSITION = Position(offset=0, line=0, character=0)
|
|
8
|
+
_DEFAULT_LITERAL_KEYWORDS = frozenset({'start'})
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def proc_parameter_arity(items: tuple[ListItem, ...]) -> CommandArity | None:
|
|
12
|
+
min_args = 0
|
|
13
|
+
max_args = 0
|
|
14
|
+
|
|
15
|
+
for index, item in enumerate(items):
|
|
16
|
+
parameter = _proc_parameter_spec(item)
|
|
17
|
+
if parameter is None:
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
name, optional = parameter
|
|
21
|
+
if name == 'args':
|
|
22
|
+
if optional or index != len(items) - 1:
|
|
23
|
+
return None
|
|
24
|
+
return CommandArity(min_args=min_args, max_args=None)
|
|
25
|
+
|
|
26
|
+
if not optional:
|
|
27
|
+
min_args += 1
|
|
28
|
+
max_args += 1
|
|
29
|
+
|
|
30
|
+
return CommandArity(min_args=min_args, max_args=max_args)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def metadata_signature_arity(signature: str) -> CommandArity | None:
|
|
34
|
+
text = signature.strip()
|
|
35
|
+
if not text or text == '{}':
|
|
36
|
+
return CommandArity(min_args=0, max_args=0)
|
|
37
|
+
|
|
38
|
+
items = tuple(item.text for item in split_tcl_list(text, _ZERO_POSITION))
|
|
39
|
+
if not items or items == ('',):
|
|
40
|
+
return CommandArity(min_args=0, max_args=0)
|
|
41
|
+
return _signature_items_arity(items)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _signature_items_arity(items: tuple[str, ...]) -> CommandArity | None:
|
|
45
|
+
min_args = 0
|
|
46
|
+
max_args = 0
|
|
47
|
+
index = 0
|
|
48
|
+
|
|
49
|
+
while index < len(items):
|
|
50
|
+
token = items[index]
|
|
51
|
+
if token == '?':
|
|
52
|
+
try:
|
|
53
|
+
group_end = items.index('?', index + 1)
|
|
54
|
+
except ValueError:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
group_arity = _optional_group_arity(items[index + 1 : group_end])
|
|
58
|
+
if group_arity is None:
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
max_args += group_arity.max_args
|
|
62
|
+
index = group_end + 1
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
token_arity = _signature_token_arity(token, is_last=index == len(items) - 1)
|
|
66
|
+
if token_arity is None:
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
min_args += token_arity.min_args
|
|
70
|
+
if token_arity.max_args is None:
|
|
71
|
+
if index != len(items) - 1:
|
|
72
|
+
return None
|
|
73
|
+
return CommandArity(min_args=min_args, max_args=None)
|
|
74
|
+
|
|
75
|
+
max_args += token_arity.max_args
|
|
76
|
+
index += 1
|
|
77
|
+
|
|
78
|
+
return CommandArity(min_args=min_args, max_args=max_args)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _optional_group_arity(tokens: tuple[str, ...]) -> CommandArity | None:
|
|
82
|
+
if not tokens:
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
max_args = 0
|
|
86
|
+
for token in tokens:
|
|
87
|
+
token_arity = _signature_token_arity(token, is_last=False)
|
|
88
|
+
if token_arity is None or token_arity.max_args is None:
|
|
89
|
+
return None
|
|
90
|
+
max_args += token_arity.max_args
|
|
91
|
+
return CommandArity(min_args=0, max_args=max_args)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _signature_token_arity(token: str, *, is_last: bool) -> CommandArity | None:
|
|
95
|
+
if not token:
|
|
96
|
+
return CommandArity(min_args=0, max_args=0)
|
|
97
|
+
if token.startswith('=') and len(token) > 1:
|
|
98
|
+
return CommandArity(min_args=1, max_args=1)
|
|
99
|
+
if token.startswith('<') and token.endswith('>') and len(token) > 2:
|
|
100
|
+
slot_name = token[1:-1]
|
|
101
|
+
if slot_name in {'selector', 'bodySelector', 'ownerSelector', 'procedureSelector'}:
|
|
102
|
+
# Selectors range from one word (`1`) to five words
|
|
103
|
+
# (`after-options list 1..last step 2`).
|
|
104
|
+
return CommandArity(min_args=1, max_args=5)
|
|
105
|
+
return CommandArity(min_args=1, max_args=1)
|
|
106
|
+
if token == 'args':
|
|
107
|
+
if not is_last:
|
|
108
|
+
return None
|
|
109
|
+
return CommandArity(min_args=0, max_args=None)
|
|
110
|
+
if _is_safe_inline_optional_literal(token):
|
|
111
|
+
return CommandArity(min_args=0, max_args=1)
|
|
112
|
+
if token == '?' or '...' in token or '|' in token or '?' in token:
|
|
113
|
+
return None
|
|
114
|
+
if not _has_internal_whitespace(token):
|
|
115
|
+
return CommandArity(min_args=1, max_args=1)
|
|
116
|
+
|
|
117
|
+
default_arity = _default_like_token_arity(token)
|
|
118
|
+
if default_arity is not None:
|
|
119
|
+
return default_arity
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _proc_parameter_spec(item: ListItem) -> tuple[str, bool] | None:
|
|
124
|
+
if not _has_internal_whitespace(item.text):
|
|
125
|
+
return item.text, False
|
|
126
|
+
|
|
127
|
+
subitems = split_tcl_list(item.text, item.content_start)
|
|
128
|
+
if len(subitems) != 2 or not is_simple_name(subitems[0].text):
|
|
129
|
+
return None
|
|
130
|
+
return subitems[0].text, True
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _default_like_token_arity(token: str) -> CommandArity | None:
|
|
134
|
+
subitems = split_tcl_list(token, _ZERO_POSITION)
|
|
135
|
+
if len(subitems) != 2 or not is_simple_name(subitems[0].text):
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
default_value = subitems[1].text
|
|
139
|
+
if (
|
|
140
|
+
not default_value
|
|
141
|
+
or not is_simple_name(default_value)
|
|
142
|
+
or default_value.isdigit()
|
|
143
|
+
or default_value.startswith('-')
|
|
144
|
+
or default_value in _DEFAULT_LITERAL_KEYWORDS
|
|
145
|
+
):
|
|
146
|
+
return CommandArity(min_args=0, max_args=1)
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _is_safe_inline_optional_literal(token: str) -> bool:
|
|
151
|
+
if len(token) <= 2 or not token.startswith('?') or not token.endswith('?'):
|
|
152
|
+
return False
|
|
153
|
+
inner = token[1:-1]
|
|
154
|
+
return bool(inner) and inner.startswith('-') and '?' not in inner and '...' not in inner
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _has_internal_whitespace(text: str) -> bool:
|
|
158
|
+
return any(char.isspace() for char in text)
|