@rohal12/spindle-lsp 0.15.4 → 0.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +108 -28
- package/dist/bin.js.map +3 -3
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -55,7 +55,7 @@ var VERSION;
|
|
|
55
55
|
var init_version = __esm({
|
|
56
56
|
"src/version.ts"() {
|
|
57
57
|
"use strict";
|
|
58
|
-
VERSION = false ? pkg.version : "0.15.
|
|
58
|
+
VERSION = false ? pkg.version : "0.15.5";
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
61
|
|
|
@@ -23448,6 +23448,7 @@ var init_passage_parser = __esm({
|
|
|
23448
23448
|
"StoryTitle",
|
|
23449
23449
|
"StoryBanner",
|
|
23450
23450
|
"StoryCaption",
|
|
23451
|
+
"StoryContext",
|
|
23451
23452
|
"StoryMenu",
|
|
23452
23453
|
"StoryInterface",
|
|
23453
23454
|
"StoryAuthor"
|
|
@@ -32580,11 +32581,27 @@ var init_workspace_model = __esm({
|
|
|
32580
32581
|
WorkspaceModel = class extends EventEmitter2 {
|
|
32581
32582
|
documents;
|
|
32582
32583
|
passages;
|
|
32583
|
-
|
|
32584
|
-
|
|
32585
|
-
|
|
32584
|
+
_macros;
|
|
32585
|
+
get macros() {
|
|
32586
|
+
this.ensureCurrent();
|
|
32587
|
+
return this._macros;
|
|
32588
|
+
}
|
|
32589
|
+
_variables;
|
|
32590
|
+
get variables() {
|
|
32591
|
+
this.ensureCurrent();
|
|
32592
|
+
return this._variables;
|
|
32593
|
+
}
|
|
32594
|
+
_widgets;
|
|
32595
|
+
get widgets() {
|
|
32596
|
+
this.ensureCurrent();
|
|
32597
|
+
return this._widgets;
|
|
32598
|
+
}
|
|
32586
32599
|
/** Every document's markup, read through Spindle's tooling API. */
|
|
32587
|
-
|
|
32600
|
+
_markup;
|
|
32601
|
+
get markup() {
|
|
32602
|
+
this.ensureCurrent();
|
|
32603
|
+
return this._markup;
|
|
32604
|
+
}
|
|
32588
32605
|
/** True after initialize() has completed (full workspace scan done). */
|
|
32589
32606
|
initialized = false;
|
|
32590
32607
|
/** The story format declared by StoryData, updated with the passages. */
|
|
@@ -32594,12 +32611,17 @@ var init_workspace_model = __esm({
|
|
|
32594
32611
|
* workspace root, else StoryData's `format-version`. Only a version below
|
|
32595
32612
|
* {@link MINIMUM_SPINDLE_VERSION} matters (it is reported, not emulated).
|
|
32596
32613
|
*/
|
|
32597
|
-
|
|
32614
|
+
_target;
|
|
32615
|
+
get target() {
|
|
32616
|
+
this.ensureCurrent();
|
|
32617
|
+
return this._target;
|
|
32618
|
+
}
|
|
32598
32619
|
workspaceRoot;
|
|
32599
32620
|
/** The version installed under the workspace root, read at startup and on refresh(). */
|
|
32600
32621
|
installedVersion;
|
|
32601
32622
|
/** The `format-version` StoryData declares. */
|
|
32602
32623
|
declaredVersion;
|
|
32624
|
+
analysisPending = false;
|
|
32603
32625
|
debounceTimer = null;
|
|
32604
32626
|
DEBOUNCE_MS = 200;
|
|
32605
32627
|
/** Bound listeners for cleanup in dispose(). */
|
|
@@ -32610,11 +32632,11 @@ var init_workspace_model = __esm({
|
|
|
32610
32632
|
super();
|
|
32611
32633
|
this.documents = new DocumentStore();
|
|
32612
32634
|
this.passages = new PassageIndex();
|
|
32613
|
-
this.
|
|
32635
|
+
this._macros = new MacroRegistry();
|
|
32614
32636
|
this.macros.onChange = () => this.markup?.invalidate();
|
|
32615
|
-
this.
|
|
32616
|
-
this.
|
|
32617
|
-
this.
|
|
32637
|
+
this._variables = new VariableTracker();
|
|
32638
|
+
this._widgets = new WidgetRegistry();
|
|
32639
|
+
this._markup = new MarkupIndex({
|
|
32618
32640
|
text: (uri) => this.documents.getText(uri),
|
|
32619
32641
|
passages: (uri) => this.passages.getPassagesInDocument(uri),
|
|
32620
32642
|
context: () => ({
|
|
@@ -32624,7 +32646,7 @@ var init_workspace_model = __esm({
|
|
|
32624
32646
|
});
|
|
32625
32647
|
this.workspaceRoot = config2?.workspaceRoot;
|
|
32626
32648
|
this.installedVersion = this.workspaceRoot ? readInstalledSpindleVersion(this.workspaceRoot) : void 0;
|
|
32627
|
-
this.
|
|
32649
|
+
this._target = resolveSpindleTarget(this.installedVersion);
|
|
32628
32650
|
this.macros.loadBuiltins();
|
|
32629
32651
|
this.macros.loadSupplements(macro_supplements_default);
|
|
32630
32652
|
this.onDocumentChanged = (uri) => this.handleDocumentChange(uri);
|
|
@@ -32656,7 +32678,8 @@ var init_workspace_model = __esm({
|
|
|
32656
32678
|
*/
|
|
32657
32679
|
refresh() {
|
|
32658
32680
|
if (this.workspaceRoot) this.installedVersion = readInstalledSpindleVersion(this.workspaceRoot);
|
|
32659
|
-
this.
|
|
32681
|
+
this.analysisPending = true;
|
|
32682
|
+
this.ensureCurrent();
|
|
32660
32683
|
this.scheduleModelReady();
|
|
32661
32684
|
}
|
|
32662
32685
|
/**
|
|
@@ -32680,6 +32703,7 @@ var init_workspace_model = __esm({
|
|
|
32680
32703
|
* undefined if no StoryData passage names one.
|
|
32681
32704
|
*/
|
|
32682
32705
|
get storyFormat() {
|
|
32706
|
+
this.ensureCurrent();
|
|
32683
32707
|
return this.format.name;
|
|
32684
32708
|
}
|
|
32685
32709
|
/**
|
|
@@ -32689,6 +32713,7 @@ var init_workspace_model = __esm({
|
|
|
32689
32713
|
* Spindle.
|
|
32690
32714
|
*/
|
|
32691
32715
|
isSpindleProject() {
|
|
32716
|
+
this.ensureCurrent();
|
|
32692
32717
|
return this.format.isSpindle;
|
|
32693
32718
|
}
|
|
32694
32719
|
/** Clean up listeners and timers. */
|
|
@@ -32702,25 +32727,23 @@ var init_workspace_model = __esm({
|
|
|
32702
32727
|
}
|
|
32703
32728
|
this.removeAllListeners();
|
|
32704
32729
|
}
|
|
32705
|
-
/**
|
|
32730
|
+
/** Index local headers immediately; defer expensive cross-document analysis. */
|
|
32706
32731
|
handleDocumentChange(uri) {
|
|
32707
32732
|
const text3 = this.documents.getText(uri);
|
|
32708
32733
|
if (text3 !== void 0 && !isMacroSource(uri)) {
|
|
32709
32734
|
this.passages.rebuild(uri, text3);
|
|
32710
32735
|
}
|
|
32711
|
-
this.
|
|
32712
|
-
this.cascade();
|
|
32736
|
+
this.analysisPending = true;
|
|
32713
32737
|
this.updateStoryFormat();
|
|
32714
32738
|
this.emit("documentChanged", uri);
|
|
32715
32739
|
this.emit("passagesUpdated", uri);
|
|
32716
32740
|
this.scheduleModelReady();
|
|
32717
32741
|
}
|
|
32718
|
-
/**
|
|
32742
|
+
/** Remove local indices immediately and schedule cross-document analysis. */
|
|
32719
32743
|
handleDocumentClose(uri) {
|
|
32720
32744
|
this.passages.remove(uri);
|
|
32721
|
-
this.
|
|
32722
|
-
this.
|
|
32723
|
-
this.cascade();
|
|
32745
|
+
this._variables.removeDocument(uri);
|
|
32746
|
+
this.analysisPending = true;
|
|
32724
32747
|
this.updateStoryFormat();
|
|
32725
32748
|
this.emit("documentClosed", uri);
|
|
32726
32749
|
this.emit("passagesUpdated", uri);
|
|
@@ -32734,14 +32757,21 @@ var init_workspace_model = __esm({
|
|
|
32734
32757
|
this.passages.rebuild(uri, text3);
|
|
32735
32758
|
}
|
|
32736
32759
|
}
|
|
32760
|
+
this.analysisPending = true;
|
|
32761
|
+
this.ensureCurrent();
|
|
32762
|
+
}
|
|
32763
|
+
/** Finish pending cross-document work once, before a feature reads the indices. */
|
|
32764
|
+
ensureCurrent() {
|
|
32765
|
+
if (!this.analysisPending) return;
|
|
32766
|
+
this.analysisPending = false;
|
|
32737
32767
|
this.refreshDiscoveredMacros();
|
|
32738
32768
|
this.cascade();
|
|
32739
32769
|
this.updateStoryFormat();
|
|
32740
32770
|
}
|
|
32741
32771
|
/**
|
|
32742
32772
|
* Re-read the story format from the StoryData passages after the passage
|
|
32743
|
-
* index changed, emitting 'storyFormatChanged' if it differs.
|
|
32744
|
-
* the
|
|
32773
|
+
* index changed, emitting 'storyFormatChanged' if it differs. Listeners
|
|
32774
|
+
* that read the analysis indices finish pending analysis through getters.
|
|
32745
32775
|
*/
|
|
32746
32776
|
updateStoryFormat() {
|
|
32747
32777
|
const format = resolveStoryFormat(storyDataFormats(
|
|
@@ -32763,7 +32793,8 @@ var init_workspace_model = __esm({
|
|
|
32763
32793
|
*/
|
|
32764
32794
|
refreshDiscoveredMacros() {
|
|
32765
32795
|
const found = [];
|
|
32766
|
-
|
|
32796
|
+
const init = [];
|
|
32797
|
+
for (const uri of this.documents.getUris().sort()) {
|
|
32767
32798
|
const text3 = this.documents.getText(uri);
|
|
32768
32799
|
if (!text3) continue;
|
|
32769
32800
|
if (isMacroSource(uri)) {
|
|
@@ -32777,10 +32808,11 @@ var init_workspace_model = __esm({
|
|
|
32777
32808
|
if (!isStoryInit && !isScript) continue;
|
|
32778
32809
|
lines ??= text3.split("\n");
|
|
32779
32810
|
const content2 = lines.slice(passage.headerEnd.end.line + 1, passage.range.end.line + 1).join("\n");
|
|
32780
|
-
found.push(...
|
|
32811
|
+
if (isScript) found.push(...discoverMacros(content2));
|
|
32812
|
+
else init.push(...storyInitMacros(content2));
|
|
32781
32813
|
}
|
|
32782
32814
|
}
|
|
32783
|
-
this.macros.setDiscoveredMacros(found);
|
|
32815
|
+
this.macros.setDiscoveredMacros([...found, ...init]);
|
|
32784
32816
|
}
|
|
32785
32817
|
/**
|
|
32786
32818
|
* Cascade: rescan variables and widgets based on current passages.
|
|
@@ -32794,7 +32826,7 @@ var init_workspace_model = __esm({
|
|
|
32794
32826
|
cascade() {
|
|
32795
32827
|
this.markup.invalidate();
|
|
32796
32828
|
this.declaredVersion = storyDataFormatVersion(this.passages.getAllPassages(), (uri) => this.documents.getText(uri));
|
|
32797
|
-
this.
|
|
32829
|
+
this._target = resolveSpindleTarget(this.installedVersion, this.declaredVersion);
|
|
32798
32830
|
const declarations = (name) => {
|
|
32799
32831
|
const passage = this.passages.getPassage(name);
|
|
32800
32832
|
return passage ? this.markup.get(passage.uri)?.passages.find((p) => p.passage === passage) : void 0;
|
|
@@ -32827,13 +32859,14 @@ var init_workspace_model = __esm({
|
|
|
32827
32859
|
const macros = this.macros.toolingMacros();
|
|
32828
32860
|
return [...macros, ...this.widgets.getAllWidgets().filter((widget) => !this.macros.getMacro(widget.name)).map((widget) => ({ name: widget.name, block: widget.block, subMacros: [], widget: widget.tooling }))];
|
|
32829
32861
|
}
|
|
32830
|
-
/**
|
|
32862
|
+
/** Coalesce analysis and diagnostics across a burst of document changes. */
|
|
32831
32863
|
scheduleModelReady() {
|
|
32832
32864
|
if (this.debounceTimer) {
|
|
32833
32865
|
clearTimeout(this.debounceTimer);
|
|
32834
32866
|
}
|
|
32835
32867
|
this.debounceTimer = setTimeout(() => {
|
|
32836
32868
|
this.debounceTimer = null;
|
|
32869
|
+
this.ensureCurrent();
|
|
32837
32870
|
this.emit("modelReady");
|
|
32838
32871
|
}, this.DEBOUNCE_MS);
|
|
32839
32872
|
}
|
|
@@ -34416,8 +34449,6 @@ var init_diagnostics = __esm({
|
|
|
34416
34449
|
}
|
|
34417
34450
|
};
|
|
34418
34451
|
ctx.workspace.on("modelReady", publishAll);
|
|
34419
|
-
ctx.workspace.on("storyFormatChanged", publishAll);
|
|
34420
|
-
ctx.workspace.on("documentChanged", publishFor);
|
|
34421
34452
|
ctx.workspace.on("documentClosed", (uri) => {
|
|
34422
34453
|
ctx.connection.sendDiagnostics({ uri, diagnostics: [] });
|
|
34423
34454
|
});
|
|
@@ -80061,6 +80092,7 @@ function computeRename(uri, position, newName, workspace) {
|
|
|
80061
80092
|
addEdit(declaration.uri, declaration.nameRange, escapePassageName(newName));
|
|
80062
80093
|
}
|
|
80063
80094
|
for (const { uri: refUri, ref: ref2, text: text3 } of refEdits) addEdit(refUri, ref2.range, text3);
|
|
80095
|
+
preserveEntryPassage(symbol2.name, newName, workspace, addEdit);
|
|
80064
80096
|
break;
|
|
80065
80097
|
}
|
|
80066
80098
|
case "variable": {
|
|
@@ -80133,6 +80165,54 @@ function computeRename(uri, position, newName, workspace) {
|
|
|
80133
80165
|
}
|
|
80134
80166
|
return edits;
|
|
80135
80167
|
}
|
|
80168
|
+
function preserveEntryPassage(oldName, newName, workspace, addEdit) {
|
|
80169
|
+
const storyData = workspace.passages.getPassages("StoryData");
|
|
80170
|
+
for (const declaration of storyData) {
|
|
80171
|
+
const passage = workspace.markup.get(declaration.uri).passages.find((p) => p.passage === declaration);
|
|
80172
|
+
let data2;
|
|
80173
|
+
try {
|
|
80174
|
+
data2 = JSON.parse(passage.content);
|
|
80175
|
+
if (!data2 || typeof data2 !== "object" || Array.isArray(data2)) throw new Error();
|
|
80176
|
+
} catch {
|
|
80177
|
+
throw new RenameError("Cannot preserve the entry passage: StoryData must contain a valid JSON object.").at(declaration.uri, declaration.nameRange);
|
|
80178
|
+
}
|
|
80179
|
+
const start = typeof data2.start === "string" && data2.start ? data2.start : "Start";
|
|
80180
|
+
if (start !== oldName) continue;
|
|
80181
|
+
if (Object.hasOwn(data2, "start") && typeof data2.start !== "string") {
|
|
80182
|
+
throw new RenameError("Cannot preserve the entry passage: StoryData.start must be a string.").at(declaration.uri, declaration.nameRange);
|
|
80183
|
+
}
|
|
80184
|
+
let depth = 0;
|
|
80185
|
+
let startValue = false;
|
|
80186
|
+
let replaced = false;
|
|
80187
|
+
lexJs(passage.content, {
|
|
80188
|
+
code(ch) {
|
|
80189
|
+
if (ch === "{" || ch === "[") depth++;
|
|
80190
|
+
if (ch === "}" || ch === "]") depth--;
|
|
80191
|
+
if (ch === ",") startValue = false;
|
|
80192
|
+
},
|
|
80193
|
+
literal(text3, index) {
|
|
80194
|
+
if (depth !== 1 || !text3.startsWith('"')) return;
|
|
80195
|
+
const isKey = /^\s*:/.test(passage.content.slice(index + text3.length));
|
|
80196
|
+
if (isKey) startValue = JSON.parse(text3) === "start";
|
|
80197
|
+
else if (startValue) {
|
|
80198
|
+
addEdit(declaration.uri, passage.range(index, index + text3.length), JSON.stringify(newName));
|
|
80199
|
+
replaced = true;
|
|
80200
|
+
}
|
|
80201
|
+
}
|
|
80202
|
+
});
|
|
80203
|
+
if (!replaced) {
|
|
80204
|
+
const index = passage.content.indexOf("{") + 1;
|
|
80205
|
+
addEdit(declaration.uri, passage.range(index, index), `"start":${JSON.stringify(newName)}${Object.keys(data2).length ? "," : ""}`);
|
|
80206
|
+
}
|
|
80207
|
+
}
|
|
80208
|
+
if (storyData.length === 0 && oldName === "Start") {
|
|
80209
|
+
const declaration = workspace.passages.getPassage(oldName);
|
|
80210
|
+
const doc = workspace.markup.get(declaration.uri);
|
|
80211
|
+
const end = doc.passages.at(-1).position(doc.passages.at(-1).content.length);
|
|
80212
|
+
const eol = doc.text.includes("\r\n") ? "\r\n" : "\n";
|
|
80213
|
+
addEdit(declaration.uri, { start: end, end }, `${eol}${eol}:: StoryData${eol}${JSON.stringify({ start: newName })}${eol}`);
|
|
80214
|
+
}
|
|
80215
|
+
}
|
|
80136
80216
|
function passageHeaderProblem(name) {
|
|
80137
80217
|
if (name.trim() === "") return "a passage name cannot be empty";
|
|
80138
80218
|
if (/[\r\n]/.test(name)) return "a passage header is a single line, so the name cannot contain a line break";
|