@px-lsp/server 0.1.0
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.
- package/LICENSE +674 -0
- package/README.md +334 -0
- package/THIRD-PARTY-NOTICES.md +83 -0
- package/data/ck3/dataTypes.json +2195 -0
- package/data/ck3/data_types/data_types_common.txt +2040 -0
- package/data/ck3/data_types/data_types_gui.txt +5264 -0
- package/data/ck3/data_types/data_types_internalclausewitzgui.txt +14843 -0
- package/data/ck3/data_types/data_types_script.txt +4251 -0
- package/data/ck3/data_types/data_types_uncategorized.txt +109984 -0
- package/data/ck3/freqs.json +1 -0
- package/data/ck3/guiSchema.json +6344 -0
- package/data/ck3/script_docs/effects.log +16059 -0
- package/data/ck3/script_docs/event_targets.log +2098 -0
- package/data/ck3/script_docs/modifiers.log +2228 -0
- package/data/ck3/script_docs/on_actions.log +5275 -0
- package/data/ck3/script_docs/triggers.log +11991 -0
- package/data/ck3/structures.json +9743 -0
- package/data/ck3/wikidocs/ATTRIBUTION.md +18 -0
- package/data/ck3/wikidocs/Data_types.md +2568 -0
- package/data/ck3/wikidocs/Effects_list.md +1176 -0
- package/data/ck3/wikidocs/Scopes_list.md +341 -0
- package/data/ck3/wikidocs/Triggers_list.md +1097 -0
- package/data/eu5/data_types/data_types_common.txt +2087 -0
- package/data/eu5/data_types/data_types_gui.txt +6732 -0
- package/data/eu5/data_types/data_types_internalclausewitzgui.txt +19276 -0
- package/data/eu5/data_types/data_types_script.txt +5688 -0
- package/data/eu5/data_types/data_types_uncategorized.txt +135569 -0
- package/data/vic3/data_types/data_types_common.txt +2021 -0
- package/data/vic3/data_types/data_types_gui.txt +5592 -0
- package/data/vic3/data_types/data_types_internalclausewitzgui.txt +17304 -0
- package/data/vic3/data_types/data_types_script.txt +2817 -0
- package/data/vic3/data_types/data_types_uncategorized.txt +84354 -0
- package/data/vic3/freqs.json +1 -0
- package/data/vic3/guiSchema.json +5578 -0
- package/data/vic3/script_docs/effects.log +38135 -0
- package/data/vic3/script_docs/event_targets.log +2028 -0
- package/data/vic3/script_docs/modifiers.log +18954 -0
- package/data/vic3/script_docs/on_actions.log +1561 -0
- package/data/vic3/script_docs/triggers.log +15738 -0
- package/data/vic3/structures.json +10189 -0
- package/dist/server.js +63668 -0
- package/media/px-lsp.svg +12 -0
- package/package.json +50 -0
- package/src/clientMode.ts +60 -0
- package/src/coa/coa.ts +184 -0
- package/src/coa/coaParse.ts +267 -0
- package/src/context.ts +78 -0
- package/src/contextKeywords.ts +224 -0
- package/src/data/dataBindingMacros.ts +82 -0
- package/src/data/dataFnDocs.ts +152 -0
- package/src/data/dataFnUsage.ts +431 -0
- package/src/data/dataTypes.ts +279 -0
- package/src/data/defines.ts +123 -0
- package/src/data/docsParser.ts +453 -0
- package/src/data/keywordDocs.ts +98 -0
- package/src/data/modifierTemplates.ts +143 -0
- package/src/data/textFormatting.ts +165 -0
- package/src/data/wikiDocs.ts +187 -0
- package/src/dds/decoder.ts +1007 -0
- package/src/dds/encode.ts +235 -0
- package/src/dds/index.ts +58 -0
- package/src/dds/png.ts +96 -0
- package/src/dds/tga.ts +62 -0
- package/src/documents.ts +35 -0
- package/src/features/assetPaths.ts +169 -0
- package/src/features/codeActions.ts +148 -0
- package/src/features/colors.ts +244 -0
- package/src/features/completion.ts +961 -0
- package/src/features/datafunction.ts +729 -0
- package/src/features/definition.ts +84 -0
- package/src/features/diagnostics.ts +244 -0
- package/src/features/folding.ts +106 -0
- package/src/features/formatting.ts +60 -0
- package/src/features/guiLanguage.ts +366 -0
- package/src/features/guiNavigation.ts +140 -0
- package/src/features/guiTree.ts +97 -0
- package/src/features/hover.ts +817 -0
- package/src/features/hoverRender.ts +222 -0
- package/src/features/inlayHints.ts +147 -0
- package/src/features/locFormatting.ts +127 -0
- package/src/features/references.ts +70 -0
- package/src/features/rename.ts +135 -0
- package/src/features/scopeAt.ts +65 -0
- package/src/features/semanticTokens.ts +188 -0
- package/src/features/signatureHelp.ts +72 -0
- package/src/features/symbols.ts +241 -0
- package/src/features/textureHover.ts +143 -0
- package/src/features/workspaceSymbols.ts +69 -0
- package/src/games/active.ts +19 -0
- package/src/games/ck3/ambientScopes.ts +273 -0
- package/src/games/ck3/index.ts +38 -0
- package/src/games/ck3/meta.ts +28 -0
- package/src/games/ck3/modifierPlaceholders.ts +61 -0
- package/src/games/ck3/saveSchema.ts +134 -0
- package/src/games/ck3/scaffolds.ts +197 -0
- package/src/games/ck3/schema.ts +422 -0
- package/src/games/ck3/structures.ts +887 -0
- package/src/games/eu5/index.ts +75 -0
- package/src/games/eu5/meta.ts +44 -0
- package/src/games/eu5/scaffolds.ts +49 -0
- package/src/games/eu5/schema.generated.ts +1043 -0
- package/src/games/jomini/variables.ts +134 -0
- package/src/games/profile.ts +205 -0
- package/src/games/registry.ts +27 -0
- package/src/games/vic3/index.ts +52 -0
- package/src/games/vic3/meta.ts +55 -0
- package/src/games/vic3/saveSchema.ts +77 -0
- package/src/games/vic3/scaffolds.ts +135 -0
- package/src/games/vic3/schema.ts +650 -0
- package/src/games/vic3/structures.ts +33 -0
- package/src/gui/anchorSpec.ts +66 -0
- package/src/gui/declMarkers.ts +30 -0
- package/src/gui/fillGeometry.ts +101 -0
- package/src/gui/guiDefs.ts +386 -0
- package/src/gui/guiDependencies.ts +352 -0
- package/src/gui/guiLinks.ts +64 -0
- package/src/gui/layoutEngine.ts +1998 -0
- package/src/gui/layoutService.ts +221 -0
- package/src/gui/measuredMetrics.ts +21 -0
- package/src/gui/previewService.ts +89 -0
- package/src/gui/saveSchema.ts +220 -0
- package/src/gui/saveValues.ts +399 -0
- package/src/gui/saveZip.ts +60 -0
- package/src/gui/sourceEdit.ts +535 -0
- package/src/gui/sourceEditService.ts +439 -0
- package/src/gui/sourceModel.ts +603 -0
- package/src/gui/textResolve.ts +145 -0
- package/src/gui/textureInfo.ts +106 -0
- package/src/gui/vocabulary.ts +149 -0
- package/src/gui/widgetEdit.ts +52 -0
- package/src/gui/widgetInfo.ts +245 -0
- package/src/index/docComments.ts +103 -0
- package/src/index/extract.ts +252 -0
- package/src/index/indexer.ts +369 -0
- package/src/index/intern.ts +101 -0
- package/src/index/lazyRefs.ts +145 -0
- package/src/index/modOrigin.ts +69 -0
- package/src/index/references.ts +534 -0
- package/src/overview/dependencies.ts +240 -0
- package/src/overview/eventBanner.ts +95 -0
- package/src/overview/eventDetail.ts +482 -0
- package/src/overview/eventGraph.ts +617 -0
- package/src/overview/eventVocabulary.ts +214 -0
- package/src/overview/locCoverage.ts +138 -0
- package/src/overview/modOverview.ts +29 -0
- package/src/overview/overrides.ts +89 -0
- package/src/parseCache.ts +81 -0
- package/src/parser/cst.ts +257 -0
- package/src/parser/encoding.ts +106 -0
- package/src/parser/index.ts +7 -0
- package/src/parser/lexer.ts +245 -0
- package/src/parser/locParser.ts +276 -0
- package/src/parser/parser.ts +360 -0
- package/src/schema/freqs.ts +70 -0
- package/src/schema/loader.ts +113 -0
- package/src/schema/types.ts +142 -0
- package/src/scopes/inference.ts +478 -0
- package/src/scopes/model.ts +148 -0
- package/src/scopes/varTypes.ts +290 -0
- package/src/server.ts +1894 -0
- package/src/serverData.ts +98 -0
- package/src/structure.ts +56 -0
- package/src/wordAt.ts +49 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static keyword-to-context table for block-context detection.
|
|
3
|
+
*
|
|
4
|
+
* Extending behavior is a one-line change here; the walking logic in context.ts
|
|
5
|
+
* never needs to be touched. Keywords are matched lowercase.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Blocks whose direct content is written in trigger grammar. */
|
|
9
|
+
export const TRIGGER_BLOCK_KEYWORDS = new Set<string>([
|
|
10
|
+
"trigger",
|
|
11
|
+
"limit",
|
|
12
|
+
"alternative_limit",
|
|
13
|
+
"potential",
|
|
14
|
+
"allow",
|
|
15
|
+
"is_shown",
|
|
16
|
+
"is_valid",
|
|
17
|
+
"is_valid_showing_failures_only",
|
|
18
|
+
"can_start",
|
|
19
|
+
"can_join",
|
|
20
|
+
"can_pick",
|
|
21
|
+
"can_pick_phase",
|
|
22
|
+
"is_highlighted",
|
|
23
|
+
"valid",
|
|
24
|
+
"filter",
|
|
25
|
+
"trigger_if",
|
|
26
|
+
"trigger_else_if",
|
|
27
|
+
"trigger_else",
|
|
28
|
+
"calc_true_if",
|
|
29
|
+
"custom_description", // contains a trigger plus text/subject keys
|
|
30
|
+
"modifier", // mtth/chance modifier blocks contain triggers (+ add/factor)
|
|
31
|
+
"compare_modifier",
|
|
32
|
+
"opinion_modifier",
|
|
33
|
+
"is_visible",
|
|
34
|
+
"is_valid_demand",
|
|
35
|
+
"can_send",
|
|
36
|
+
"can_be_picked",
|
|
37
|
+
"can_be_picked_title",
|
|
38
|
+
"on_invalidated_trigger",
|
|
39
|
+
"cancellation_trigger",
|
|
40
|
+
"hidden_trigger",
|
|
41
|
+
"show_as_tooltip_trigger",
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
/** Blocks whose direct content is written in effect grammar. */
|
|
45
|
+
export const EFFECT_BLOCK_KEYWORDS = new Set<string>([
|
|
46
|
+
"effect",
|
|
47
|
+
"immediate",
|
|
48
|
+
"after",
|
|
49
|
+
"option", // options mix metadata keys with effects; effect is the useful default
|
|
50
|
+
"on_accept",
|
|
51
|
+
"on_decline",
|
|
52
|
+
"on_send",
|
|
53
|
+
"on_start",
|
|
54
|
+
"on_end",
|
|
55
|
+
"on_join",
|
|
56
|
+
"on_leave",
|
|
57
|
+
"on_complete",
|
|
58
|
+
"on_success",
|
|
59
|
+
"on_failure",
|
|
60
|
+
"on_invalidated",
|
|
61
|
+
"on_cancel",
|
|
62
|
+
"on_monthly",
|
|
63
|
+
"on_yearly",
|
|
64
|
+
"on_activate",
|
|
65
|
+
"on_deactivate",
|
|
66
|
+
"then",
|
|
67
|
+
"fallback",
|
|
68
|
+
"hidden_effect",
|
|
69
|
+
"show_as_tooltip",
|
|
70
|
+
"random",
|
|
71
|
+
"random_list",
|
|
72
|
+
"creation_effect",
|
|
73
|
+
"removal_effect",
|
|
74
|
+
"success",
|
|
75
|
+
"abort_effect",
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Blocks whose direct content is script-value math: base/add/factor/modifier
|
|
80
|
+
* keys plus iterators — NOT effects or plain triggers. `modifier` children
|
|
81
|
+
* switch back to trigger grammar via TRIGGER_BLOCK_KEYWORDS.
|
|
82
|
+
*
|
|
83
|
+
* The math instruction keys themselves are included for their BLOCK form
|
|
84
|
+
* (`add = { value = x if = { … } }` inside an effect or trigger): a math key
|
|
85
|
+
* opening a block always contains math, wherever it appears. Scalar forms
|
|
86
|
+
* (`add = 5`) never enter the block stack, so this cannot misfire there.
|
|
87
|
+
*/
|
|
88
|
+
export const VALUE_BLOCK_KEYWORDS = new Set<string>([
|
|
89
|
+
"ai_chance",
|
|
90
|
+
"ai_will_do",
|
|
91
|
+
"weight",
|
|
92
|
+
"weight_multiplier",
|
|
93
|
+
"chance",
|
|
94
|
+
"ai_value",
|
|
95
|
+
"ai_will_revoke_title",
|
|
96
|
+
"join_chance",
|
|
97
|
+
"value",
|
|
98
|
+
"add",
|
|
99
|
+
"subtract",
|
|
100
|
+
"multiply",
|
|
101
|
+
"divide",
|
|
102
|
+
"modulo",
|
|
103
|
+
"min",
|
|
104
|
+
"max",
|
|
105
|
+
"base",
|
|
106
|
+
"factor",
|
|
107
|
+
"fixed_range",
|
|
108
|
+
"integer_range",
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Blocks that keep their parent's context: control flow, boolean operators and
|
|
113
|
+
* scope changes. The context walk skips over these and keeps going up.
|
|
114
|
+
*/
|
|
115
|
+
export const TRANSPARENT_KEYWORDS = new Set<string>([
|
|
116
|
+
"if",
|
|
117
|
+
"else_if",
|
|
118
|
+
"else",
|
|
119
|
+
"while",
|
|
120
|
+
"switch",
|
|
121
|
+
"trigger_switch",
|
|
122
|
+
"and",
|
|
123
|
+
"or",
|
|
124
|
+
"not",
|
|
125
|
+
"nor",
|
|
126
|
+
"nand",
|
|
127
|
+
"all_false",
|
|
128
|
+
"any_false",
|
|
129
|
+
"custom_tooltip",
|
|
130
|
+
"first_valid",
|
|
131
|
+
"random_valid",
|
|
132
|
+
"triggered_desc",
|
|
133
|
+
"desc",
|
|
134
|
+
"root",
|
|
135
|
+
"this",
|
|
136
|
+
"prev",
|
|
137
|
+
"from",
|
|
138
|
+
"liege",
|
|
139
|
+
"mother",
|
|
140
|
+
"father",
|
|
141
|
+
"primary_spouse",
|
|
142
|
+
"primary_title",
|
|
143
|
+
"capital_province",
|
|
144
|
+
"capital_county",
|
|
145
|
+
"faith",
|
|
146
|
+
"culture",
|
|
147
|
+
"dynasty",
|
|
148
|
+
"house",
|
|
149
|
+
"top_liege",
|
|
150
|
+
"court_owner",
|
|
151
|
+
"employer",
|
|
152
|
+
"holder",
|
|
153
|
+
"county",
|
|
154
|
+
"duchy",
|
|
155
|
+
"kingdom",
|
|
156
|
+
"empire",
|
|
157
|
+
"title_province",
|
|
158
|
+
"location",
|
|
159
|
+
"province_owner",
|
|
160
|
+
"barony",
|
|
161
|
+
"barony_controller",
|
|
162
|
+
"county_controller",
|
|
163
|
+
"religion",
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
export type KeywordClass = "trigger" | "effect" | "value" | "transparent" | "unknown";
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* True when the keyword is EXPLICITLY listed in one of the four sets above —
|
|
170
|
+
* i.e. classified by curation rather than by prefix heuristics. Scope inference
|
|
171
|
+
* uses this to divert iterator-shaped non-iterators (random_list, random_valid).
|
|
172
|
+
*/
|
|
173
|
+
export function isExplicitKeyword(rawKeyword: string): boolean {
|
|
174
|
+
const kw = rawKeyword.toLowerCase();
|
|
175
|
+
return (
|
|
176
|
+
TRIGGER_BLOCK_KEYWORDS.has(kw) ||
|
|
177
|
+
EFFECT_BLOCK_KEYWORDS.has(kw) ||
|
|
178
|
+
VALUE_BLOCK_KEYWORDS.has(kw) ||
|
|
179
|
+
TRANSPARENT_KEYWORDS.has(kw)
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Grammar words that can never be the call site of a scripted effect/trigger:
|
|
185
|
+
* the exact keyword sets plus iterator- and prev-shaped keys. Deliberately
|
|
186
|
+
* NARROWER than classifyKeyword's "not unknown" — its naming-convention
|
|
187
|
+
* buckets (X_trigger blocks, on_X blocks) match the names modders give their
|
|
188
|
+
* scripted triggers/effects, and those keys ARE call sites (#3, #5:
|
|
189
|
+
* tribute_mission_1000_can_give_treasury_trigger = yes).
|
|
190
|
+
*/
|
|
191
|
+
export function isStructuralKeyword(rawKeyword: string): boolean {
|
|
192
|
+
const kw = rawKeyword.toLowerCase();
|
|
193
|
+
if (isExplicitKeyword(kw)) return true;
|
|
194
|
+
if (/^(any|every|random|ordered)_/.test(kw)) return true;
|
|
195
|
+
return /^prev+$/.test(kw);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function classifyKeyword(rawKeyword: string): KeywordClass {
|
|
199
|
+
const kw = rawKeyword.toLowerCase();
|
|
200
|
+
if (TRIGGER_BLOCK_KEYWORDS.has(kw)) return "trigger";
|
|
201
|
+
if (EFFECT_BLOCK_KEYWORDS.has(kw)) return "effect";
|
|
202
|
+
if (VALUE_BLOCK_KEYWORDS.has(kw)) return "value";
|
|
203
|
+
if (TRANSPARENT_KEYWORDS.has(kw)) return "transparent";
|
|
204
|
+
// Iterators: any_* blocks are triggers; every_/random_/ordered_ blocks are effects
|
|
205
|
+
// (their `limit` child switches back to trigger and is found first by the walk).
|
|
206
|
+
if (kw.startsWith("any_")) return "trigger";
|
|
207
|
+
if (kw.startsWith("every_") || kw.startsWith("random_") || kw.startsWith("ordered_")) return "effect";
|
|
208
|
+
// Naming conventions the game's own .info docs follow: X_trigger blocks hold
|
|
209
|
+
// triggers (cancellation_trigger, ai_target_quick_trigger…); on_X blocks hold
|
|
210
|
+
// effects (on_auto_accept, on_intermediary_accept, on_blocked_effect…) —
|
|
211
|
+
// except on_action(s), which lists on_action NAMES, not effects.
|
|
212
|
+
if (kw.endsWith("_trigger")) return "trigger";
|
|
213
|
+
if (kw.startsWith("on_") && kw !== "on_action" && kw !== "on_actions") return "effect";
|
|
214
|
+
// Scope changers keep the parent context.
|
|
215
|
+
if (
|
|
216
|
+
kw.startsWith("scope:") ||
|
|
217
|
+
kw.startsWith("var:") ||
|
|
218
|
+
kw.startsWith("local_var:") ||
|
|
219
|
+
kw.startsWith("global_var:")
|
|
220
|
+
)
|
|
221
|
+
return "transparent";
|
|
222
|
+
if (/^prev+$/.test(kw)) return "transparent";
|
|
223
|
+
return "unknown";
|
|
224
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `game/data_binding/*.txt` macros: `macro = { description = "…" definition =
|
|
3
|
+
* "IsZero(Value)" replace_with = "…" }`. These are callable inside `[ … ]`
|
|
4
|
+
* data-function expressions, so they promote into the DataTypesData knowledge
|
|
5
|
+
* as global functions (with their signature args and description).
|
|
6
|
+
*
|
|
7
|
+
* A promotion source only: a macro never overwrites a real dump/wiki global of
|
|
8
|
+
* the same name. Harvested from game (+ mod `data_binding/` if present) at
|
|
9
|
+
* startup. No `vscode` imports.
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from "fs";
|
|
12
|
+
import * as path from "path";
|
|
13
|
+
import { parseScript } from "../parser";
|
|
14
|
+
import { listFiles } from "@px-lsp/protocol/fsWalk";
|
|
15
|
+
import type { DataTypesData } from "./dataTypes";
|
|
16
|
+
|
|
17
|
+
/** Split a `Name(a,b)` signature into its function name and argument names. */
|
|
18
|
+
function parseSignature(definition: string): { name: string; args: string[] } | null {
|
|
19
|
+
const paren = definition.indexOf("(");
|
|
20
|
+
if (paren < 0) {
|
|
21
|
+
const name = definition.trim();
|
|
22
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? { name, args: [] } : null;
|
|
23
|
+
}
|
|
24
|
+
const name = definition.slice(0, paren).trim();
|
|
25
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) return null;
|
|
26
|
+
const close = definition.lastIndexOf(")");
|
|
27
|
+
const argText = definition.slice(paren + 1, close >= 0 ? close : undefined);
|
|
28
|
+
const args = argText
|
|
29
|
+
.split(",")
|
|
30
|
+
.map((a) => a.trim())
|
|
31
|
+
.filter((a) => a.length > 0);
|
|
32
|
+
return { name, args };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Harvest `data_binding/` under each root and add the macros into `into` as
|
|
37
|
+
* global functions (add-if-absent). Returns the number of macros added.
|
|
38
|
+
*/
|
|
39
|
+
export function loadDataBindingMacros(roots: string[], into: DataTypesData): number {
|
|
40
|
+
let added = 0;
|
|
41
|
+
for (const root of roots) {
|
|
42
|
+
for (const file of listFiles(path.join(root, "data_binding"), ".txt").sort()) {
|
|
43
|
+
let text: string;
|
|
44
|
+
try {
|
|
45
|
+
text = fs.readFileSync(file, "utf8").replace(/^/, "");
|
|
46
|
+
} catch {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const { root: parsed } = parseScript(text);
|
|
50
|
+
for (const stmt of parsed.statements) {
|
|
51
|
+
if (stmt.kind !== "assignment" || stmt.key.text.toLowerCase() !== "macro") continue;
|
|
52
|
+
if (stmt.value?.kind !== "block") continue;
|
|
53
|
+
let definition: string | null = null;
|
|
54
|
+
let description = "";
|
|
55
|
+
let replaceWith = "";
|
|
56
|
+
for (const inner of stmt.value.statements) {
|
|
57
|
+
if (inner.kind !== "assignment" || inner.value?.kind !== "scalar") continue;
|
|
58
|
+
const key = inner.key.text.toLowerCase();
|
|
59
|
+
if (key === "definition") definition = inner.value.text;
|
|
60
|
+
else if (key === "description") description = inner.value.text;
|
|
61
|
+
else if (key === "replace_with") replaceWith = inner.value.text;
|
|
62
|
+
}
|
|
63
|
+
if (!definition) continue;
|
|
64
|
+
const sig = parseSignature(definition);
|
|
65
|
+
if (!sig || into.globals.has(sig.name)) continue; // real global wins
|
|
66
|
+
const descParts: string[] = [];
|
|
67
|
+
if (description) descParts.push(description);
|
|
68
|
+
if (replaceWith) descParts.push("Expands to `" + replaceWith + "`.");
|
|
69
|
+
into.globals.set(sig.name, {
|
|
70
|
+
ret: null,
|
|
71
|
+
args: sig.args.length > 0 ? sig.args : null,
|
|
72
|
+
kind: "function",
|
|
73
|
+
src: "macro",
|
|
74
|
+
...(descParts.length > 0 ? { desc: descParts.join("\n\n") } : {}),
|
|
75
|
+
});
|
|
76
|
+
into.count++;
|
|
77
|
+
added++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return added;
|
|
82
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Descriptions for [ ... ] datafunction names. Neither the game dump nor the
|
|
3
|
+
* wiki tables carry prose, so hovers are built from two layers:
|
|
4
|
+
*
|
|
5
|
+
* - CURATED_DOCS: hand-written docs for the small, engine-stable set of
|
|
6
|
+
* utility functions every gui/loc file uses (And, ObjectsEqual, Concat…).
|
|
7
|
+
* Callers only show these for names that exist in the harvested/dump data,
|
|
8
|
+
* so a renamed engine function can never surface a stale doc.
|
|
9
|
+
* - describeDataFn: a deduction from the name's morphology (Get→returns,
|
|
10
|
+
* Is/Has→condition, On→command…), always available, clearly heuristic.
|
|
11
|
+
*
|
|
12
|
+
* No vscode imports: unit-tested in plain Node.
|
|
13
|
+
*/
|
|
14
|
+
import type { DataTypeMember } from "./dataTypes";
|
|
15
|
+
|
|
16
|
+
export const CURATED_DOCS: ReadonlyMap<string, string> = new Map<string, string>([
|
|
17
|
+
// Logic
|
|
18
|
+
["And", "Logical AND of two or more boolean arguments."],
|
|
19
|
+
["Or", "Logical OR of two or more boolean arguments."],
|
|
20
|
+
["Not", "Logical negation of a boolean argument."],
|
|
21
|
+
["ObjectsEqual", "True when both arguments resolve to the same game object (compare with `.Self`)."],
|
|
22
|
+
["IsDataModelEmpty", "True when the given data model (list) has no entries."],
|
|
23
|
+
["GetDataModelSize", "Number of entries in the given data model (list)."],
|
|
24
|
+
// Selection / text
|
|
25
|
+
[
|
|
26
|
+
"SelectLocalization",
|
|
27
|
+
"Picks between two loc keys: `SelectLocalization( bool, key_if_true, key_if_false )`.",
|
|
28
|
+
],
|
|
29
|
+
["Select_CString", "Picks between two strings by a boolean: `Select_CString( bool, if_true, if_false )`."],
|
|
30
|
+
["Concatenate", "Concatenates its string arguments into one string."],
|
|
31
|
+
["Localize", "Looks up a localization key by name and returns its text."],
|
|
32
|
+
["GetHerHis", "Possessive pronoun for the character (her/his). `|U` capitalizes."],
|
|
33
|
+
["GetSheHe", "Subject pronoun for the character (she/he). `|U` capitalizes."],
|
|
34
|
+
["GetHerHim", "Object pronoun for the character (her/him). `|U` capitalizes."],
|
|
35
|
+
[
|
|
36
|
+
"Custom",
|
|
37
|
+
"Runs a customizable localization (common/customizable_localization) on this object: `Custom('key')`.",
|
|
38
|
+
],
|
|
39
|
+
["Custom2", "Customizable localization taking a second scope argument: `Custom2('key', OtherScope)`."],
|
|
40
|
+
// Commands / gui plumbing
|
|
41
|
+
["IsValidCommand", "True when the given gui command is currently allowed (drives enabled states)."],
|
|
42
|
+
["GetCommandDesc", "Tooltip text explaining the given gui command's current state."],
|
|
43
|
+
[
|
|
44
|
+
"GetVariableSystem",
|
|
45
|
+
"The gui-local variable store; chain `.Set/.Toggle/.Exists/.HasValue` for pure-UI state.",
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
"GetNullCharacter",
|
|
49
|
+
"An empty Character reference; used to blank a datacontext or as a comparison target.",
|
|
50
|
+
],
|
|
51
|
+
["EmptyScope", "An empty scope object; used to blank out a context."],
|
|
52
|
+
["GetPlayer", "The local player's character."],
|
|
53
|
+
["GetScriptedGui", "Looks up a scripted_gui by name: chain `.IsShown/.IsValid/.Execute` with a GuiScope."],
|
|
54
|
+
["GuiScope", "Builds a scope bundle for scripted_gui calls: `.SetRoot(...).AddScope('name', ...).End`."],
|
|
55
|
+
[
|
|
56
|
+
"AddScope",
|
|
57
|
+
"Adds a named scope to the bundle: `AddScope( 'name', object )` (read as `scope:name` in script).",
|
|
58
|
+
],
|
|
59
|
+
["SetRoot", "Sets the scripted_gui's root scope in a GuiScope chain."],
|
|
60
|
+
["MakeScope", "Wraps an object as a script scope (for GuiScope chains and scripted_gui calls)."],
|
|
61
|
+
["End", "Finishes a GuiScope builder chain."],
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
/** Arithmetic/compare families are generated, not listed one by one. */
|
|
65
|
+
const TYPED_FAMILY =
|
|
66
|
+
/^(Add|Subtract|Multiply|Divide|Min|Max|EqualTo|NotEqualTo|LessThan|GreaterThan|LessThanOrEqualTo|GreaterThanOrEqualTo|IntTo|FixedPointTo|FloatTo)_?([A-Za-z0-9]+)?$/;
|
|
67
|
+
const FAMILY_DOC: Record<string, string> = {
|
|
68
|
+
Add: "Sum of the two arguments",
|
|
69
|
+
Subtract: "First argument minus the second",
|
|
70
|
+
Multiply: "Product of the two arguments",
|
|
71
|
+
Divide: "First argument divided by the second",
|
|
72
|
+
Min: "Smaller of the two arguments",
|
|
73
|
+
Max: "Larger of the two arguments",
|
|
74
|
+
EqualTo: "True when the arguments are equal",
|
|
75
|
+
NotEqualTo: "True when the arguments differ",
|
|
76
|
+
LessThan: "True when the first argument is smaller",
|
|
77
|
+
GreaterThan: "True when the first argument is larger",
|
|
78
|
+
LessThanOrEqualTo: "True when the first argument is smaller or equal",
|
|
79
|
+
GreaterThanOrEqualTo: "True when the first argument is larger or equal",
|
|
80
|
+
IntTo: "Converts an integer",
|
|
81
|
+
FixedPointTo: "Converts a fixed-point number",
|
|
82
|
+
FloatTo: "Converts a float",
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** "GetHouseAspiration" → ["House", "Aspiration"]; tolerates ALL_CAPS and digits. */
|
|
86
|
+
function splitWords(name: string): string[] {
|
|
87
|
+
return name
|
|
88
|
+
.replace(/_/g, " ")
|
|
89
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
90
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
|
|
91
|
+
.split(/\s+/)
|
|
92
|
+
.filter((w) => w.length > 0);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function lowerPhrase(words: string[]): string {
|
|
96
|
+
return words.map((w) => (/^[A-Z0-9]+$/.test(w) && w.length > 1 ? w : w.toLowerCase())).join(" ");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Curated doc when available, else a description deduced from the name.
|
|
101
|
+
* `member` sharpens the wording (promote vs function, return type) when known.
|
|
102
|
+
*/
|
|
103
|
+
export function describeDataFn(name: string, member: DataTypeMember | null): string | null {
|
|
104
|
+
const curated = CURATED_DOCS.get(name);
|
|
105
|
+
if (curated) return curated;
|
|
106
|
+
|
|
107
|
+
const family = TYPED_FAMILY.exec(name);
|
|
108
|
+
if (family && FAMILY_DOC[family[1]]) {
|
|
109
|
+
const suffix = family[2] ? ` (${family[2]})` : "";
|
|
110
|
+
return `${FAMILY_DOC[family[1]]}${suffix}.`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (/^[A-Z0-9_]+$/.test(name) && name.length > 2) {
|
|
114
|
+
return "Context promote: available where the game (event, interaction, gui datacontext…) binds this scope.";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const words = splitWords(name);
|
|
118
|
+
if (words.length < 2) return null;
|
|
119
|
+
const head = words[0];
|
|
120
|
+
const rest = lowerPhrase(words.slice(1));
|
|
121
|
+
switch (head) {
|
|
122
|
+
case "Get":
|
|
123
|
+
return `Returns the ${rest}${member?.ret ? "" : " (deduced from the name)"}.`;
|
|
124
|
+
case "Is":
|
|
125
|
+
case "Are":
|
|
126
|
+
case "Was":
|
|
127
|
+
case "Has":
|
|
128
|
+
case "Have":
|
|
129
|
+
case "Can":
|
|
130
|
+
case "Should":
|
|
131
|
+
case "Will":
|
|
132
|
+
return `Whether ${head.toLowerCase()} ${rest} (boolean, deduced from the name).`;
|
|
133
|
+
case "On":
|
|
134
|
+
return `Command: runs when triggered (button click, …) — ${rest}.`;
|
|
135
|
+
case "Set":
|
|
136
|
+
case "Toggle":
|
|
137
|
+
case "Make":
|
|
138
|
+
case "Add":
|
|
139
|
+
case "Remove":
|
|
140
|
+
case "Clear":
|
|
141
|
+
case "Open":
|
|
142
|
+
case "Close":
|
|
143
|
+
case "Show":
|
|
144
|
+
case "Hide":
|
|
145
|
+
case "Select":
|
|
146
|
+
return `Command: ${head.toLowerCase()} ${rest}.`;
|
|
147
|
+
case "Format":
|
|
148
|
+
return `Formats ${rest} as text.`;
|
|
149
|
+
default:
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|