@px-lsp/protocol 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 (48) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +25 -0
  3. package/dist/arrays.d.ts +13 -0
  4. package/dist/arrays.js +19 -0
  5. package/dist/constants.d.ts +9 -0
  6. package/dist/constants.js +10 -0
  7. package/dist/descriptorMetadata.d.ts +51 -0
  8. package/dist/descriptorMetadata.js +98 -0
  9. package/dist/descriptorMod.d.ts +66 -0
  10. package/dist/descriptorMod.js +335 -0
  11. package/dist/errorLogParser.d.ts +33 -0
  12. package/dist/errorLogParser.js +125 -0
  13. package/dist/fsWalk.d.ts +20 -0
  14. package/dist/fsWalk.js +159 -0
  15. package/dist/locProperties.d.ts +13 -0
  16. package/dist/locProperties.js +46 -0
  17. package/dist/locRefs.d.ts +11 -0
  18. package/dist/locRefs.js +31 -0
  19. package/dist/modName.d.ts +6 -0
  20. package/dist/modName.js +53 -0
  21. package/dist/protocol.d.ts +1462 -0
  22. package/dist/protocol.js +201 -0
  23. package/dist/regex.d.ts +13 -0
  24. package/dist/regex.js +21 -0
  25. package/dist/suppression.d.ts +52 -0
  26. package/dist/suppression.js +173 -0
  27. package/dist/tigerParser.d.ts +28 -0
  28. package/dist/tigerParser.js +72 -0
  29. package/dist/translationCore.d.ts +26 -0
  30. package/dist/translationCore.js +162 -0
  31. package/dist/types.d.ts +82 -0
  32. package/dist/types.js +3 -0
  33. package/package.json +39 -0
  34. package/src/arrays.ts +16 -0
  35. package/src/constants.ts +12 -0
  36. package/src/descriptorMetadata.ts +101 -0
  37. package/src/descriptorMod.ts +354 -0
  38. package/src/errorLogParser.ts +136 -0
  39. package/src/fsWalk.ts +126 -0
  40. package/src/locProperties.ts +43 -0
  41. package/src/locRefs.ts +38 -0
  42. package/src/modName.ts +18 -0
  43. package/src/protocol.ts +1459 -0
  44. package/src/regex.ts +19 -0
  45. package/src/suppression.ts +178 -0
  46. package/src/tigerParser.ts +79 -0
  47. package/src/translationCore.ts +140 -0
  48. package/src/types.ts +90 -0
