@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.
Files changed (163) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +334 -0
  3. package/THIRD-PARTY-NOTICES.md +83 -0
  4. package/data/ck3/dataTypes.json +2195 -0
  5. package/data/ck3/data_types/data_types_common.txt +2040 -0
  6. package/data/ck3/data_types/data_types_gui.txt +5264 -0
  7. package/data/ck3/data_types/data_types_internalclausewitzgui.txt +14843 -0
  8. package/data/ck3/data_types/data_types_script.txt +4251 -0
  9. package/data/ck3/data_types/data_types_uncategorized.txt +109984 -0
  10. package/data/ck3/freqs.json +1 -0
  11. package/data/ck3/guiSchema.json +6344 -0
  12. package/data/ck3/script_docs/effects.log +16059 -0
  13. package/data/ck3/script_docs/event_targets.log +2098 -0
  14. package/data/ck3/script_docs/modifiers.log +2228 -0
  15. package/data/ck3/script_docs/on_actions.log +5275 -0
  16. package/data/ck3/script_docs/triggers.log +11991 -0
  17. package/data/ck3/structures.json +9743 -0
  18. package/data/ck3/wikidocs/ATTRIBUTION.md +18 -0
  19. package/data/ck3/wikidocs/Data_types.md +2568 -0
  20. package/data/ck3/wikidocs/Effects_list.md +1176 -0
  21. package/data/ck3/wikidocs/Scopes_list.md +341 -0
  22. package/data/ck3/wikidocs/Triggers_list.md +1097 -0
  23. package/data/eu5/data_types/data_types_common.txt +2087 -0
  24. package/data/eu5/data_types/data_types_gui.txt +6732 -0
  25. package/data/eu5/data_types/data_types_internalclausewitzgui.txt +19276 -0
  26. package/data/eu5/data_types/data_types_script.txt +5688 -0
  27. package/data/eu5/data_types/data_types_uncategorized.txt +135569 -0
  28. package/data/vic3/data_types/data_types_common.txt +2021 -0
  29. package/data/vic3/data_types/data_types_gui.txt +5592 -0
  30. package/data/vic3/data_types/data_types_internalclausewitzgui.txt +17304 -0
  31. package/data/vic3/data_types/data_types_script.txt +2817 -0
  32. package/data/vic3/data_types/data_types_uncategorized.txt +84354 -0
  33. package/data/vic3/freqs.json +1 -0
  34. package/data/vic3/guiSchema.json +5578 -0
  35. package/data/vic3/script_docs/effects.log +38135 -0
  36. package/data/vic3/script_docs/event_targets.log +2028 -0
  37. package/data/vic3/script_docs/modifiers.log +18954 -0
  38. package/data/vic3/script_docs/on_actions.log +1561 -0
  39. package/data/vic3/script_docs/triggers.log +15738 -0
  40. package/data/vic3/structures.json +10189 -0
  41. package/dist/server.js +63668 -0
  42. package/media/px-lsp.svg +12 -0
  43. package/package.json +50 -0
  44. package/src/clientMode.ts +60 -0
  45. package/src/coa/coa.ts +184 -0
  46. package/src/coa/coaParse.ts +267 -0
  47. package/src/context.ts +78 -0
  48. package/src/contextKeywords.ts +224 -0
  49. package/src/data/dataBindingMacros.ts +82 -0
  50. package/src/data/dataFnDocs.ts +152 -0
  51. package/src/data/dataFnUsage.ts +431 -0
  52. package/src/data/dataTypes.ts +279 -0
  53. package/src/data/defines.ts +123 -0
  54. package/src/data/docsParser.ts +453 -0
  55. package/src/data/keywordDocs.ts +98 -0
  56. package/src/data/modifierTemplates.ts +143 -0
  57. package/src/data/textFormatting.ts +165 -0
  58. package/src/data/wikiDocs.ts +187 -0
  59. package/src/dds/decoder.ts +1007 -0
  60. package/src/dds/encode.ts +235 -0
  61. package/src/dds/index.ts +58 -0
  62. package/src/dds/png.ts +96 -0
  63. package/src/dds/tga.ts +62 -0
  64. package/src/documents.ts +35 -0
  65. package/src/features/assetPaths.ts +169 -0
  66. package/src/features/codeActions.ts +148 -0
  67. package/src/features/colors.ts +244 -0
  68. package/src/features/completion.ts +961 -0
  69. package/src/features/datafunction.ts +729 -0
  70. package/src/features/definition.ts +84 -0
  71. package/src/features/diagnostics.ts +244 -0
  72. package/src/features/folding.ts +106 -0
  73. package/src/features/formatting.ts +60 -0
  74. package/src/features/guiLanguage.ts +366 -0
  75. package/src/features/guiNavigation.ts +140 -0
  76. package/src/features/guiTree.ts +97 -0
  77. package/src/features/hover.ts +817 -0
  78. package/src/features/hoverRender.ts +222 -0
  79. package/src/features/inlayHints.ts +147 -0
  80. package/src/features/locFormatting.ts +127 -0
  81. package/src/features/references.ts +70 -0
  82. package/src/features/rename.ts +135 -0
  83. package/src/features/scopeAt.ts +65 -0
  84. package/src/features/semanticTokens.ts +188 -0
  85. package/src/features/signatureHelp.ts +72 -0
  86. package/src/features/symbols.ts +241 -0
  87. package/src/features/textureHover.ts +143 -0
  88. package/src/features/workspaceSymbols.ts +69 -0
  89. package/src/games/active.ts +19 -0
  90. package/src/games/ck3/ambientScopes.ts +273 -0
  91. package/src/games/ck3/index.ts +38 -0
  92. package/src/games/ck3/meta.ts +28 -0
  93. package/src/games/ck3/modifierPlaceholders.ts +61 -0
  94. package/src/games/ck3/saveSchema.ts +134 -0
  95. package/src/games/ck3/scaffolds.ts +197 -0
  96. package/src/games/ck3/schema.ts +422 -0
  97. package/src/games/ck3/structures.ts +887 -0
  98. package/src/games/eu5/index.ts +75 -0
  99. package/src/games/eu5/meta.ts +44 -0
  100. package/src/games/eu5/scaffolds.ts +49 -0
  101. package/src/games/eu5/schema.generated.ts +1043 -0
  102. package/src/games/jomini/variables.ts +134 -0
  103. package/src/games/profile.ts +205 -0
  104. package/src/games/registry.ts +27 -0
  105. package/src/games/vic3/index.ts +52 -0
  106. package/src/games/vic3/meta.ts +55 -0
  107. package/src/games/vic3/saveSchema.ts +77 -0
  108. package/src/games/vic3/scaffolds.ts +135 -0
  109. package/src/games/vic3/schema.ts +650 -0
  110. package/src/games/vic3/structures.ts +33 -0
  111. package/src/gui/anchorSpec.ts +66 -0
  112. package/src/gui/declMarkers.ts +30 -0
  113. package/src/gui/fillGeometry.ts +101 -0
  114. package/src/gui/guiDefs.ts +386 -0
  115. package/src/gui/guiDependencies.ts +352 -0
  116. package/src/gui/guiLinks.ts +64 -0
  117. package/src/gui/layoutEngine.ts +1998 -0
  118. package/src/gui/layoutService.ts +221 -0
  119. package/src/gui/measuredMetrics.ts +21 -0
  120. package/src/gui/previewService.ts +89 -0
  121. package/src/gui/saveSchema.ts +220 -0
  122. package/src/gui/saveValues.ts +399 -0
  123. package/src/gui/saveZip.ts +60 -0
  124. package/src/gui/sourceEdit.ts +535 -0
  125. package/src/gui/sourceEditService.ts +439 -0
  126. package/src/gui/sourceModel.ts +603 -0
  127. package/src/gui/textResolve.ts +145 -0
  128. package/src/gui/textureInfo.ts +106 -0
  129. package/src/gui/vocabulary.ts +149 -0
  130. package/src/gui/widgetEdit.ts +52 -0
  131. package/src/gui/widgetInfo.ts +245 -0
  132. package/src/index/docComments.ts +103 -0
  133. package/src/index/extract.ts +252 -0
  134. package/src/index/indexer.ts +369 -0
  135. package/src/index/intern.ts +101 -0
  136. package/src/index/lazyRefs.ts +145 -0
  137. package/src/index/modOrigin.ts +69 -0
  138. package/src/index/references.ts +534 -0
  139. package/src/overview/dependencies.ts +240 -0
  140. package/src/overview/eventBanner.ts +95 -0
  141. package/src/overview/eventDetail.ts +482 -0
  142. package/src/overview/eventGraph.ts +617 -0
  143. package/src/overview/eventVocabulary.ts +214 -0
  144. package/src/overview/locCoverage.ts +138 -0
  145. package/src/overview/modOverview.ts +29 -0
  146. package/src/overview/overrides.ts +89 -0
  147. package/src/parseCache.ts +81 -0
  148. package/src/parser/cst.ts +257 -0
  149. package/src/parser/encoding.ts +106 -0
  150. package/src/parser/index.ts +7 -0
  151. package/src/parser/lexer.ts +245 -0
  152. package/src/parser/locParser.ts +276 -0
  153. package/src/parser/parser.ts +360 -0
  154. package/src/schema/freqs.ts +70 -0
  155. package/src/schema/loader.ts +113 -0
  156. package/src/schema/types.ts +142 -0
  157. package/src/scopes/inference.ts +478 -0
  158. package/src/scopes/model.ts +148 -0
  159. package/src/scopes/varTypes.ts +290 -0
  160. package/src/server.ts +1894 -0
  161. package/src/serverData.ts +98 -0
  162. package/src/structure.ts +56 -0
  163. package/src/wordAt.ts +49 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Variable/flag/list vocabulary of the Jomini script engine, shared by every
