@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,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema loading: the active game profile's bundled schema table merged with an
|
|
3
|
+
* optional per-workspace overlay at `<mod>/<configDir>/schema.json`, so
|
|
4
|
+
* total-conversion frameworks can teach the extension their own folders
|
|
5
|
+
* without a release.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { activeProfile } from "../games/active";
|
|
10
|
+
import type { GameProfile } from "../games/profile";
|
|
11
|
+
import type { AmbientScope, SchemaEntry, KeySpec, RefField, SchemaOverlay } from "./types";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Per-kind structure/ambient lookup precomputed at schema load (v1.1 §B2/§B3),
|
|
15
|
+
* so completion and hover do no per-request scans (perf budget ~1-2 ms).
|
|
16
|
+
*/
|
|
17
|
+
export interface StructureIndex {
|
|
18
|
+
/** kind -> block name ("" = top level) -> KeySpec, for key/doc lookup. */
|
|
19
|
+
keysByKindBlock: Map<string, Map<string, Map<string, KeySpec>>>;
|
|
20
|
+
/** kind -> ambient scope name -> AmbientScope. */
|
|
21
|
+
ambientByKind: Map<string, Map<string, AmbientScope>>;
|
|
22
|
+
/** kind -> provenance label for hover ("character_interactions"). */
|
|
23
|
+
source(kind: string): string | undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface SchemaData {
|
|
27
|
+
entries: SchemaEntry[];
|
|
28
|
+
/** key -> field spec (merged). */
|
|
29
|
+
refFields: Map<string, RefField>;
|
|
30
|
+
/** value prefix -> candidate kinds. */
|
|
31
|
+
prefixRefs: Record<string, string[]>;
|
|
32
|
+
/** Precomputed structure/ambient lookup (v1.1). */
|
|
33
|
+
structures: StructureIndex;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function buildStructureIndex(profile: GameProfile, entries: SchemaEntry[]): StructureIndex {
|
|
37
|
+
const keysByKindBlock = new Map<string, Map<string, Map<string, KeySpec>>>();
|
|
38
|
+
const ambientByKind = new Map<string, Map<string, AmbientScope>>();
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
if (entry.structure) {
|
|
41
|
+
const byBlock = new Map<string, Map<string, KeySpec>>();
|
|
42
|
+
const top = new Map<string, KeySpec>();
|
|
43
|
+
for (const spec of entry.structure.topLevel) top.set(spec.key, spec);
|
|
44
|
+
byBlock.set("", top);
|
|
45
|
+
for (const [name, specs] of Object.entries(entry.structure.blocks ?? {})) {
|
|
46
|
+
const m = new Map<string, KeySpec>();
|
|
47
|
+
for (const spec of specs) m.set(spec.key, spec);
|
|
48
|
+
byBlock.set(name, m);
|
|
49
|
+
}
|
|
50
|
+
keysByKindBlock.set(entry.kind, byBlock);
|
|
51
|
+
}
|
|
52
|
+
if (entry.ambientScopes) {
|
|
53
|
+
const m = new Map<string, AmbientScope>();
|
|
54
|
+
for (const a of entry.ambientScopes) m.set(a.name, a);
|
|
55
|
+
ambientByKind.set(entry.kind, m);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
keysByKindBlock,
|
|
60
|
+
ambientByKind,
|
|
61
|
+
source: (kind) => profile.structureSources[kind],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function loadSchema(modPath: string | string[] | null, log?: (msg: string) => void): SchemaData {
|
|
66
|
+
const profile = activeProfile();
|
|
67
|
+
const entries = [...profile.schema];
|
|
68
|
+
const refFields = new Map<string, RefField>();
|
|
69
|
+
for (const f of profile.refFields) refFields.set(f.key, f);
|
|
70
|
+
const prefixRefs: Record<string, string[]> = { ...profile.prefixRefs };
|
|
71
|
+
|
|
72
|
+
// Multi-mod workspaces: every workspace mod may carry an overlay; later
|
|
73
|
+
// roots win on collisions (roots are passed in load order, mod-of-record
|
|
74
|
+
// first, collisions are rare and per-path).
|
|
75
|
+
const roots = modPath === null ? [] : Array.isArray(modPath) ? modPath : [modPath];
|
|
76
|
+
for (const root of roots) {
|
|
77
|
+
const overlayFile = path.join(root, profile.configDirName, "schema.json");
|
|
78
|
+
try {
|
|
79
|
+
if (!fs.existsSync(overlayFile)) continue;
|
|
80
|
+
const overlay = JSON.parse(fs.readFileSync(overlayFile, "utf8")) as SchemaOverlay;
|
|
81
|
+
for (const e of overlay.entries ?? []) {
|
|
82
|
+
if (typeof e?.path !== "string" || typeof e?.kind !== "string") continue;
|
|
83
|
+
// Overlay entries replace bundled ones with the same path.
|
|
84
|
+
const i = entries.findIndex((x) => x.path === e.path);
|
|
85
|
+
if (i >= 0) entries[i] = e;
|
|
86
|
+
else entries.push(e);
|
|
87
|
+
}
|
|
88
|
+
for (const f of overlay.refFields ?? []) {
|
|
89
|
+
if (typeof f?.key !== "string" || !Array.isArray(f?.kinds)) continue;
|
|
90
|
+
refFields.set(f.key, f);
|
|
91
|
+
}
|
|
92
|
+
for (const [prefix, kinds] of Object.entries(overlay.prefixRefs ?? {})) {
|
|
93
|
+
if (Array.isArray(kinds)) prefixRefs[prefix] = kinds;
|
|
94
|
+
}
|
|
95
|
+
log?.(`schema overlay loaded from ${overlayFile}`);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
log?.(`schema overlay ignored (${overlayFile}): ${String(err)}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Profile-level structure layer (a fully harvested one, as opposed to a schema
|
|
102
|
+
// table that already carries curated `structure` on its entries). Applied last
|
|
103
|
+
// so workspace-overlay folders of a known kind get it too; an entry that
|
|
104
|
+
// already declares its own structure keeps it.
|
|
105
|
+
if (profile.structures) {
|
|
106
|
+
for (let i = 0; i < entries.length; i++) {
|
|
107
|
+
const structure = profile.structures[entries[i].kind];
|
|
108
|
+
if (structure && !entries[i].structure) entries[i] = { ...entries[i], structure };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { entries, refFields, prefixRefs, structures: buildStructureIndex(profile, entries) };
|
|
113
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The game type schema (rework plan AD-3): a *small*, declarative,
|
|
3
|
+
* community-editable table describing what lives in each game folder, how
|
|
4
|
+
* definitions are named, which loc keys a type requires, what scope its
|
|
5
|
+
* script blocks run in, and which assignment keys cross-reference other
|
|
6
|
+
* definitions.
|
|
7
|
+
*
|
|
8
|
+
* This is deliberately NOT a validation-rule language (that was CWTools'
|
|
9
|
+
* mistake); deep semantic validation is the tiger validator's job. The schema feeds
|
|
10
|
+
* navigation, completion, hover, references, rename, coverage and (very
|
|
11
|
+
* conservative) structural diagnostics.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** How definition names are extracted from files in a folder. */
|
|
15
|
+
export type NameExtraction =
|
|
16
|
+
/** One definition per top-level assignment key (`my_thing = { ... }`). */
|
|
17
|
+
| "top-level-key"
|
|
18
|
+
/** Event files: only `namespace.NNN` top-level keys are definitions. */
|
|
19
|
+
| "event-id"
|
|
20
|
+
/** Landed titles: keys matching /^[ekdcb]_/ at any nesting depth. */
|
|
21
|
+
| "nested-title"
|
|
22
|
+
/** GUI files: `type X = base { ... }` and `template X { ... }` statements. */
|
|
23
|
+
| "gui-type"
|
|
24
|
+
/** Localization yml entries. */
|
|
25
|
+
| "loc-key";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* One documented key inside a definition's body or a named sub-block (v1.1 §B2).
|
|
29
|
+
* `values` is a coarse value hint ("enum:a|b|c" for enumerations); `freq` is the
|
|
30
|
+
* per-context usage count used for ranking (Workstream C).
|
|
31
|
+
*/
|
|
32
|
+
export interface KeySpec {
|
|
33
|
+
key: string;
|
|
34
|
+
doc?: string;
|
|
35
|
+
values?: "loc" | "bool" | "block" | `enum:${string}`;
|
|
36
|
+
freq?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Root scope of the block this key opens, when the game's `_*.info` doc
|
|
39
|
+
* declares one (`# root = the activity` → "activity"). Scope inference sets
|
|
40
|
+
* the current scope to this when walking through the key.
|
|
41
|
+
*/
|
|
42
|
+
scope?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Hand-curated entry (structures.ts): its position in the curated list is
|
|
45
|
+
* deliberate and outranks any harvested key. Harvested `.info` freqs count
|
|
46
|
+
* usage at ANY depth in the folder, so re-sorting curated top-level keys by
|
|
47
|
+
* them lets option-level keys (name, modifier…) bury the real top-level
|
|
48
|
+
* vocabulary, the completion regression rank-eval caught in 2026-07.
|
|
49
|
+
*/
|
|
50
|
+
curated?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The document shape of a definition kind: top-level keys plus named sub-blocks. */
|
|
54
|
+
export interface StructureSpec {
|
|
55
|
+
topLevel: KeySpec[];
|
|
56
|
+
/** Named sub-blocks (option, send_option, cost…) with their own keys. */
|
|
57
|
+
blocks?: Record<string, KeySpec[]>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* How one definition kind declares the root scope of its own script blocks
|
|
62
|
+
* (scopes/inference.ts). Games disagree on both the key and the vocabulary: one
|
|
63
|
+
* writes `scope = character` inside an event, another writes `type = X_event`.
|
|
64
|
+
* That is why this table lives on the game profile and not in the engine,
|
|
65
|
+
* assuming one game's spelling everywhere puts every event of the other game in
|
|
66
|
+
* the wrong root scope, which demotes every correct effect to "other scope" and
|
|
67
|
+
* sinks it to the bottom of completion.
|
|
68
|
+
*/
|
|
69
|
+
export interface DefRootKey {
|
|
70
|
+
/** Key inside the definition body that names the root scope. */
|
|
71
|
+
key: string;
|
|
72
|
+
/** Scope when the key is absent. Omit = fall back to the schema's rootScopes. */
|
|
73
|
+
default?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Declared value → scope name, for games that do not spell the value as the
|
|
76
|
+
* scope (`country_event` → country). Absent = the value IS the scope name.
|
|
77
|
+
* A value the map does not list falls back to `default`.
|
|
78
|
+
*/
|
|
79
|
+
values?: Record<string, string>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** An engine-provided saved scope available in a kind's script blocks (v1.1 §B3). */
|
|
83
|
+
export interface AmbientScope {
|
|
84
|
+
name: string;
|
|
85
|
+
type: string;
|
|
86
|
+
doc: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface SchemaEntry {
|
|
90
|
+
/** Folder relative to the game/mod root, forward slashes, no trailing slash. */
|
|
91
|
+
path: string;
|
|
92
|
+
/** Definition kind, singular snake_case (e.g. "trait", "decision"). */
|
|
93
|
+
kind: string;
|
|
94
|
+
/** File extension, default ".txt". */
|
|
95
|
+
ext?: string;
|
|
96
|
+
/** Name extraction mode, default "top-level-key". */
|
|
97
|
+
extraction?: NameExtraction;
|
|
98
|
+
/**
|
|
99
|
+
* Loc keys the game requires per definition; `$` is the definition name
|
|
100
|
+
* (e.g. "trait_$", "$_desc"). Used for conservative missing-loc diagnostics
|
|
101
|
+
* and loc coverage, only include patterns that ≥95% of vanilla definitions
|
|
102
|
+
* of this kind actually define.
|
|
103
|
+
*/
|
|
104
|
+
requiredLoc?: string[];
|
|
105
|
+
/** Scope(s) a definition of this type pushes as root in its script blocks (Phase 3). */
|
|
106
|
+
rootScopes?: string[];
|
|
107
|
+
/** Include definitions of this kind in completion lists (default true).
|
|
108
|
+
* False for huge/noisy kinds (history characters, provinces). */
|
|
109
|
+
completable?: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Block-local structural keys for this kind (v1.1 §B2). Sourced from the game's
|
|
112
|
+
* `_*.info` files. Static, not harvested at runtime. Not yet overlayable (F5).
|
|
113
|
+
*/
|
|
114
|
+
structure?: StructureSpec;
|
|
115
|
+
/** Engine-provided saved scopes for this kind (v1.1 §B3). Not yet overlayable (F5). */
|
|
116
|
+
ambientScopes?: AmbientScope[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Form a cross-reference field takes. */
|
|
120
|
+
export type RefFieldForm =
|
|
121
|
+
/** `key = name` */
|
|
122
|
+
| "scalar"
|
|
123
|
+
/** `key = { name_a name_b ... }` */
|
|
124
|
+
| "list"
|
|
125
|
+
/** either of the above */
|
|
126
|
+
| "both";
|
|
127
|
+
|
|
128
|
+
/** An assignment key whose value references definitions of the given kinds. */
|
|
129
|
+
export interface RefField {
|
|
130
|
+
key: string;
|
|
131
|
+
kinds: string[];
|
|
132
|
+
form?: RefFieldForm; // default "scalar"
|
|
133
|
+
/** List also accepts weighted entries (`<number> = name`), like random_events. */
|
|
134
|
+
weighted?: boolean;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** JSON shape of the optional workspace overlay at <configDir>/schema.json. */
|
|
138
|
+
export interface SchemaOverlay {
|
|
139
|
+
entries?: SchemaEntry[];
|
|
140
|
+
refFields?: RefField[];
|
|
141
|
+
prefixRefs?: Record<string, string[]>;
|
|
142
|
+
}
|