@@ -0,0 +1,1462 @@
1
+ /** Resolved extension settings, computed client-side (path validation, Steam
2
+ * detection fallbacks, workspace-folder default) and pushed to the server. */
3
+ export interface ParadoxSettings {
4
+ /** Game profile id; absent/unknown ids fall back to the server's default
5
+ * game. Detected client-side per workspace (descriptor file, else setting). */
6
+ gameId?: string;
7
+ gamePath: string | null;
8
+ logsPath: string | null;
9
+ modPath: string | null;
10
+ /** Parent/dependency mod roots (load order, base first) indexed as source "parent"
11
+ *, the submod / compatibility-patch workflow. */
12
+ parentPaths: string[];
13
+ /** Workspace mod roots (subset of parentPaths): mods the user is EDITING in
14
+ * this workspace, so they get the mod treatment, reference indexing and
15
+ * reference diagnostics, on top of the parent definition scan. */
16
+ workspaceMods?: string[];
17
+ locLanguage: string;
18
+ /** Show inferred scope after scope-changing block openers (off by default). */
19
+ scopeInlayHints: boolean;
20
+ /** Our diagnostic codes to suppress everywhere. */
21
+ diagnosticsIgnore: string[];
22
+ /** Glob patterns (workspace-relative paths) whose diagnostics are suppressed. */
23
+ diagnosticsIgnorePatterns: string[];
24
+ /** When false (default) mod-only: never diagnose files under the game path. */
25
+ diagnosticsVanilla: boolean;
26
+ /** `px.trace.perf`: wall clock for every request, rescan, index change and
27
+ * scan phase into the output channel. Off by default (perf campaign §A2). */
28
+ tracePerf?: boolean;
29
+ }
30
+ /**
31
+ * What the connected client can do beyond plain LSP. Every capability is
32
+ * independent and off by default, so a bare client gets the degraded shape
33
+ * without declaring anything and a rich client opts in to exactly the parts
34
+ * it implements.
35
+ */
36
+ export interface ParadoxClientCapabilities {
37
+ /**
38
+ * The client renders the sanitized `<span style="color:var(--vscode-*)">`
39
+ * markup in hover markdown (VSCode theme variables). Default false: hover
40
+ * cards are plain markdown, with the same content.
41
+ */
42
+ hoverHtml?: boolean;
43
+ /**
44
+ * The command ids the client registers, from {@link clientCommands}. The
45
+ * server emits `command:` links and command-carrying code actions ONLY for
46
+ * ids listed here; for the rest it falls back to plain text or a real
47
+ * WorkspaceEdit. Default: none.
48
+ */
49
+ commands?: string[];
50
+ /**
51
+ * The client watches the mod tree itself and pushes
52
+ * {@link modFileChangedNotification}. The server then does NOT register its
53
+ * own `workspace/didChangeWatchedFiles` watcher. Default false: the server
54
+ * registers one whenever the client supports dynamic registration.
55
+ */
56
+ ownFileWatcher?: boolean;
57
+ }
58
+ /** initializationOptions passed at LanguageClient start. All fields optional:
59
+ * the server has fail-soft fallbacks for bare clients. */
60
+ export interface ParadoxInitOptions {
61
+ /** Server-side cache directory (the extension's global storage path). */
62
+ storageDir?: string;
63
+ /** What this client can do; see {@link ParadoxClientCapabilities}. Absent
64
+ * fields default to off (the plain-LSP-client shape). */
65
+ client?: ParadoxClientCapabilities;
66
+ /**
67
+ * @deprecated Send {@link ParadoxInitOptions.client} instead. `true` is an
68
+ * alias for `{ hoverHtml: true, commands: <every id in clientCommands>,
69
+ * ownFileWatcher: true }` (what the VSCode extension declared before the
70
+ * capabilities object existed); false/absent means all-off. Ignored when
71
+ * `client` is present.
72
+ */
73
+ clientCommands?: boolean;
74
+ /**
75
+ * Root holding the bundled per-game data directories: the server reads
76
+ * `<dataDir>/<gameId>/wikidocs/` and `<dataDir>/<gameId>/freqs.json`.
77
+ * Normally omitted: the server uses `data/` next to its own bundle. Set it
78
+ * when the data ships apart from the server bundle (an embedder unpacking
79
+ * both separately). Re-resolved against the new `gameId` whenever the game
80
+ * changes, so it stays profile-correct.
81
+ */
82
+ dataDir?: string;
83
+ /**
84
+ * @deprecated Send {@link ParadoxInitOptions.dataDir} instead. Overrides the
85
+ * wikidocs/ folder ALONE, freqs.json still comes from `dataDir`/the bundle,
86
+ * and, being one fixed folder, it does NOT follow a `gameId` change.
87
+ */
88
+ wikidocsDir?: string;
89
+ settings?: ParadoxSettings;
90
+ }
91
+ /**
92
+ * Client commands the server references in code actions and hover links (part
93
+ * of the wire contract: a client that implements one must register exactly
94
+ * this id and list it in {@link ParadoxClientCapabilities.commands}). They
95
+ * carry the "px." prefix: these are public extension command ids with shipped
96
+ * default keybindings. The prefix was renamed in the Paradox Toolkit rebrand
97
+ * and no fallback to the old ids is registered.
98
+ */
99
+ export declare const clientCommands: {
100
+ readonly editLocalization: "px.editLocalization";
101
+ readonly openLocalizationSideBySide: "px.openLocalizationSideBySide";
102
+ readonly showReferences: "px.showReferences";
103
+ };
104
+ /** Every id in {@link clientCommands}: what a fully capable client registers. */
105
+ export declare const allClientCommandIds: string[];
106
+ /** Notification: settings changed; payload {@link ParadoxSettings}. */
107
+ export declare const configChangedNotification = "paradox/configChanged";
108
+ /** Notification: a mod file changed on disk; payload {@link ModFileChangeParams}. */
109
+ export declare const modFileChangedNotification = "paradox/modFileChanged";
110
+ export interface ModFileChangeParams {
111
+ /** Absolute filesystem path (not a URI). */
112
+ fsPath: string;
113
+ }
114
+ /** Request: re-parse script_docs logs; payload {@link ReloadDocsParams} -> {@link ReloadDocsResult}. */
115
+ export declare const reloadDocsRequest = "paradox/reloadDocs";
116
+ export interface ReloadDocsParams {
117
+ force: boolean;
118
+ }
119
+ export interface ReloadDocsResult {
120
+ tokens: number;
121
+ }
122
+ /** Request: index statistics; no payload -> {@link IndexStats}. */
123
+ export declare const indexStatsRequest = "paradox/indexStats";
124
+ /** Request: look up localization entries for a key; {@link LookupLocParams} -> {@link LocEntryInfo}[].
125
+ * Mod entries shadow vanilla ones (the full list is returned, mod first). */
126
+ export declare const lookupLocRequest = "paradox/lookupLoc";
127
+ export interface LookupLocParams {
128
+ key: string;
129
+ }
130
+ export interface LocEntryInfo {
131
+ file: string;
132
+ /** 0-based. */
133
+ line: number;
134
+ source: "vanilla" | "parent" | "mod";
135
+ value?: string;
136
+ }
137
+ /** Notification: data health for the status bar; payload {@link StatusPayload}. */
138
+ export declare const statusNotification = "paradox/status";
139
+ export interface StatusPayload {
140
+ tokens: number;
141
+ tokensFromScriptDocs: boolean;
142
+ /** True when the script_docs tokens came from the BUNDLED dump snapshot
143
+ * (data/<gameId>/script_docs) rather than the user's own dump. */
144
+ tokensFromBundledDumps?: boolean;
145
+ definitions: number;
146
+ /** True while a (re)scan is running. */
147
+ indexing: boolean;
148
+ }
149
+ /** Notification: the definition index changed (debounced server-side); no payload.
150
+ * Overview views re-query on this signal. */
151
+ export declare const indexChangedNotification = "paradox/indexChanged";
152
+ /** Notification: a long-running server phase started or finished; payload
153
+ * {@link ProgressPayload}. The status bar lists what is still loading, so a
154
+ * cold workspace says which step it is on instead of looking idle. No
155
+ * percentages: the phases are coarse and the client only shows their state. */
156
+ export declare const progressNotification = "paradox/progress";
157
+ export interface ProgressPayload {
158
+ /** Stable phase id, so a "done" can find the "start" it belongs to. */
159
+ phase: string;
160
+ state: "start" | "done";
161
+ /** Human-readable label for the phase, sent with "start". */
162
+ detail?: string;
163
+ }
164
+ /** Shared param for the mod-scoped overview requests: restrict the result to
165
+ * one workspace mod (absolute root path). Absent/null = all workspace mods. */
166
+ export interface ModScopedParams {
167
+ modRoot?: string | null;
168
+ }
169
+ /** Request: mod content inventory; {@link ModScopedParams} -> {@link ModOverview}. */
170
+ export declare const modOverviewRequest = "paradox/modOverview";
171
+ export interface OverviewDef {
172
+ name: string;
173
+ file: string;
174
+ line: number;
175
+ }
176
+ export interface OverviewKind {
177
+ kind: string;
178
+ count: number;
179
+ /** Capped list (first N alphabetically); `count` is the real total. */
180
+ defs: OverviewDef[];
181
+ }
182
+ export interface ModOverview {
183
+ kinds: OverviewKind[];
184
+ totalDefs: number;
185
+ totalRefs: number;
186
+ }
187
+ /** Request: localization coverage; {@link ModScopedParams} -> {@link LocCoverage}[]. */
188
+ export declare const locCoverageRequest = "paradox/locCoverage";
189
+ export interface LocIssue {
190
+ key: string;
191
+ file?: string;
192
+ /** 0-based. */
193
+ line?: number;
194
+ /** For untranslated: the source-language text. */
195
+ value?: string;
196
+ }
197
+ export interface LocCoverage {
198
+ language: string;
199
+ defined: number;
200
+ /** Referenced by mod script / required by schema but not defined anywhere. */
201
+ missing: LocIssue[];
202
+ /** Defined in the mod but never referenced and not overriding vanilla. */
203
+ orphaned: LocIssue[];
204
+ /** Value identical to the source language (only for non-source languages). */
205
+ untranslated: LocIssue[];
206
+ }
207
+ /** Request: override/conflict map; {@link ModScopedParams} -> {@link OverrideInfo}[]. */
208
+ export declare const overridesRequest = "paradox/overrides";
209
+ export interface OverrideSite {
210
+ source: "vanilla" | "parent" | "mod";
211
+ /** Display label: the owning mod's descriptor name when known, else `source`. */
212
+ label?: string;
213
+ file: string;
214
+ line: number;
215
+ }
216
+ export interface OverrideInfo {
217
+ name: string;
218
+ kind: string;
219
+ mod: OverrideSite;
220
+ shadowed: OverrideSite[];
221
+ /** Folder rule: script is last-in-wins, GUI is first-in-wins. */
222
+ rule: "LIOS" | "FIOS";
223
+ winner: "mod" | "other";
224
+ note?: string;
225
+ }
226
+ /** Request: full event detail for the graph inspector; {@link EventDetailParams} -> {@link EventDetail} | null. */
227
+ export declare const eventDetailRequest = "paradox/eventDetail";
228
+ export interface EventDetailParams {
229
+ id: string;
230
+ }
231
+ /** A localizable field: key, resolved text, and (for mod entries) the editable site. */
232
+ export interface EventLocField {
233
+ key: string;
234
+ text?: string;
235
+ /** Present only when the entry lives in the mod (in-place editable). */
236
+ file?: string;
237
+ line?: number;
238
+ /** The value comes from a dynamic block (first_valid / triggered_desc), not a plain key. */
239
+ dynamic?: boolean;
240
+ }
241
+ /**
242
+ * One flattened line of a rendered block: enough to print an event's logic
243
+ * back as readable pseudo-script without the client re-parsing anything.
244
+ */
245
+ export interface EventScriptLine {
246
+ /** Nesting depth inside the rendered block (0 = a direct child). */
247
+ depth: number;
248
+ /** The statement without indentation: `key = value`, `key = {`, `}`, or a bare scalar. */
249
+ text: string;
250
+ /** 0-based source line. */
251
+ line: number;
252
+ }
253
+ /**
254
+ * A reference inside a block that hands control to another event or on_action:
255
+ * the step-into edge of an event walkthrough. Collected from the schema's
256
+ * event/on_action reference fields (`trigger_event`, `on_action`, `events`,
257
+ * `random_events`, …), so a game profile that names them differently is
258
+ * covered without a hard-coded key list.
259
+ */
260
+ export interface EventStepTarget {
261
+ /** The key that produced the reference (`trigger_event`, `on_action`, …). */
262
+ via: string;
263
+ /** Referenced event id / on_action name, exactly as written. */
264
+ name: string;
265
+ /** What the index says `name` is. "unknown" = not indexed; say so, do not guess. */
266
+ kind: "event" | "on_action" | "unknown";
267
+ /** 0-based line of the reference, in the file that contains it (for a
268
+ * {@link EventStepTarget.fires} entry that is the on_action's own file). */
269
+ line: number;
270
+ /** Definition site, when the name is indexed. */
271
+ file?: string;
272
+ defLine?: number;
273
+ /** Definition sites of that kind, when more than one. on_actions merge
274
+ * across files (a mod extending a vanilla on_action), so `fires` reflects
275
+ * only the site at {@link EventStepTarget.file}. */
276
+ defCount?: number;
277
+ /**
278
+ * on_action targets only: what that on_action itself fires, read from its own
279
+ * definition. Empty when the definition names nothing. Absent when there was
280
+ * nothing to read: the name is not an indexed on_action, its file could not
281
+ * be parsed, or this target already IS one level deep (resolution stops
282
+ * there, so a self-chaining pair cannot recurse).
283
+ */
284
+ fires?: EventStepTarget[];
285
+ /** Real target count before `fires` was capped. */
286
+ firesTotal?: number;
287
+ }
288
+ /**
289
+ * A scalar `key = value` written directly in an event body or an option body,
290
+ * with the line it sits on, so an editor can rewrite it in place instead of
291
+ * re-parsing the file. Blocks are not fields: they are `sections` / `options`.
292
+ */
293
+ export interface EventFieldInfo {
294
+ key: string;
295
+ value: string;
296
+ /** 0-based source line. */
297
+ line: number;
298
+ /** The value was written in quotes and must be rewritten that way. */
299
+ quoted?: boolean;
300
+ }
301
+ export interface EventSectionInfo {
302
+ name: string;
303
+ /** 0-based line of the section key. */
304
+ line: number;
305
+ /** Top-level keys inside the section (capped). */
306
+ keys: string[];
307
+ /** The section rendered as pseudo-script, capped (`totalLines` is the truth). */
308
+ lines: EventScriptLine[];
309
+ totalLines: number;
310
+ /** Events / on_actions this section hands control to, capped. */
311
+ targets: EventStepTarget[];
312
+ /** Real target count before `targets` was capped. */
313
+ targetsTotal: number;
314
+ }
315
+ /** A gate block (trigger / ai_chance) rendered for in-place editing. */
316
+ export interface EventGateInfo {
317
+ /** 0-based line of the block's key. */
318
+ line: number;
319
+ lines: EventScriptLine[];
320
+ totalLines: number;
321
+ }
322
+ export interface EventOptionInfo {
323
+ line: number;
324
+ /** Line the option's first statement may be inserted before (0-based). */
325
+ bodyLine: number;
326
+ /** Scalar keys written in the option body, editable in place. */
327
+ fields: EventFieldInfo[];
328
+ name?: EventLocField;
329
+ effectKeys: string[];
330
+ hasTrigger: boolean;
331
+ hasAiChance: boolean;
332
+ /** The option's own trigger block, rendered, when it has one. */
333
+ trigger?: EventGateInfo;
334
+ /** The option's ai_chance block, rendered, when it has one. */
335
+ aiChance?: EventGateInfo;
336
+ /** The option's effects rendered as pseudo-script (name/trigger/ai_chance/
337
+ * ai_value dropped: they gate the option, they are not its effect), capped. */
338
+ lines: EventScriptLine[];
339
+ totalLines: number;
340
+ /** Events / on_actions this option hands control to, capped. */
341
+ targets: EventStepTarget[];
342
+ /** Real target count before `targets` was capped. */
343
+ targetsTotal: number;
344
+ }
345
+ export interface EventRefInfo {
346
+ name: string;
347
+ kind: "saved_scope" | "variable" | "scripted_effect" | "scripted_trigger" | "script_value" | "event";
348
+ /** First use inside the event, 0-based. */
349
+ line: number;
350
+ defFile?: string;
351
+ defLine?: number;
352
+ /** Number of definition/save sites. */
353
+ defCount?: number;
354
+ }
355
+ export interface EventDetail {
356
+ id: string;
357
+ file: string;
358
+ line: number;
359
+ /** Line of the event's closing brace (option-scaffold insertion point). */
360
+ endLine: number;
361
+ /** Line a new top-level statement may be inserted before (0-based). */
362
+ bodyLine: number;
363
+ /** Scalar keys written at the event's top level, editable in place. */
364
+ fields: EventFieldInfo[];
365
+ type?: string;
366
+ hidden?: boolean;
367
+ theme?: string;
368
+ title?: EventLocField;
369
+ desc?: EventLocField;
370
+ /** The event's third displayed string in the games whose events have one
371
+ * (top-level `flavor`); absent everywhere else. */
372
+ flavor?: EventLocField;
373
+ sections: EventSectionInfo[];
374
+ options: EventOptionInfo[];
375
+ refs: EventRefInfo[];
376
+ }
377
+ /** Request: GUI widget tree for a .gui document; {@link GuiTreeParams} -> {@link GuiTree}. */
378
+ export declare const guiTreeRequest = "paradox/guiTree";
379
+ export interface GuiTreeParams {
380
+ /** For display only; the text is authoritative. */
381
+ uri: string;
382
+ text: string;
383
+ }
384
+ export interface GuiTreeNode {
385
+ /** Widget type or declaration header (window, flowcontainer, "template NAME"…). */
386
+ key: string;
387
+ /** name = "..." when present. */
388
+ name?: string;
389
+ /** For `type x = base { }` / tagged blocks: the base widget type. */
390
+ base?: string;
391
+ /** using = template references. */
392
+ using?: string[];
393
+ /** decl = template/types/type/blockoverride/block headers; state = animation states. */
394
+ kind: "widget" | "state" | "decl";
395
+ /** 0-based line of the key. */
396
+ line: number;
397
+ children: GuiTreeNode[];
398
+ }
399
+ export interface GuiTree {
400
+ nodes: GuiTreeNode[];
401
+ /** Total node count across all depths. */
402
+ count: number;
403
+ }
404
+ /**
405
+ * Request: rendered GUI layout for a .gui document;
406
+ * {@link GuiLayoutParams} -> {@link GuiLayoutResult}. Rectangles come from
407
+ * the measured layout engine (docs/gui-designer/calibration/spec.md), with
408
+ * templates/types resolved against the vanilla + mod gui tree.
409
+ */
410
+ export declare const guiLayoutRequest = "paradox/guiLayout";
411
+ export interface GuiLayoutParams {
412
+ /** For display only; the text is authoritative. */
413
+ uri: string;
414
+ text: string;
415
+ /** Conditional-visibility preview mode; absent = `showAll`. */
416
+ visibility?: GuiVisibilityOptions;
417
+ /**
418
+ * `resolve` (default): textbox keys show their localized value and
419
+ * `[datafunctions]` their knowable text, and sizes follow. `raw`: the
420
+ * `text =` value verbatim, as the file has it.
421
+ */
422
+ loc?: "resolve" | "raw";
423
+ /** Modder-supplied preview text per `[...]` expression (the `.<game>modding/gui-preview-values.json` table). */
424
+ previewValues?: Record<string, string>;
425
+ }
426
+ /**
427
+ * How the layout treats a CONDITIONALLY visible widget, one whose `visible`
428
+ * holds an expression a static preview cannot evaluate (`visible =
429
+ * "[GetPlayer.IsAI]"`). A literal `visible = no` is deterministic and always
430
+ * collapses; `visible = yes` always shows. Neither is a check.
431
+ */
432
+ export type GuiVisibilityMode = "showAll" | "hideAll" | "evaluate";
433
+ export interface GuiVisibilityOptions {
434
+ mode: GuiVisibilityMode;
435
+ /**
436
+ * `evaluate` only: per-check assignments. The KEY is the `visible` value
437
+ * exactly as authored, minus its quotes (`[GetPlayer.IsAI]`). The source
438
+ * string is the only identity a static preview has, so two widgets written
439
+ * with the same condition share one toggle, and a key stays stable across
440
+ * edits that do not touch the condition. A check with no assignment behaves
441
+ * as `showAll` (shown).
442
+ */
443
+ checks?: Record<string, boolean>;
444
+ }
445
+ /** A conditional `visible` the layout met, for building a toggle UI. */
446
+ export interface GuiVisibilityCheck {
447
+ /** The condition source string, the key {@link GuiVisibilityOptions.checks} takes. */
448
+ key: string;
449
+ /** Widgets carrying this condition in this document. */
450
+ count: number;
451
+ /** True when THIS run resolved the check to hidden. */
452
+ hidden: boolean;
453
+ }
454
+ /** Server-side wall clock of one `paradox/guiLayout`, for a stats line. */
455
+ export interface GuiLayoutTimings {
456
+ /** Parsing the document and collecting its own template/type declarations. */
457
+ parseMs: number;
458
+ /** Building the cross-file template/type store; 0 on a cache hit. */
459
+ defsMs: number;
460
+ /** Building the widget tree and arranging every rect. */
461
+ layoutMs: number;
462
+ /** The whole request, server side. */
463
+ totalMs: number;
464
+ }
465
+ export interface GuiLayoutFill {
466
+ texture?: string;
467
+ /** rgba 0..1, straight sRGB multiply (rendered = round(v*255)). */
468
+ color?: [number, number, number, number];
469
+ /**
470
+ * Nine-slice border widths [left, top, right, bottom] in texture pixels
471
+ * (from `spriteborder`/`spriteborder_<side>`). The values as authored;
472
+ * `mode` says whether they apply.
473
+ */
474
+ border?: [number, number, number, number];
475
+ /**
476
+ * How to draw the texture. Nine-slicing needs BOTH a `Cornered*` spriteType
477
+ * AND a non-zero border; a border alone is ignored and the whole texture
478
+ * stretches. `nineslice-*` = corners unscaled, edges and centre tiled or
479
+ * stretched per the suffix; `tile` = repeat the whole texture.
480
+ */
481
+ mode?: "stretch" | "tile" | "nineslice-stretch" | "nineslice-tile";
482
+ /** `framesize = { w h }` cell size when the texture is a frame sheet. */
483
+ framesize?: [number, number];
484
+ /** `alpha = x`: the fill's opacity, 0..1 (absent = 1). */
485
+ alpha?: number;
486
+ /**
487
+ * `modify_texture` with `blend_mode = alphamultiply`: a texture whose alpha
488
+ * multiplies the fill's, stretched over the rect. Listed in `textures` like
489
+ * any other path. Other blend modes are not carried.
490
+ */
491
+ mask?: string;
492
+ /** `fittype = centercrop`: cover the rect and crop to the centre instead of stretching. */
493
+ fit?: "centercrop";
494
+ /**
495
+ * 1-based frame index into that sheet, row-major over the cols x rows grid
496
+ * (cols = texW/w). Out-of-range values clamp to the first or last cell.
497
+ */
498
+ frame?: number;
499
+ }
500
+ /**
501
+ * One piece of what a textbox shows. `loc`: a localization key the index
502
+ * resolved (or not: `resolved` false shows the key itself). `datafn`: a
503
+ * `[...]` expression; resolved through `Localize`/`Concept` or the modder's
504
+ * preview values, else shown as its last chain segment with `resolved` false.
505
+ * `source` is the key or the expression without brackets.
506
+ */
507
+ export interface GuiTextSegment {
508
+ text: string;
509
+ kind: "literal" | "loc" | "datafn";
510
+ source: string;
511
+ resolved: boolean;
512
+ }
513
+ export interface GuiLayoutText {
514
+ /** What is measured and drawn (resolved when the request asked for it). */
515
+ text: string;
516
+ /** The raw `text =` value; differs from `text` when something resolved. */
517
+ raw?: string;
518
+ segments?: GuiTextSegment[];
519
+ fontsize: number;
520
+ offsetX: number;
521
+ offsetY: number;
522
+ lines: string[];
523
+ color?: [number, number, number, number];
524
+ }
525
+ export interface GuiLayoutNode {
526
+ key: string;
527
+ name?: string;
528
+ rect: {
529
+ x: number;
530
+ y: number;
531
+ w: number;
532
+ h: number;
533
+ };
534
+ /** Scrollarea viewport: children are clipped to the rect. */
535
+ clip: boolean;
536
+ bg?: GuiLayoutFill;
537
+ fill?: GuiLayoutFill;
538
+ text?: GuiLayoutText;
539
+ /** 0-based line of the instance statement in the requested document. */
540
+ line?: number;
541
+ /** Placed via anchor+position rules (position honored -> draggable). */
542
+ positioned: boolean;
543
+ /**
544
+ * `line` is the widget's own statement in this document (safe to edit);
545
+ * false for children spliced from type definitions.
546
+ */
547
+ editable: boolean;
548
+ /** Raw `position = { x y }` source values, when present. */
549
+ srcPosition?: [number, number];
550
+ /** Raw `size = { w h }` source values, when present. */
551
+ srcSize?: [number, number];
552
+ /**
553
+ * The widget's index among its parent body's REORDER SIBLINGS: exactly the
554
+ * index a `reorder`, `insert` or `delete` op counts (see {@link GuiSourceOp}).
555
+ * Those are the body's DECLARATIONS, which include the `blockoverride` /
556
+ * `block` / `template` entries a preview never shows, so a client that ranks
557
+ * the widgets it can see is off by one per intervening declaration.
558
+ *
559
+ * Absent whenever no index names the node: a template- or type-spliced child,
560
+ * a datamodel ghost, the contents of a named slot, and a scrollarea's
561
+ * pass-through children, whose ranks count a body their drawn parent does not
562
+ * own. Absent means "not addressable by index"; do not fall back to counting.
563
+ */
564
+ srcIndex?: number;
565
+ /**
566
+ * Placeholder copy of a datamodel item template (the list has no runtime
567
+ * rows in a static preview). The renderer draws it at reduced opacity; it is
568
+ * never editable. Presentation only, not a measured layout rule.
569
+ */
570
+ ghost?: boolean;
571
+ /**
572
+ * The widget's `onclick` value as authored, minus its quotes, when it has
573
+ * one. A static preview cannot run it; a client's interact mode reads the
574
+ * `GetVariableSystem.*` calls out of it to drive the visibility checks, and
575
+ * names the rest as what the game would run.
576
+ */
577
+ onclick?: string;
578
+ /** The widget's `tooltip` value as authored (a loc key or a [datafunction]), when it has one. */
579
+ tooltip?: string;
580
+ /**
581
+ * A root that is a `type name = base { }` DECLARATION laid out as one
582
+ * instance of itself. Set only on roots, and only for a document that
583
+ * instantiates nothing at top level, the shape whole panels are written in
584
+ * by the games whose engine instantiates a window by name from code. The
585
+ * declaration header is not editable; the children under it are ordinary
586
+ * statements of the document and are.
587
+ */
588
+ declared?: boolean;
589
+ children: GuiLayoutNode[];
590
+ }
591
+ export interface GuiLayoutResult {
592
+ nodes: GuiLayoutNode[];
593
+ /** Distinct texture paths referenced anywhere in the tree (mod-relative). */
594
+ textures: string[];
595
+ /** Total node count across all depths. */
596
+ nodeCount: number;
597
+ /** How many .gui files fed the template/type store (0 = no game path). */
598
+ defsFiles: number;
599
+ /**
600
+ * Every conditional `visible` the layout met, key-sorted. Reported in ALL
601
+ * modes, `showAll` included, so a client can build the toggle UI before the
602
+ * user has switched mode.
603
+ */
604
+ visibilityChecks: GuiVisibilityCheck[];
605
+ /** Per-stage wall clock of this request. */
606
+ timings: GuiLayoutTimings;
607
+ }
608
+ /**
609
+ * Request: the properties of ONE widget, as the layout engine resolved them;
610
+ * {@link GuiWidgetInfoParams} -> {@link GuiWidgetInfo}, null when the line
611
+ * carries no widget of its own (a node spliced in from a template or a type has
612
+ * no source here, the same answer `guiSourceEdit` refuses with).
613
+ *
614
+ * This is the designer inspector's READ side. It is a separate request rather
615
+ * than a field on {@link GuiLayoutNode} because it is per-SELECTION data: a
616
+ * vanilla window lays out 500+ widgets and carrying every widget's expanded
617
+ * property list on every layout push would multiply the payload for rows one
618
+ * widget at a time is ever shown.
619
+ */
620
+ export declare const guiWidgetInfoRequest = "paradox/guiWidgetInfo";
621
+ export interface GuiWidgetInfoParams {
622
+ /** For display only; the text is authoritative. */
623
+ uri: string;
624
+ text: string;
625
+ /** 0-based line of the widget's own statement (`GuiLayoutNode.line`). */
626
+ line: number;
627
+ /**
628
+ * Also answer "why is it here": run the layout with an explanation trace on
629
+ * and return {@link GuiWidgetInfo.placement}. Off by default because it costs
630
+ * a full layout of the document; the trace itself is what the flag gates, so
631
+ * an ordinary `paradox/guiLayout` never pays for it.
632
+ */
633
+ placement?: boolean;
634
+ }
635
+ /** One step of the chain a property was spliced through. */
636
+ export interface GuiWidgetOrigin {
637
+ kind: "type" | "template";
638
+ /** The type or template name, as `expandWidget` resolved it. */
639
+ name: string;
640
+ }
641
+ export interface GuiWidgetProperty {
642
+ key: string;
643
+ /**
644
+ * The value as authored, rendered from the tokens: a quoted scalar keeps its
645
+ * quotes, a block reads `{ a b }`. Blocks come from other files whose text
646
+ * the store does not keep, so this is a rendering, not a byte copy.
647
+ */
648
+ value: string;
649
+ /**
650
+ * Definitions the entry was spliced through, INNERMOST first (`[template
651
+ * PxDeco, type px_card]` = a template used inside a type). Empty means the
652
+ * property is authored in the widget's own body, which is the only case
653
+ * `setProperties` rewrites in place.
654
+ */
655
+ origin: GuiWidgetOrigin[];
656
+ /**
657
+ * The values this key SHADOWED, in expansion order (base-most first), so the
658
+ * last entry is the one this row directly overrides. Present only when the
659
+ * key was assigned more than once, which is exactly when the inspector can
660
+ * say "this overrides `{ 100 50 }` from type px_card". Absent otherwise.
661
+ */
662
+ overrides?: GuiWidgetOverride[];
663
+ }
664
+ /** A value a later assignment of the same key replaced. */
665
+ export interface GuiWidgetOverride {
666
+ /** Rendered the same way {@link GuiWidgetProperty.value} is. */
667
+ value: string;
668
+ /** Where the replaced value came from; empty = the widget's own body. */
669
+ origin: GuiWidgetOrigin[];
670
+ }
671
+ /**
672
+ * One contribution to a widget's final origin, in engine order. The `dx`/`dy`
673
+ * of the terms sum to the rect's `x`/`y` exactly (see spec.md B1-B/C/D:
674
+ * `x = parent.x + parentanchor.fx*parent.w - widgetanchor.fx*w + position.x`).
675
+ */
676
+ export interface GuiPlacementTerm {
677
+ kind: "parentOrigin" | "parentanchor" | "widgetanchor" | "position";
678
+ /**
679
+ * The authored spec behind the term (`bottom|right`, `{ -30 -30 }`). Absent
680
+ * on `parentOrigin`, which is the parent's rect rather than a property, and
681
+ * on a `widgetanchor` that was never written (it mirrors `parentanchor`,
682
+ * B1-B/C), there `source` names the anchor it mirrored.
683
+ */
684
+ source?: string;
685
+ dx: number;
686
+ dy: number;
687
+ }
688
+ /**
689
+ * The layout container that assigned a rect outright. The engine DROPS an
690
+ * authored `position` on such a child and logs "Widget cannot have a position
691
+ * in a layout" (probe 2026-08-02, parity-checklist L23), which is the single
692
+ * most common "why is my widget not where I put it".
693
+ */
694
+ export interface GuiPlacedBy {
695
+ /** The parent's widget key (`hbox`, `flowcontainer`, `fixedgridbox`, …). */
696
+ key: string;
697
+ name?: string;
698
+ layout: "box" | "flow" | "grid";
699
+ /** The `position` the engine dropped, when the widget authored one. */
700
+ droppedPosition?: [number, number];
701
+ }
702
+ /** Why a widget's rect is where it is. */
703
+ export interface GuiPlacement {
704
+ /** The final rect, the same one `GuiLayoutNode.rect` carries. */
705
+ rect: {
706
+ x: number;
707
+ y: number;
708
+ w: number;
709
+ h: number;
710
+ };
711
+ /** What the terms are measured against: the parent's content rect, or the
712
+ * viewport for a root widget. */
713
+ parentRect: {
714
+ x: number;
715
+ y: number;
716
+ w: number;
717
+ h: number;
718
+ };
719
+ /**
720
+ * The anchor terms, summing to the rect origin. EMPTY when `placedBy` is
721
+ * set: a layout container computes the slot, so there is no anchor sum to
722
+ * show.
723
+ */
724
+ terms: GuiPlacementTerm[];
725
+ placedBy?: GuiPlacedBy;
726
+ /**
727
+ * The innermost clipping ancestor (a scrollarea viewport, or any widget with
728
+ * `scissor = yes`), when one clips this widget. The rect is the clip rect,
729
+ * NOT the intersection: the geometry is true and the renderer clips.
730
+ */
731
+ clippedBy?: {
732
+ key: string;
733
+ name?: string;
734
+ rect: {
735
+ x: number;
736
+ y: number;
737
+ w: number;
738
+ h: number;
739
+ };
740
+ };
741
+ }
742
+ /**
743
+ * A texture the widget draws, with its frame-sheet grid when it is one. The
744
+ * sheet's pixel size comes from the DDS header alone (128 bytes read, no
745
+ * decode); `columns`/`rows`/`cell` need it, so they are absent when the file
746
+ * does not resolve under the configured roots.
747
+ *
748
+ * The grid is driven by `framesize`, the property the vanilla gui trees
749
+ * actually carry (both harvested titles ship it; neither ships `noofframes`).
750
+ */
751
+ export interface GuiTextureInfo {
752
+ /** The path as authored, mod-relative, the way the engine reads it. */
753
+ path: string;
754
+ /** Which fill it belongs to. */
755
+ source: "fill" | "background";
756
+ /** Absolute file it resolved to: mod, then parent mods (last first), then the game. */
757
+ file?: string;
758
+ /** Sheet pixel size from the DDS header. */
759
+ width?: number;
760
+ height?: number;
761
+ /** `framesize = { w h }`: the grid's cell size. */
762
+ framesize?: [number, number];
763
+ /** Grid shape, row-major: floor(width/cellW) x floor(height/cellH). */
764
+ columns?: number;
765
+ rows?: number;
766
+ /** The 1-based frame the widget shows (`frame`, default 1), clamped to the grid. */
767
+ frame?: number;
768
+ /** That frame's cell in texture pixels. */
769
+ cell?: {
770
+ x: number;
771
+ y: number;
772
+ w: number;
773
+ h: number;
774
+ };
775
+ }
776
+ export interface GuiWidgetInfo {
777
+ key: string;
778
+ name?: string;
779
+ /** The base-type chain the key resolves through, derived-most first. */
780
+ typeChain: string[];
781
+ /**
782
+ * Effective properties in expansion order, last-in-wins per key: exactly the
783
+ * values the engine laid the widget out with, so the inspector cannot show a
784
+ * row the canvas did not use.
785
+ */
786
+ properties: GuiWidgetProperty[];
787
+ /**
788
+ * Textures the widget draws (its own fill first, then its background), with
789
+ * frame-sheet geometry. `[]` when it draws none; absent only from a server
790
+ * that predates the field.
791
+ */
792
+ textures?: GuiTextureInfo[];
793
+ /**
794
+ * Why the widget's rect is where it is. Present only when the request asked
795
+ * for it (`placement: true`) AND the layout actually reached the widget: a
796
+ * declaration inside a `tooltipwidget` or a subtree the engine skips has a
797
+ * source line but no rect.
798
+ */
799
+ placement?: GuiPlacement;
800
+ }
801
+ /**
802
+ * Request: what a `.gui` document reaches on the SCRIPT side;
803
+ * {@link GuiDependenciesParams} -> {@link GuiDependenciesResult}. The forward
804
+ * half of the dependency surface; the reverse (script definition -> the .gui
805
+ * paths using it) is `paradox/dependencies` with `guiUses: true`, so both
806
+ * directions come out of the same scripted_gui link.
807
+ */
808
+ export declare const guiDependenciesRequest = "paradox/guiDependencies";
809
+ export interface GuiDependenciesParams {
810
+ /** For display only; the text is authoritative. */
811
+ uri: string;
812
+ text: string;
813
+ /**
814
+ * Restrict the answer to one widget's SOURCE subtree, addressed by the
815
+ * 0-based line of its own statement (`GuiLayoutNode.line`). Absent = the
816
+ * whole document. A line carrying no widget answers with empty lists.
817
+ */
818
+ line?: number;
819
+ }
820
+ /** A scripted_gui the document calls, and what it hands control to. */
821
+ export interface GuiScriptedGuiRow {
822
+ name: string;
823
+ /** Definition site; absent when the index has no scripted_gui by that name. */
824
+ file?: string;
825
+ line?: number;
826
+ /** 0-based lines in the REQUESTED document that call it. */
827
+ callLines: number[];
828
+ /** Call sites across every `.gui` file the layout store scanned. */
829
+ uses: number;
830
+ /** Events / on_actions the scripted_gui's own blocks hand control to. */
831
+ chains: GuiEventChain[];
832
+ }
833
+ /** An event or on_action a scripted_gui reaches, and how. */
834
+ export interface GuiEventChain {
835
+ name: string;
836
+ kind: "event" | "on_action";
837
+ file?: string;
838
+ line?: number;
839
+ /**
840
+ * The scripted effects traversed to get there, outermost first. Empty =
841
+ * "directly"; `["effect_a", "effect_b"]` renders as "via effect_a -> effect_b".
842
+ */
843
+ via: string[];
844
+ }
845
+ /** A localization key the document names, checked against the loc index. */
846
+ export interface GuiLocRow {
847
+ key: string;
848
+ /** The gui property that named it (`text`, `tooltip`). */
849
+ prop: string;
850
+ /** 0-based line in the requested document. */
851
+ line: number;
852
+ /** No `loc_key` definition anywhere in the index. */
853
+ missing: boolean;
854
+ /** The resolved text, when the index has one. */
855
+ value?: string;
856
+ }
857
+ export interface GuiDependenciesResult {
858
+ /** The widget the answer is scoped to; absent for a whole-document answer. */
859
+ widget?: {
860
+ key: string;
861
+ name?: string;
862
+ line: number;
863
+ };
864
+ scriptedGuis: GuiScriptedGuiRow[];
865
+ locKeys: GuiLocRow[];
866
+ }
867
+ /**
868
+ * Request: the widget names a designer palette may offer for THIS document;
869
+ * {@link GuiVocabularyParams} -> {@link GuiVocabularyResult}.
870
+ *
871
+ * Every name is harvested, never listed by hand: the bundled per-game widget
872
+ * schema (`data/<game>/guiSchema.json`, built from the vanilla `gui/` tree)
873
+ * plus the requested document's own `template` and `type` declarations. A
874
+ * palette entry is therefore always a widget the game knows.
875
+ */
876
+ export declare const guiVocabularyRequest = "paradox/guiVocabulary";
877
+ export interface GuiVocabularyParams {
878
+ /** For display only; the text is authoritative. */
879
+ uri: string;
880
+ text: string;
881
+ }
882
+ export interface GuiVocabularyEntry {
883
+ name: string;
884
+ /** `builtin` = the vanilla harvest; `type`/`template` = this document declares it. */
885
+ kind: "builtin" | "type" | "template";
886
+ /** How many times the vanilla gui tree writes it (`builtin` only). */
887
+ count?: number;
888
+ /** The base widget key a `type` derives from. */
889
+ base?: string;
890
+ /** Declared in the requested document itself. */
891
+ local?: boolean;
892
+ /**
893
+ * The vanilla tree writes widgets inside it, so it can hold children: what a
894
+ * "wrap in a container" menu offers. Derived from the harvest's own child
895
+ * counts, not from a list of container names.
896
+ */
897
+ container?: boolean;
898
+ }
899
+ export interface GuiVocabularyResult {
900
+ /**
901
+ * The document's own declarations first, then the harvested types by vanilla
902
+ * usage. Capped; `total` gives the real count, so a UI states what it hid.
903
+ */
904
+ entries: GuiVocabularyEntry[];
905
+ total: number;
906
+ /**
907
+ * Widget type -> the property names the harvest saw on it, most used first
908
+ * and capped: what an inspector's add-property row completes from. Only the
909
+ * types THIS DOCUMENT names are here (the keys it writes blocks under, plus
910
+ * the bases of its own `type X = base` declarations), because the harvest
911
+ * holds hundreds of types and this answer is re-asked after every layout.
912
+ * The server always sends it (empty for a game with no harvest); it is
913
+ * optional only so older recorded responses stay type-valid.
914
+ */
915
+ properties?: Record<string, string[]>;
916
+ /**
917
+ * The vanilla tree's most-used property names overall, most used first and
918
+ * capped: the fallback ranking for a widget whose type the harvest has never
919
+ * seen, so completion still offers something real rather than nothing.
920
+ */
921
+ commonProperties?: string[];
922
+ }
923
+ /**
924
+ * Render-ready previews of palette entries: one instance of each entry laid
925
+ * out in a synthetic document that keeps the requested document's own
926
+ * declarations (so a local template previews with its real base). The
927
+ * result is an ordinary node tree the client draws with the same painter as
928
+ * the canvas. Entries a synthetic document cannot stand up (nothing to show,
929
+ * zero size, a type the store lacks) come back with `node: null` and a
930
+ * `reason`. Capped per request (GUI_PREVIEW_MAX); ask for the visible page.
931
+ */
932
+ export declare const guiPreviewRequest = "paradox/guiPreview";
933
+ export declare const GUI_PREVIEW_MAX = 48;
934
+ export interface GuiPreviewEntry {
935
+ name: string;
936
+ /** `raw`: `fragment` is `.gui` text (a saved component) laid out as is. */
937
+ kind: "builtin" | "type" | "template" | "raw";
938
+ fragment?: string;
939
+ }
940
+ export interface GuiPreviewParams {
941
+ /** For display only; the text is authoritative. */
942
+ uri: string;
943
+ text: string;
944
+ entries: GuiPreviewEntry[];
945
+ }
946
+ export interface GuiPreview {
947
+ name: string;
948
+ node: GuiLayoutNode | null;
949
+ /** Texture paths the node tree references (mod-relative). */
950
+ textures: string[];
951
+ reason?: string;
952
+ }
953
+ export interface GuiPreviewResult {
954
+ previews: GuiPreview[];
955
+ }
956
+ /**
957
+ * Preview values read out of a save game, so a designer draws
958
+ * `[GetPlayer.GetName]` as "Great Britain" instead of a placeholder chip.
959
+ *
960
+ * `values` is keyed by datafunction chain WITHOUT brackets, exactly the shape
961
+ * {@link GuiLayoutParams.previewValues} takes, so a client hands the answer
962
+ * straight back to the next layout request. A chain the save has no field for
963
+ * is absent: a preview shows what is knowable and never invents a value.
964
+ *
965
+ * The server streams the file and parses only the few blocks it needs (a big
966
+ * campaign runs ~115 MB), and caches the answer per file and mtime.
967
+ * Ironman and binary saves are refused with `error` set; melting them is a
968
+ * different tool.
969
+ */
970
+ export declare const guiSaveValuesRequest = "paradox/guiSaveValues";
971
+ export interface GuiSaveValuesParams {
972
+ /** Absolute path to the save file. */
973
+ path: string;
974
+ }
975
+ export interface GuiSaveValuesResult {
976
+ /** Datafunction chain without brackets -> display text. */
977
+ values: Record<string, string>;
978
+ /** What the values came from, for a UI to name the save it is showing. */
979
+ source: {
980
+ /** The campaign's name as the save's meta data states it. */
981
+ name: string;
982
+ /** The in-game date, already formatted ("21 January 1836"). */
983
+ date: string;
984
+ /** The game the values were read for. */
985
+ game: string;
986
+ };
987
+ /** Set when the save cannot be read (ironman, binary, unreadable). */
988
+ error?: string;
989
+ }
990
+ /**
991
+ * Request: source edits for a `.gui` designer gesture;
992
+ * {@link GuiSourceEditParams} -> {@link GuiSourceEditResult}, null when the
993
+ * request itself makes no sense (an unknown op). The server never writes: it
994
+ * returns offsets into the text it was handed and the host applies them, which
995
+ * keeps undo, dirty state and the live preview in the editor (EMBEDDING.md,
996
+ * host-owns-text).
997
+ *
998
+ * Every edit is surgical, over the exact span the source model recorded, so
999
+ * untouched bytes stay byte-identical: comments, CRLF, tabs-vs-spaces and
1000
+ * single-line bodies all survive a write.
1001
+ */
1002
+ export declare const guiSourceEditRequest = "paradox/guiSourceEdit";
1003
+ export interface GuiSourceEditParams {
1004
+ /** For display only; the text is authoritative. */
1005
+ uri: string;
1006
+ /** Authoritative document text every offset refers to. */
1007
+ text: string;
1008
+ /** One op. Mutually exclusive with {@link ops}; sending both answers null. */
1009
+ op?: GuiSourceOp;
1010
+ /**
1011
+ * A BATCH: several ops computed against this one text and answered as one
1012
+ * edit set, which is what makes a multi-widget gesture one document change
1013
+ * and one undo step. Every op gets a verdict of its own in
1014
+ * {@link GuiSourceEditResult.results}, so a refusal is per op and the rest
1015
+ * still apply. Order matters: the ops are computed in the order given, and a
1016
+ * later one whose bytes a earlier one already changes is refused rather than
1017
+ * silently dropped.
1018
+ */
1019
+ ops?: GuiSourceOp[];
1020
+ }
1021
+ /** One surgical replacement: replace `[start, end)` with `newText`. */
1022
+ export interface GuiTextEdit {
1023
+ /** UTF-16 offsets into the request text. */
1024
+ start: number;
1025
+ end: number;
1026
+ newText: string;
1027
+ }
1028
+ /**
1029
+ * What to do. `line` is the 0-based line of the target widget's own statement,
1030
+ * the same `line` {@link GuiLayoutNode} reports; a node with no line of its own
1031
+ * (spliced in from a template or a type) has no source to edit and is refused.
1032
+ * `index` counts SOURCE children, not the template-expanded ones a preview
1033
+ * shows; out of range appends.
1034
+ */
1035
+ export type GuiSourceOp =
1036
+ /** Set or (with a null value) remove properties on one widget. */
1037
+ {
1038
+ kind: "setProperties";
1039
+ line: number;
1040
+ properties: {
1041
+ key: string;
1042
+ value: string | null;
1043
+ }[];
1044
+ }
1045
+ /** Move a source child of the widget on `line` from one index to another. */
1046
+ | {
1047
+ kind: "reorder";
1048
+ line: number;
1049
+ from: number;
1050
+ to: number;
1051
+ } | {
1052
+ kind: "insert";
1053
+ line: number;
1054
+ widget: GuiNewWidget;
1055
+ index?: number;
1056
+ }
1057
+ /** Paste `.gui` text as a child, re-indented for the destination. */
1058
+ | {
1059
+ kind: "insertRaw";
1060
+ line: number;
1061
+ fragment: string;
1062
+ index?: number;
1063
+ } | {
1064
+ kind: "delete";
1065
+ line: number;
1066
+ }
1067
+ /** Copy the widget in as its own next sibling, optionally renamed. */
1068
+ | {
1069
+ kind: "duplicate";
1070
+ line: number;
1071
+ name?: string;
1072
+ }
1073
+ /** Wrap the widgets on `lines` (siblings) in a fresh container. */
1074
+ | {
1075
+ kind: "wrap";
1076
+ lines: number[];
1077
+ container: GuiNewWidget;
1078
+ }
1079
+ /** Read-only: the widget's block, verbatim, for a clipboard. */
1080
+ | {
1081
+ kind: "blockText";
1082
+ line: number;
1083
+ };
1084
+ /** A declaration to write: `type = { properties }`, properties in order. */
1085
+ export interface GuiNewWidget {
1086
+ type: string;
1087
+ properties?: [string, string][];
1088
+ }
1089
+ /**
1090
+ * For a single `op`, exactly one of `edits` and `refused` is present. A refusal
1091
+ * is an ANSWER, not an error: it names why the gesture would not do what it
1092
+ * looks like it does (a box owns its children's slots, a content-sized type
1093
+ * ignores an explicit size, a type definition other files use). `warning` rides
1094
+ * along with a write that went ahead but is only half honoured.
1095
+ *
1096
+ * For a BATCH (`ops`), `results` is present with one entry per op in the same
1097
+ * order, `edits` is every applied op's edits together (apply them as ONE
1098
+ * change), and `warning` joins the warnings. Top-level `refused` then names
1099
+ * only a whole-request failure (a document that does not parse, an empty
1100
+ * batch): a per-op refusal lives in its own entry and does not stop the others.
1101
+ */
1102
+ export interface GuiSourceEditResult {
1103
+ edits?: GuiTextEdit[];
1104
+ refused?: string;
1105
+ warning?: string;
1106
+ /** `blockText` only: the copied block. */
1107
+ blockText?: string;
1108
+ /** Batch only: one verdict per requested op, in request order. */
1109
+ results?: GuiSourceOpResult[];
1110
+ }
1111
+ /** One op's own answer inside a batch. */
1112
+ export interface GuiSourceOpResult {
1113
+ /** Why this op wrote nothing. The others in the batch still applied. */
1114
+ refused?: string;
1115
+ /** This op wrote, and is only half honoured. */
1116
+ warning?: string;
1117
+ /** This op's contribution to the combined `edits`; empty when it wrote nothing. */
1118
+ edits: GuiTextEdit[];
1119
+ /** `blockText` only: the copied block. */
1120
+ blockText?: string;
1121
+ }
1122
+ /**
1123
+ * Request: text edit for a preview interaction (drag / property change);
1124
+ * {@link GuiWidgetEditParams} -> {@link GuiWidgetEditResult} (null when the
1125
+ * widget or property cannot be edited). The client applies the offsets via
1126
+ * WorkspaceEdit so undo and the live preview loop stay in the editor.
1127
+ *
1128
+ * @deprecated Use {@link guiSourceEditRequest} with a `setProperties` op. This
1129
+ * is a thin alias over the same core, kept for hosts already wired to it: it
1130
+ * can only write the `position`/`size` pair and returns one edit or null, so a
1131
+ * refusal reaches the caller as a bare null with no reason attached.
1132
+ */
1133
+ export declare const guiWidgetEditRequest = "paradox/guiWidgetEdit";
1134
+ export interface GuiWidgetEditParams {
1135
+ uri: string;
1136
+ /** Authoritative document text the offsets refer to. */
1137
+ text: string;
1138
+ /** 0-based line of the widget's instance statement (GuiLayoutNode.line). */
1139
+ line: number;
1140
+ /** Pair property to set. */
1141
+ property: "position" | "size";
1142
+ values: [number, number];
1143
+ }
1144
+ export interface GuiWidgetEditResult {
1145
+ /** UTF-16 offsets into the request text. */
1146
+ start: number;
1147
+ end: number;
1148
+ newText: string;
1149
+ }
1150
+ /** Request: event graph; {@link EventGraphParams} -> {@link EventGraph}. */
1151
+ export declare const eventGraphRequest = "paradox/eventGraph";
1152
+ export interface EventGraphParams {
1153
+ /** Focus definition (event id / on_action name); with namespace, either works. */
1154
+ root?: string;
1155
+ /** Restrict to an event namespace. */
1156
+ namespace?: string;
1157
+ /** Restrict to one workspace mod (absolute root path). */
1158
+ modRoot?: string | null;
1159
+ maxNodes?: number;
1160
+ /** Also read each mod event's `theme`. Off by default: it costs one parse per
1161
+ * event file, and only a client that draws the theme's art needs it. */
1162
+ themes?: boolean;
1163
+ }
1164
+ /**
1165
+ * One row of a mod event's card, in EXECUTION order (immediate, then the
1166
+ * options, then after) rather than file order. `line` is the join key an edge
1167
+ * uses to anchor at the row that fires it ({@link EventGraphEdge.fromLine}).
1168
+ */
1169
+ export interface EventGraphStep {
1170
+ phase: "immediate" | "option" | "after";
1171
+ /** Option ordinal within the event, 0-based. */
1172
+ index?: number;
1173
+ /** The option's localized text, when resolvable. */
1174
+ text?: string;
1175
+ /** 0-based line of the step's key in the event's file. */
1176
+ line: number;
1177
+ }
1178
+ export interface EventGraphNode {
1179
+ id: string;
1180
+ kind: string;
1181
+ source: "vanilla" | "parent" | "mod";
1182
+ file?: string;
1183
+ line?: number;
1184
+ /** Localized title (best-effort: <id>.t / <id>_t / <id>.title lookups). */
1185
+ title?: string;
1186
+ /** The event's declared `theme`, when the request asked for themes. */
1187
+ theme?: string;
1188
+ /** How many `option` blocks this definition has (mod-side definitions only). */
1189
+ options?: number;
1190
+ /** The first keys of its `trigger` block, e.g. `is_adult, has_trait…`; absent = no trigger. */
1191
+ triggerSummary?: string;
1192
+ /** How many other nodes of this graph it fires; absent when it fires none. */
1193
+ fires?: number;
1194
+ /** The card's rows (mod events only), capped; {@link EventGraphNode.options} is the true count. */
1195
+ steps?: EventGraphStep[];
1196
+ }
1197
+ export interface EventGraphEdge {
1198
+ from: string;
1199
+ to: string;
1200
+ /** The referencing field (trigger_event, events, on_actions...). */
1201
+ via: string;
1202
+ /** Where in the source event the reference sits: an option's text, or immediate/after/… */
1203
+ label?: string;
1204
+ /** The block the reference sits in, normalized (option/immediate/after/effect/…). */
1205
+ phase?: string;
1206
+ /** 0-based line of that block's key: matches a step's `line` on the source node. */
1207
+ fromLine?: number;
1208
+ /** The trigger_event delay at this site, pre-rendered short: "30d", "7–14d", "2mo", "1y". */
1209
+ delay?: string;
1210
+ /** random_events weight at this site (raw script number). */
1211
+ weight?: number;
1212
+ }
1213
+ /**
1214
+ * What a query box may offer: the whole mod-side vocabulary of the graph, NOT
1215
+ * the ids this particular query selected. It is the same pass that collects the
1216
+ * mod's graph definitions, so a client gets it without a second request.
1217
+ */
1218
+ export interface EventGraphSuggestions {
1219
+ /** Mod-side event / on_action / decision ids, sorted, capped at 2000. */
1220
+ ids: string[];
1221
+ /** The event namespaces those ids belong to, sorted. */
1222
+ namespaces: string[];
1223
+ }
1224
+ export interface EventGraph {
1225
+ nodes: EventGraphNode[];
1226
+ edges: EventGraphEdge[];
1227
+ truncated: boolean;
1228
+ /** Absent from servers that predate it; a client must tolerate that. */
1229
+ suggestions?: EventGraphSuggestions;
1230
+ /**
1231
+ * Set only when the graph is empty AND the server knows why: the queried
1232
+ * namespace/root exists, but outside what the graph shows (another workspace
1233
+ * mod when a focus filter is on, a dependency mod, or vanilla). One
1234
+ * user-readable sentence; absent = the generic "nothing found" story.
1235
+ */
1236
+ emptyReason?: string;
1237
+ }
1238
+ /**
1239
+ * Request: the value sets an event editor may offer; {@link EventVocabularyParams}
1240
+ * to {@link EventVocabularyResult}.
1241
+ *
1242
+ * Everything in the answer is DERIVED: the key lists come from the active
1243
+ * profile's structure table, the field value sets from the schema's reference
1244
+ * fields resolved through the definition index, and the effect/trigger lists
1245
+ * from the user's script_docs (or the bundled wiki fallback). Nothing here is a
1246
+ * hand-written name list, so a game patch that adds a theme or an effect shows
1247
+ * up without a release.
1248
+ */
1249
+ /**
1250
+ * Request: the illustration an event theme puts behind its window;
1251
+ * {@link EventBannerParams} to {@link EventBannerResult}.
1252
+ *
1253
+ * Resolved through the game's own two hops (event_themes -> event_backgrounds),
1254
+ * taking the last `background` block that carries no `trigger`, which is the
1255
+ * file's own unconditional fallback. `texture` is the engine's mod-relative
1256
+ * path, exactly as a `.gui` file would spell it, so a client resolves it with
1257
+ * the same mod-then-game lookup it uses for any other texture. A theme that
1258
+ * resolves to nothing answers `reason` instead: the caller is expected to say
1259
+ * so rather than draw a picture that is not the event's.
1260
+ */
1261
+ export declare const eventBannerRequest = "paradox/eventBanner";
1262
+ export interface EventBannerParams {
1263
+ /** Theme name as the event writes it (`theme = intrigue`). */
1264
+ theme: string;
1265
+ }
1266
+ export interface EventBannerResult {
1267
+ theme: string;
1268
+ /** Mod-relative texture path, absent when nothing resolved. */
1269
+ texture?: string;
1270
+ /** Why nothing resolved. Present exactly when `texture` is absent. */
1271
+ reason?: string;
1272
+ }
1273
+ export declare const eventVocabularyRequest = "paradox/eventVocabulary";
1274
+ export interface EventVocabularyParams {
1275
+ /** Restrict definition-backed value sets to one workspace mod (plus vanilla). */
1276
+ modRoot?: string | null;
1277
+ }
1278
+ /** One offerable value with the one-line docs an editor shows beside it. */
1279
+ export interface EventVocabularyItem {
1280
+ value: string;
1281
+ /** Documentation, capped. Empty when the source has none; never invented. */
1282
+ doc?: string;
1283
+ /** Dimmer right-hand label: where the value comes from (mod / vanilla / a kind). */
1284
+ hint?: string;
1285
+ }
1286
+ /** Caps: an editor lists a page at a time, and these ride on every open. */
1287
+ export declare const EVENT_VOCABULARY_MAX_TOKENS = 600;
1288
+ export declare const EVENT_VOCABULARY_MAX_VALUES = 400;
1289
+ /**
1290
+ * Request: the value set a VALUE belongs to, resolved through the definition
1291
+ * index; {@link EventValueOptionsParams} -> {@link EventValueOptionsResult} |
1292
+ * null. The static vocabulary maps a KEY to its values, which only works where
1293
+ * the schema knows the key's context (an event's or option's own fields). Deep
1294
+ * inside an effect tree the same key name means something else (`type` in
1295
+ * `random_secret` is a secret, not an event type), so there the editor asks
1296
+ * about the value it already has: `secret_cultivator` is an indexed `secret`,
1297
+ * and the answer is every secret the index knows. Null = the value resolves to
1298
+ * nothing enumerable; the editor falls back to a free input.
1299
+ */
1300
+ export declare const eventValueOptionsRequest = "paradox/eventValueOptions";
1301
+ export interface EventValueOptionsParams {
1302
+ value: string;
1303
+ /** Restrict mod-side entries to one workspace mod (plus vanilla/parents). */
1304
+ modRoot?: string | null;
1305
+ }
1306
+ export interface EventValueOptionsResult {
1307
+ /** The definition kind the value resolved to (trait, secret, faith…). */
1308
+ kind: string;
1309
+ /** Every indexed definition of that kind, mod entries first, capped. */
1310
+ items: EventVocabularyItem[];
1311
+ }
1312
+ export interface EventVocabularyResult {
1313
+ /** Keys valid at an event's top level, most used first. */
1314
+ eventKeys: EventVocabularyItem[];
1315
+ /** Keys valid inside an `option` block, most used first. */
1316
+ optionKeys: EventVocabularyItem[];
1317
+ /**
1318
+ * Key to the values that key accepts, for the keys whose value set is known:
1319
+ * a declared enumeration, or a reference field resolved through the index
1320
+ * (`theme` gives every indexed event_theme). Keys with a free value are absent.
1321
+ */
1322
+ values: Record<string, EventVocabularyItem[]>;
1323
+ /** Effect tokens, most used first, capped at EVENT_VOCABULARY_MAX_TOKENS. */
1324
+ effects: EventVocabularyItem[];
1325
+ /** Trigger tokens, same ordering and cap. */
1326
+ triggers: EventVocabularyItem[];
1327
+ /** Saved scopes the mod writes (`save_scope_as`), sorted. */
1328
+ savedScopes: EventVocabularyItem[];
1329
+ }
1330
+ /**
1331
+ * Request: dependency explorer for any indexed definition;
1332
+ * {@link DependenciesParams} -> {@link DependenciesResult}. Cursor-driven
1333
+ * (uri + position) or by name (optionally disambiguated by kind).
1334
+ */
1335
+ export declare const dependenciesRequest = "paradox/dependencies";
1336
+ export interface DependenciesParams {
1337
+ /** Resolve the definition under this cursor position. */
1338
+ uri?: string;
1339
+ position?: {
1340
+ line: number;
1341
+ character: number;
1342
+ };
1343
+ /** Fallback: look the definition up by name (optionally by kind). */
1344
+ name?: string;
1345
+ kind?: string;
1346
+ /**
1347
+ * Also resolve {@link DependenciesResult.guiUses}: the `.gui` call sites that
1348
+ * reach this definition through a scripted_gui. Off by default, it walks the
1349
+ * scripted_gui definitions that any .gui file calls, which the plain
1350
+ * dependency answer does not need.
1351
+ */
1352
+ guiUses?: boolean;
1353
+ }
1354
+ export interface DependencyDef {
1355
+ name: string;
1356
+ kind: string;
1357
+ file: string;
1358
+ /** 0-based. */
1359
+ line: number;
1360
+ }
1361
+ export interface DependencyItem {
1362
+ name: string;
1363
+ file: string;
1364
+ /** 0-based. */
1365
+ line: number;
1366
+ }
1367
+ export interface DependencyGroup {
1368
+ kind: string;
1369
+ items: DependencyItem[];
1370
+ }
1371
+ export interface DependenciesResult {
1372
+ /** The resolved definition, or null when nothing matches the cursor/name. */
1373
+ def: DependencyDef | null;
1374
+ /** Mod definitions/sites that reference `def` (mod files only; vanilla
1375
+ * references aren't indexed, AD-4). Grouped by the containing definition's
1376
+ * kind, else by file. */
1377
+ dependents: DependencyGroup[];
1378
+ /** Named definitions referenced inside `def`'s block, grouped by target kind. */
1379
+ dependencies: DependencyGroup[];
1380
+ /**
1381
+ * The GUI side of the same question, present only when `guiUses` was asked
1382
+ * for: which `.gui` files reach `def`, and through which scripted_gui. `[]`
1383
+ * is the honest "none found"; the field is absent when it was not requested.
1384
+ */
1385
+ guiUses?: GuiUseSite[];
1386
+ }
1387
+ /**
1388
+ * One `.gui` call site that reaches a script definition. The link is always a
1389
+ * scripted_gui: `.gui` invokes script through `GetScriptedGui('name')` and
1390
+ * nothing else, so the path is `file:line -> scripted_gui -> [effects] -> def`.
1391
+ */
1392
+ export interface GuiUseSite {
1393
+ /** Absolute path of the `.gui` file holding the call. */
1394
+ file: string;
1395
+ /** 0-based line of the `GetScriptedGui(...)` call. */
1396
+ line: number;
1397
+ /** The scripted_gui the call names. */
1398
+ scriptedGui: string;
1399
+ /**
1400
+ * The scripted effects between that scripted_gui and the definition,
1401
+ * outermost first. Empty means the scripted_gui's own blocks name it
1402
+ * ("directly"); `["effect_a", "effect_b"]` renders as
1403
+ * "via effect_a -> effect_b".
1404
+ */
1405
+ via: string[];
1406
+ }
1407
+ /**
1408
+ * Request: the inferred scope chain at a cursor position;
1409
+ * {@link ScopeAtParams} -> {@link ScopeAtResult} | null. Answers for OPEN
1410
+ * script documents only (the server reads the client's text, not the disk);
1411
+ * null means "not open / not a script document", which a status bar renders as
1412
+ * nothing rather than as an error.
1413
+ *
1414
+ * This is a read-out of the same inference completion, hover and inlay hints
1415
+ * run at a position: it ranks and annotates, never diagnoses, and never
1416
+ * asserts more than the derived link tables actually say.
1417
+ */
1418
+ export declare const scopeAtRequest = "paradox/scopeAt";
1419
+ export interface ScopeAtParams {
1420
+ uri: string;
1421
+ /** 0-based, as in LSP. */
1422
+ position: {
1423
+ line: number;
1424
+ character: number;
1425
+ };
1426
+ }
1427
+ /** One resolved step of the walk from the root scope down to the cursor. */
1428
+ export interface ScopeChainStep {
1429
+ /**
1430
+ * The key that produced the step: a link (`liege`), an iterator
1431
+ * (`every_vassal`), `root`/`prev`, a `scope:x` / `var:x` anchor, or a data
1432
+ * link abbreviated as `culture:…`. Absent on the FIRST step only, which is
1433
+ * the enclosing definition's root scope and comes from no key.
1434
+ */
1435
+ entryKeyword?: string;
1436
+ /** Scopes after this step; empty = unknown. */
1437
+ scopes: string[];
1438
+ }
1439
+ /** A saved scope visible in the document, with the type it resolves to. */
1440
+ export interface SavedScopeInfo {
1441
+ name: string;
1442
+ /** Scopes the name resolves to; empty = unknown. */
1443
+ scopes: string[];
1444
+ }
1445
+ export interface ScopeAtResult {
1446
+ /**
1447
+ * Scopes at the position. A SET, not one name: a link or iterator with
1448
+ * several documented output scopes stays ambiguous instead of guessing, and
1449
+ * an EMPTY array means unknown, which is a first-class answer here. Render
1450
+ * several as `a|b` and none as "unknown".
1451
+ */
1452
+ scopes: string[];
1453
+ /** The walk, outermost (root) first, one entry per scope-changing step. */
1454
+ chain: ScopeChainStep[];
1455
+ /**
1456
+ * Saved scopes visible in the document, name-sorted: every `save_scope_as` /
1457
+ * `save_scope_value_as` site in the file plus the engine-provided ambient
1458
+ * scopes of its definition kind. NOT flow-sensitive, a save further down
1459
+ * the file is listed too, matching what completion and hover already offer.
1460
+ */
1461
+ savedScopes: SavedScopeInfo[];
1462
+ }