3
+ * Jomini game (same `set_variable` / `add_to_variable_list` / flag effects in
4
+ * all of them). Consumed by reference extraction, completion, hover and
5
+ * semantic tokens; game profiles spread {@link JOMINI_VARIABLE_BLOCK_REFS}
6
+ * into their own block-ref tables.
7
+ */
8
+
9
+ /**
10
+ * Variable vocabulary shared by reference extraction (server) and completion.
11
+ * `var:` reads what set_variable wrote on the current scope object,
12
+ * `local_var:` / `global_var:` the other storage classes. Lists live in the
13
+ * same storage (has_variable is true for a list) — see references.ts.
14
+ */
15
+ export const VARIABLE_SET_KINDS: Record<string, string> = {
16
+ set_variable: "variable",
17
+ change_variable: "variable",
18
+ set_local_variable: "local_variable",
19
+ change_local_variable: "local_variable",
20
+ set_global_variable: "global_variable",
21
+ change_global_variable: "global_variable",
22
+ };
23
+ export const VARIABLE_LIST_SET_KINDS: Record<string, string> = {
24
+ add_to_variable_list: "variable_list",
25
+ add_to_local_variable_list: "local_variable_list",
26
+ add_to_global_variable_list: "global_variable_list",
27
+ };
28
+ /** Effects/triggers that READ a variable by name (scalar or `{ name = X }`). */
29
+ export const VARIABLE_READ_KINDS: Record<string, string> = {
30
+ has_variable: "variable",
31
+ remove_variable: "variable",
32
+ clamp_variable: "variable",
33
+ round_variable: "variable",
34
+ has_local_variable: "local_variable",
35
+ remove_local_variable: "local_variable",
36
+ clamp_local_variable: "local_variable",
37
+ round_local_variable: "local_variable",
38
+ has_global_variable: "global_variable",
39
+ remove_global_variable: "global_variable",
40
+ clamp_global_variable: "global_variable",
41
+ round_global_variable: "global_variable",
42
+ has_variable_list: "variable_list",
43
+ clear_variable_list: "variable_list",
44
+ variable_list_size: "variable_list",
45
+ is_target_in_variable_list: "variable_list",
46
+ remove_list_variable: "variable_list",
47
+ has_local_variable_list: "local_variable_list",
48
+ clear_local_variable_list: "local_variable_list",
49
+ local_variable_list_size: "local_variable_list",
50
+ is_target_in_local_variable_list: "local_variable_list",
51
+ remove_list_local_variable: "local_variable_list",
52
+ has_global_variable_list: "global_variable_list",
53
+ clear_global_variable_list: "global_variable_list",
54
+ global_variable_list_size: "global_variable_list",
55
+ is_target_in_global_variable_list: "global_variable_list",
56
+ remove_list_global_variable: "global_variable_list",
57
+ };
58
+ /** `var:x` → candidate definition kinds (scalar first, list second). */
59
+ export const VAR_PREFIX_KINDS: Record<string, string[]> = {
60
+ var: ["variable", "variable_list"],
61
+ local_var: ["local_variable", "local_variable_list"],
62
+ global_var: ["global_variable", "global_variable_list"],
63
+ };
64
+ /** All variable definition kinds (index/completion registration). */
65
+ export const VARIABLE_KINDS = [
66
+ "variable",
67
+ "local_variable",
68
+ "global_variable",
69
+ "variable_list",
70
+ "local_variable_list",
71
+ "global_variable_list",
72
+ ];
73
+
74
+ /**
75
+ * Block-local ref fields for the variable ops: in-list iterators
76
+ * (`every_in_list = { variable = X }`) and the block forms of the
77
+ * change/clamp/round/membership effects. Spread into each profile's
78
+ * blockRefFields table.
79
+ */
80
+ export const JOMINI_VARIABLE_BLOCK_REFS: Record<string, Record<string, string[]>> = {
81
+ // Variable list iterators: `variable = X` names a variable list of the
82
+ // matching storage class; `list = X` names an add_to_list-style ad-hoc list.
83
+ ...inListIteratorRefs(),
84
+ // Block-form variable ops: `name = X` references an existing variable.
85
+ is_target_in_variable_list: { name: ["variable_list"] },
86
+ remove_list_variable: { name: ["variable_list"] },
87
+ variable_list_size: { name: ["variable_list"] },
88
+ is_target_in_local_variable_list: { name: ["local_variable_list"] },
89
+ remove_list_local_variable: { name: ["local_variable_list"] },
90
+ local_variable_list_size: { name: ["local_variable_list"] },
91
+ is_target_in_global_variable_list: { name: ["global_variable_list"] },
92
+ remove_list_global_variable: { name: ["global_variable_list"] },
93
+ global_variable_list_size: { name: ["global_variable_list"] },
94
+ change_variable: { name: ["variable"] },
95
+ clamp_variable: { name: ["variable"] },
96
+ round_variable: { name: ["variable"] },
97
+ change_local_variable: { name: ["local_variable"] },
98
+ clamp_local_variable: { name: ["local_variable"] },
99
+ round_local_variable: { name: ["local_variable"] },
100
+ change_global_variable: { name: ["global_variable"] },
101
+ clamp_global_variable: { name: ["global_variable"] },
102
+ round_global_variable: { name: ["global_variable"] },
103
+ };
104
+
105
+ function inListIteratorRefs(): Record<string, Record<string, string[]>> {
106
+ const out: Record<string, Record<string, string[]>> = {};
107
+ for (const prefix of ["every", "any", "random", "ordered"]) {
108
+ out[`${prefix}_in_list`] = { variable: ["variable_list"], list: ["list"] };
109
+ out[`${prefix}_in_local_list`] = { variable: ["local_variable_list"], list: ["list"] };
110
+ out[`${prefix}_in_global_list`] = { variable: ["global_variable_list"], list: ["list"] };
111
+ }
112
+ return out;
113
+ }
114
+
115
+ const FLAG_REF_KEY = /^(?:has|remove)_[a-z_]*flag$/;
116
+ const LIST_REF_KEYS = new Set(["is_in_list", "is_target_in_list", "remove_from_list", "list"]);
117
+
118
+ /**
119
+ * Ref kinds for key families too open-ended to enumerate in a profile's
120
+ * refFields: per-scope flag triggers/effects (`has_character_flag`,
121
+ * `remove_house_flag`, … → flags declared at `add_*_flag` sites) and list
122
+ * membership (`is_in_list`, the `list =` key of in-list iterators → names
123
+ * declared at `add_to_list`).
124
+ */
125
+ export function dynamicRefKinds(key: string): string[] | null {
126
+ if (FLAG_REF_KEY.test(key)) return ["flag"];
127
+ if (LIST_REF_KEYS.has(key)) return ["list"];
128
+ const varKind = VARIABLE_READ_KINDS[key];
129
+ if (varKind) {
130
+ // Scalar reads accept lists too (has_variable is true for a list variable).
131
+ return varKind.endsWith("_list") ? [varKind] : [varKind, `${varKind}_list`];
132
+ }
133
+ return null;
134
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * The GameProfile boundary (docs/PLAN.md §3): everything game-specific lives
3
+ * behind this interface, in one module per game under games/. The engine and
4
+ * features never name a game, they read the active profile (games/active.ts)
5
+ * or the SchemaData built from it (schema/loader.ts).
6
+ *
7
+ * CI enforces the boundary: outside packages/server/src/games/ and
8
+ * packages/vscode/, game-name strings may not appear in source
9
+ * (scripts/check-game-boundary.mjs).
10
+ */
11
+ import type { DefRootKey, RefField, SchemaEntry, StructureSpec } from "../schema/types";
12
+ import type { PlaceholderSpec } from "../data/modifierTemplates";
13
+ import type { GuiLayoutQuirks, GuiTextMetrics } from "../gui/layoutEngine";
14
+ import type { SaveSchema } from "../gui/saveSchema";
15
+
16
+ /**
17
+ * One "New Content" template: the content of a scaffold, as data, so the writer
18
+ * (packages/vscode/src/scaffold/) stays game-neutral. Every text field expands
19
+ * four placeholders: `$PREFIX$` (the mod prefix), `$NAME$` (the key or event id
20
+ * the user gave), `$KEY$` (`$NAME$` with dots turned into underscores, for
21
+ * games whose loc keys cannot carry a dot) and `$LANG$` (the loc language).
22
+ *
23
+ * Every template must be written from the game's OWN vanilla files: a scaffold
24
+ * that names a key the game does not know is exactly the silent failure this
25
+ * command exists to prevent.
26
+ */
27
+ export interface ScaffoldTemplate {
28
+ /** Stable kind id, also the quick-pick value ("event", "on_action"). */
29
+ id: string;
30
+ /** Quick-pick label including its codicon ("$(zap) Event"). */
31
+ label: string;
32
+ /** Quick-pick detail: where the content lands. */
33
+ detail: string;
34
+ /** Word for the name prompt ("event id", "decision"). */
35
+ nameLabel: string;
36
+ /** Shape `$NAME$` must have: a plain identifier or a `<prefix>.<number>` id. */
37
+ nameKind: "identifier" | "eventId";
38
+ /**
39
+ * Fixed choices for `$NAME$` (the vanilla on_action names to hook), offered
40
+ * as a quick-pick with a free-text escape instead of a bare input box.
41
+ */
42
+ picks?: string[];
43
+ /** Script file, mod-relative with forward slashes. */
44
+ scriptPath: string;
45
+ /** The block written, and appended when the file already exists. */
46
+ block: string;
47
+ /** The (expanded) line inside `block` the cursor lands on. */
48
+ cursorMarker: string;
49
+ /** Line the script file MUST start with (the event namespace). */
50
+ requiredHeader?: string;
51
+ /** Loc file, when the content type needs loc keys. */
52
+ locPath?: string;
53
+ /** Loc entry lines (without the `l_<lang>:` header). */
54
+ locBody?: string;
55
+ }
56
+
57
+ /**
58
+ * Data-only identity and conventions of a supported game. Kept separate from
59
+ * the knowledge tables so clients (the VSCode extension) can import a game's
60
+ * meta without pulling the bundled schema/data into their bundle.
61
+ */
62
+ export interface GameMeta {
63
+ /** Stable id used on the wire (settings.gameId) and for data/<id>/ bundles. */
64
+ id: string;
65
+ /** Full display name ("Crusader Kings III"). */
66
+ name: string;
67
+ /** Short user-facing prefix for progress titles and messages ("CK3"). */
68
+ shortName: string;
69
+ engine: "jomini" | "clausewitz-classic";
70
+ /** Mod descriptor convention: Paradox-launcher `.mod` file vs `.metadata/metadata.json`. */
71
+ descriptor: "mod" | "metadata";
72
+ /** Per-workspace config dir holding schema.json / playset.json overlays. */
73
+ configDirName: string;
74
+ /** Game folder under `Documents/Paradox Interactive/` (script_docs logs live in its logs/). */
75
+ docsFolderName: string;
76
+ /**
77
+ * Subfolder of docsFolderName holding the script_docs dumps. Absent =
78
+ * "logs" (the classic location); newer titles may write to "docs".
79
+ */
80
+ scriptDocsSubdir?: string;
81
+ /**
82
+ * Console command that dumps the data-type documentation. Absent =
83
+ * "DumpDataTypes" (CK3's casing); newer Jomini titles use snake_case.
84
+ * The dump lands under `<Documents>/<docsFolderName>/logs/` regardless of
85
+ * where script_docs go.
86
+ */
87
+ dataTypesCommand?: string;
88
+ steamAppId: number;
89
+ /** Whether event files declare `namespace = x` and use `ns.N` event ids. */
90
+ eventNamespaces: boolean;
91
+ /**
92
+ * Subfolder of docsFolderName the ENGINE writes error.log into. Absent =
93
+ * "logs", which is where both live installs checked (2026-08-12) write it.
94
+ * Independent of scriptDocsSubdir, which newer titles point at docs/.
95
+ */
96
+ errorLogSubdir?: string;
97
+ /**
98
+ * The game's default UI font file, relative to the game data dir, embedded by
99
+ * the GUI editor so its canvas text looks like the game's. Absent = no font
100
+ * is embedded and the webview falls back to a system serif.
101
+ */
102
+ uiFont?: string;
103
+ /**
104
+ * In-game-measured text metrics for the game's default GUI font, feeding the
105
+ * layout engine's text measurer and the editor canvas. Absent = the game is
106
+ * NOT calibrated: the engine assumes the default table
107
+ * (gui/measuredMetrics.ts) and the GUI editor refuses to open. Measured via
108
+ * docs/gui-designer/calibration/probes/.
109
+ */
110
+ guiTextMetrics?: GuiTextMetrics;
111
+ /**
112
+ * "New Content" templates offered for this game, in quick-pick order. Absent
113
+ * or empty = no content type has been verified against the game's own files,
114
+ * and the command says so instead of writing a guess.
115
+ */
116
+ scaffolds?: ScaffoldTemplate[];
117
+ /**
118
+ * Load-stage folders at the mod root under which all content lives (EU5's
119
+ * `in_game/` etc.). Schema paths carry the prefix explicitly; this list is
120
+ * for mod detection. Absent = content sits directly at the mod root.
121
+ */
122
+ stageRoots?: string[];
123
+ /**
124
+ * The game composes flags from `common/coat_of_arms` definitions over
125
+ * `gfx/coat_of_arms/{patterns,colored_emblems,textured_emblems}` textures,
126
+ * in the layout the flag builder renders. Absent = the Flag Builder does
127
+ * not open for this game.
128
+ */
129
+ flagBuilder?: boolean;
130
+ /**
131
+ * Database entry-mode prefixes legal on top-level definition keys
132
+ * (EU5's `REPLACE:key`). The indexer strips a leading `<MODE>:` before
133
+ * treating the rest as the definition name. Absent = no such syntax.
134
+ */
135
+ entryModes?: string[];
136
+ /**
137
+ * script_docs dump dialect. Absent = the classic plain-text format
138
+ * (`name - doc` entries with `----` separators). Newer Jomini titles emit
139
+ * markdown (`## name`, `**Supported Scopes**`) and per-game modifier shapes:
140
+ * "masked-block" (`tag:` + indented Mask/Name/Description) or "tag-line"
141
+ * (`Tag: name, Categories: ...` lines).
142
+ */
143
+ scriptDocs?: { format: "classic" | "markdown"; modifiers: "classic" | "masked-block" | "tag-line" };
144
+ /** External deep-validation tool (the tiger family), when one exists. */
145
+ tiger?: { binaryName: string; repoSlug: string; confName: string };
146
+ /**
147
+ * Suffix for server-side cache filenames under storageDir ("" keeps the
148
+ * pre-profile names so existing caches survive; non-empty for later games,
149
+ * e.g. "-vic3", so games sharing one storageDir never collide).
150
+ */
151
+ cacheSuffix: string;
152
+ }
153
+
154
+ /** A game's full knowledge bundle: meta plus the tables the engine consumes. */
155
+ export interface GameProfile extends GameMeta {
156
+ /** Folder→definition-kind table (see schema/types.ts). */
157
+ schema: SchemaEntry[];
158
+ /** Assignment keys whose values reference other definitions. */
159
+ refFields: RefField[];
160
+ /** Scalar-value prefixes that reference definitions (`culture:czech`). */
161
+ prefixRefs: Record<string, string[]>;
162
+ /** Block-local ref fields (outer key → inner key → kinds). */
163
+ blockRefFields: Record<string, Record<string, string[]>>;
164
+ /** Hover provenance labels per definition kind (`_*.info` folder names). */
165
+ structureSources: Record<string, string>;
166
+ /**
167
+ * Block-schema `structure` layer per definition kind, attached to the matching
168
+ * schema entries at load (schema/loader.ts). A game whose schema table already
169
+ * carries `structure` on its entries (a hand-curated layer) needs nothing here;
170
+ * those entries always win.
171
+ */
172
+ structures?: Record<string, StructureSpec>;
173
+ /**
174
+ * Definition kinds that declare their own root scope in their body, keyed by
175
+ * kind (scopes/inference.ts). Absent = every kind's root scope comes from the
176
+ * schema table alone.
177
+ */
178
+ defRootKeys?: Record<string, DefRootKey>;
179
+ /** Templated-modifier placeholder table (data/modifierTemplates.ts). */
180
+ modifierPlaceholders: Record<string, PlaceholderSpec>;
181
+ /**
182
+ * Bundled `[ ... ]` data-function tables (data/<id>/dataTypes.json), when the
183
+ * game ships one. Shape is data/dataTypes.ts's bundled-JSON shape; typed
184
+ * loosely here to keep profiles JSON-import-friendly.
185
+ */
186
+ bundledDataTypes?: unknown;
187
+ /** Bundled .gui widget schema (data/<id>/guiSchema.json), when available. */
188
+ guiSchema?: unknown;
189
+ /**
190
+ * In-game-measured layout rule divergences from the engine's defaults
191
+ * (which are themselves in-game-measured for the default profile). Each
192
+ * flag documents its probe in gui/layoutEngine.ts's GuiLayoutQuirks.
193
+ */
194
+ guiLayoutQuirks?: GuiLayoutQuirks;
195
+ /**
196
+ * How this game's save games are read for GUI preview values: the entity
197
+ * mapping, the meta keys and the shape the streaming reader must expect
198
+ * (gui/saveSchema.ts). Absent = a save answers the meta-only default rows.
199
+ */
200
+ saveSchema?: SaveSchema;
201
+ /** Trailing provenance note on bundled-wiki token hovers. */
202
+ wikiNote: string;
203
+ /** LSP diagnostic `source` label ("ck3-script"). */
204
+ diagnosticSource: string;
205
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Registry of in-repo game profiles. Profiles are not a plugin API (PLAN.md
3
+ * non-goals): adding a game means adding a games/<id>/ module and registering
4
+ * it here.
5
+ */
6
+ import type { GameProfile } from "./profile";
7
+ import { ck3Profile } from "./ck3";
8
+ import { vic3Profile } from "./vic3";
9
+ import { eu5Profile } from "./eu5";
10
+
11
+ const profiles = new Map<string, GameProfile>([
12
+ [ck3Profile.id, ck3Profile],
13
+ [vic3Profile.id, vic3Profile],
14
+ [eu5Profile.id, eu5Profile],
15
+ ]);
16
+
17
+ export const defaultProfile: GameProfile = ck3Profile;
18
+
19
+ /** The profile for a wire gameId; unknown/absent ids fall back to the default
20
+ * (bare LSP clients predating gameId keep working). */
21
+ export function resolveProfile(id: string | null | undefined): GameProfile {
22
+ return (id && profiles.get(id)) || defaultProfile;
23
+ }
24
+
25
+ export function allProfiles(): GameProfile[] {
26
+ return [...profiles.values()];
27
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The Victoria 3 game profile (shipped, PLAN-multigame.md M7): schema verified
3
+ * against a real install, gui widget schema harvested from vanilla, freqs from
4
+ * the vanilla corpus; engine tokens come from the user's script_docs dumps
5
+ * (markdown format). No wiki fallback and no structures layer, see below.
6
+ */
7
+ import type { GameProfile } from "../profile";
8
+ import { vic3Meta } from "./meta";
9
+ import { VIC3_BLOCK_REF_FIELDS, VIC3_PREFIX_REFS, VIC3_REF_FIELDS, VIC3_SCHEMA } from "./schema";
10
+ import { VIC3_STRUCTURES, VIC3_STRUCTURE_SOURCES } from "./structures";
11
+ import { VIC3_SAVE_SCHEMA } from "./saveSchema";
12
+ import GUI_SCHEMA from "../../../data/vic3/guiSchema.json";
13
+
14
+ export const vic3Profile: GameProfile = {
15
+ ...vic3Meta,
16
+ schema: VIC3_SCHEMA,
17
+ refFields: VIC3_REF_FIELDS,
18
+ prefixRefs: VIC3_PREFIX_REFS,
19
+ blockRefFields: VIC3_BLOCK_REF_FIELDS,
20
+ guiSchema: GUI_SCHEMA,
21
+ // guiTextMetrics live on the meta (the client reads them too, for the GUI
22
+ // editor gate and its canvas line height).
23
+ // Vic3 keeps an authored size on an EMPTY container (px_probe_c C5: the
24
+ // 150x60 rendered in full, engine warning logged yet applied) where the
25
+ // default profile measured collapse-to-0 (L25 narrow).
26
+ guiLayoutQuirks: { emptySizedContainerKept: true },
27
+ // Structure layer, fully harvested (games/vic3/structures.ts). The 2026-08-01
28
+ // note here claimed the Vic3 tree had no source for it: wrong. Vic3 ships no
29
+ // `_*.info`, but it does ship 91 `*.md` docs next to its data, and 71 of them
30
+ // are `key = value # doc` listings in the same shape as CK3's `.info` files,
31
+ // machine-readable after all. Those, cross-checked against real vanilla usage,
32
+ // are the source.
33
+ structures: VIC3_STRUCTURES,
34
+ structureSources: VIC3_STRUCTURE_SOURCES,
35
+ // Vic3 events carry no `scope` key: the root scope comes from `type`
36
+ // (measured over vanilla + three workshop mods, 2026-08-15: country_event
37
+ // 2533, state_event 14, nothing else at a definition's top level). Assuming
38
+ // CK3's `scope = character` spelling here put EVERY Vic3 event in a character
39
+ // scope, which demoted every country effect/trigger to "other scope" and sank
40
+ // it to the bottom of completion, the measured cause of the flat effect-block
41
+ // ranking. scripted_guis do declare `scope = X`, with no default.
42
+ defRootKeys: {
43
+ event: { key: "type", default: "country", values: { country_event: "country", state_event: "state" } },
44
+ customizable_localization: { key: "type" },
45
+ scripted_gui: { key: "scope" },
46
+ },
47
+ modifierPlaceholders: {},
48
+ saveSchema: VIC3_SAVE_SCHEMA,
49
+ // No bundled wiki tokens in the preview cut, so nothing ever renders this.
50
+ wikiNote: "",
51
+ diagnosticSource: "vic3-script",
52
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Victoria 3 identity and conventions. Data only — safe for the VSCode
3
+ * client to import without pulling the knowledge tables into its bundle.
4
+ */
5
+ import type { GameMeta } from "../profile";
6
+ import { VIC3_SCAFFOLDS } from "./scaffolds";
7
+
8
+ export const vic3Meta: GameMeta = {
9
+ id: "vic3",
10
+ name: "Victoria 3",
11
+ shortName: "Vic3",
12
+ engine: "jomini",
13
+ // Vic3 mods carry .metadata/metadata.json instead of a launcher .mod file.
14
+ descriptor: "metadata",
15
+ configDirName: ".vic3modding",
16
+ docsFolderName: "Victoria 3",
17
+ // Vic3's `script_docs` writes to Documents/.../docs (like EU5), while
18
+ // `dump_data_types` writes to logs/data_types — verified on a live install.
19
+ scriptDocsSubdir: "docs",
20
+ dataTypesCommand: "dump_data_types",
21
+ steamAppId: 529340,
22
+ eventNamespaces: true,
23
+ scaffolds: VIC3_SCAFFOLDS,
24
+ // uiFont deliberately absent: this game ships no Gitan (its fonts/ holds
25
+ // ParadoxVictorian, EBGaramond, NotoSans), and which file `standard_font`
26
+ // resolves to is unmeasured. The editor embeds none and the metrics below
27
+ // carry the text boxes.
28
+ //
29
+ // Measured in-game 2026-08-09 (px_probe_d/e, 1920x1080 @ 100% GUI scaling;
30
+ // docs/gui-designer/calibration/vic3-expectations.md). The measured law:
31
+ // advance(M) = round(0.9 * fontsize), i.e. 14 @15, 15 @17 (the default
32
+ // size), 27 @30, and line box = 1.3 * fontsize exactly (the game ceils the
33
+ // box: 20 @15, 39 @30, 23 @17). A base-30 table + roundPerSize reproduces
34
+ // every measured box EXACTLY: 10xM = 140 @15 / 150 @default / 270 @30,
35
+ // "M M M M M" = 82, "MMMM MMMM" = 115, 10xi = 40. A bare textbox renders
36
+ // at fontsize 17.
37
+ guiTextMetrics: {
38
+ baseFontsize: 30,
39
+ lineHeight: 39,
40
+ glyphs: {
41
+ M: { adv: 27, ink: 27 },
42
+ i: { adv: 8, ink: 8 },
43
+ " ": { adv: 6, ink: 0 },
44
+ },
45
+ defaultGlyph: { adv: 18, ink: 16 }, // unmeasured average guess
46
+ defaultFontsize: 17,
47
+ roundPerSize: true,
48
+ },
49
+ // Vic3's script_docs dumps are markdown (`## name`), with modifiers as
50
+ // `tag:` blocks carrying Mask/Name/Description lines.
51
+ scriptDocs: { format: "markdown", modifiers: "masked-block" },
52
+ tiger: { binaryName: "vic3-tiger", repoSlug: "amtep/tiger", confName: "vic3-tiger.conf" },
53
+ cacheSuffix: "-vic3",
54
+ flagBuilder: true,
55
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * How a Victoria 3 save is read for GUI preview values.
3
+ *
4
+ * A Vic3 save is plain Jomini script (a big campaign runs ~115 MB and 6.5
5
+ * million lines) and writes its registries in the order the reader needs them:
6
+ * `meta_data`, `country_manager`, `states`, `character_manager`. The played
7
+ * country's own entry names its capital, ruler and heir, so those ids are
8
+ * already known when the later registries go by and one streaming pass answers
9
+ * everything.
10
+ */
11
+ import type { BlockNode } from "../../parser";
12
+ import {
13
+ block,
14
+ META_MAPPINGS,
15
+ named,
16
+ scalar,
17
+ thousands,
18
+ type SaveContext,
19
+ type SaveSchema,
20
+ type ValueMapping,
21
+ } from "../../gui/saveSchema";
22
+
23
+ /** `first_name` + `last_name`, each resolved through loc when it is a key. */
24
+ function characterName(ctx: SaveContext, character: BlockNode | undefined): string | undefined {
25
+ const parts = [scalar(character, "first_name"), scalar(character, "last_name")]
26
+ .map((p) => named(ctx, p))
27
+ .filter((p): p is string => !!p);
28
+ return parts.length ? parts.join(" ") : undefined;
29
+ }
30
+
31
+ const VIC3_MAPPINGS: ValueMapping[] = [
32
+ ...META_MAPPINGS,
33
+ {
34
+ chains: ["GetPlayer.GetAdjective"],
35
+ read: (ctx) => (ctx.tag ? ctx.loc(`${ctx.tag}_ADJ`) : undefined),
36
+ },
37
+ {
38
+ // A character's `GetName` and `GetFullName` both render the whole name;
39
+ // only `GetFirstName` is narrower.
40
+ chains: ["GetPlayer.GetRuler.GetName", "GetPlayer.GetRuler.GetFullName"],
41
+ read: (ctx) => characterName(ctx, ctx.ruler),
42
+ },
43
+ {
44
+ chains: ["GetPlayer.GetRuler.GetFirstName"],
45
+ read: (ctx) => named(ctx, scalar(ctx.ruler, "first_name")),
46
+ },
47
+ {
48
+ chains: ["GetPlayer.GetHeir.GetName"],
49
+ read: (ctx) => characterName(ctx, ctx.heir),
50
+ },
51
+ {
52
+ chains: ["GetPlayer.GetCapital.GetName"],
53
+ read: (ctx) => {
54
+ const region = scalar(ctx.capital, "region");
55
+ return region ? (ctx.loc(region) ?? region) : undefined;
56
+ },
57
+ },
58
+ {
59
+ chains: ["GetPlayer.GetGold", "GetPlayer.GetBudget.GetGold"],
60
+ read: (ctx) => thousands(scalar(block(ctx.country, "budget"), "money")),
61
+ },
62
+ ];
63
+
64
+ export const VIC3_SAVE_SCHEMA: SaveSchema = {
65
+ mappings: VIC3_MAPPINGS,
66
+ registry: {
67
+ entries: "database",
68
+ countryBlock: "country_manager",
69
+ tagKey: "definition",
70
+ mainKey: "is_main_tag",
71
+ links: [
72
+ { slot: "ruler", key: "ruler", block: "character_manager" },
73
+ { slot: "heir", key: "heir", block: "character_manager" },
74
+ { slot: "capital", key: "capital", block: "states" },
75
+ ],
76
+ },
77
+ };