@rohal12/spindle-lsp 0.9.0 → 0.9.2
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 +1174 -529
- package/dist/bin.js.map +4 -4
- package/package.json +5 -2
package/dist/bin.js
CHANGED
|
@@ -3185,10 +3185,10 @@ var init_esm4 = __esm({
|
|
|
3185
3185
|
* Return a void Promise that resolves once the stream ends.
|
|
3186
3186
|
*/
|
|
3187
3187
|
async promise() {
|
|
3188
|
-
return new Promise((
|
|
3188
|
+
return new Promise((resolve4, reject) => {
|
|
3189
3189
|
this.on(DESTROYED, () => reject(new Error("stream destroyed")));
|
|
3190
3190
|
this.on("error", (er) => reject(er));
|
|
3191
|
-
this.on("end", () =>
|
|
3191
|
+
this.on("end", () => resolve4());
|
|
3192
3192
|
});
|
|
3193
3193
|
}
|
|
3194
3194
|
/**
|
|
@@ -3212,7 +3212,7 @@ var init_esm4 = __esm({
|
|
|
3212
3212
|
return Promise.resolve({ done: false, value: res });
|
|
3213
3213
|
if (this[EOF])
|
|
3214
3214
|
return stop();
|
|
3215
|
-
let
|
|
3215
|
+
let resolve4;
|
|
3216
3216
|
let reject;
|
|
3217
3217
|
const onerr = (er) => {
|
|
3218
3218
|
this.off("data", ondata);
|
|
@@ -3226,19 +3226,19 @@ var init_esm4 = __esm({
|
|
|
3226
3226
|
this.off("end", onend);
|
|
3227
3227
|
this.off(DESTROYED, ondestroy);
|
|
3228
3228
|
this.pause();
|
|
3229
|
-
|
|
3229
|
+
resolve4({ value, done: !!this[EOF] });
|
|
3230
3230
|
};
|
|
3231
3231
|
const onend = () => {
|
|
3232
3232
|
this.off("error", onerr);
|
|
3233
3233
|
this.off("data", ondata);
|
|
3234
3234
|
this.off(DESTROYED, ondestroy);
|
|
3235
3235
|
stop();
|
|
3236
|
-
|
|
3236
|
+
resolve4({ done: true, value: void 0 });
|
|
3237
3237
|
};
|
|
3238
3238
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
3239
3239
|
return new Promise((res2, rej) => {
|
|
3240
3240
|
reject = rej;
|
|
3241
|
-
|
|
3241
|
+
resolve4 = res2;
|
|
3242
3242
|
this.once(DESTROYED, ondestroy);
|
|
3243
3243
|
this.once("error", onerr);
|
|
3244
3244
|
this.once("end", onend);
|
|
@@ -4226,9 +4226,9 @@ var init_esm5 = __esm({
|
|
|
4226
4226
|
if (this.#asyncReaddirInFlight) {
|
|
4227
4227
|
await this.#asyncReaddirInFlight;
|
|
4228
4228
|
} else {
|
|
4229
|
-
let
|
|
4229
|
+
let resolve4 = () => {
|
|
4230
4230
|
};
|
|
4231
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
4231
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve4 = res);
|
|
4232
4232
|
try {
|
|
4233
4233
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
4234
4234
|
withFileTypes: true
|
|
@@ -4241,7 +4241,7 @@ var init_esm5 = __esm({
|
|
|
4241
4241
|
children.provisional = 0;
|
|
4242
4242
|
}
|
|
4243
4243
|
this.#asyncReaddirInFlight = void 0;
|
|
4244
|
-
|
|
4244
|
+
resolve4();
|
|
4245
4245
|
}
|
|
4246
4246
|
return children.slice(0, children.provisional);
|
|
4247
4247
|
}
|
|
@@ -6303,11 +6303,15 @@ function parsePassageHeader(line, lineNumber) {
|
|
|
6303
6303
|
nameRange
|
|
6304
6304
|
};
|
|
6305
6305
|
}
|
|
6306
|
-
|
|
6306
|
+
function isScriptOrStylesheetPassage(passage) {
|
|
6307
|
+
return passage.tags?.some((t) => CODE_PASSAGE_TAGS.has(t)) ?? false;
|
|
6308
|
+
}
|
|
6309
|
+
var passageHeaderRegex, CODE_PASSAGE_TAGS;
|
|
6307
6310
|
var init_passage_parser = __esm({
|
|
6308
6311
|
"src/core/parsing/passage-parser.ts"() {
|
|
6309
6312
|
"use strict";
|
|
6310
6313
|
passageHeaderRegex = /^(::\s+)(.*?)(\[.*?\]\s*)?(\{.*?\}\s*)?\r?$/;
|
|
6314
|
+
CODE_PASSAGE_TAGS = /* @__PURE__ */ new Set(["script", "stylesheet"]);
|
|
6311
6315
|
}
|
|
6312
6316
|
});
|
|
6313
6317
|
|
|
@@ -6339,6 +6343,7 @@ var init_passage_index = __esm({
|
|
|
6339
6343
|
// will be extended below
|
|
6340
6344
|
},
|
|
6341
6345
|
headerEnd: header.headerRange,
|
|
6346
|
+
nameRange: header.nameRange,
|
|
6342
6347
|
uri,
|
|
6343
6348
|
tags: header.tags.length > 0 ? header.tags : void 0,
|
|
6344
6349
|
meta: header.meta
|
|
@@ -6434,27 +6439,55 @@ var init_passage_index = __esm({
|
|
|
6434
6439
|
|
|
6435
6440
|
// src/core/workspace/macro-registry.ts
|
|
6436
6441
|
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
6437
|
-
import {
|
|
6438
|
-
import { dirname, join, parse as parsePath } from "node:path";
|
|
6442
|
+
import { dirname, join, resolve } from "node:path";
|
|
6439
6443
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
6444
|
+
function findRegistryPath(startDir) {
|
|
6445
|
+
const target = join("node_modules", "@rohal12", "spindle", "dist", "pkg", "macro-registry.json");
|
|
6446
|
+
let dir = resolve(startDir);
|
|
6447
|
+
for (; ; ) {
|
|
6448
|
+
const candidate = join(dir, target);
|
|
6449
|
+
if (existsSync(candidate)) return candidate;
|
|
6450
|
+
const parent = dirname(dir);
|
|
6451
|
+
if (parent === dir) return null;
|
|
6452
|
+
dir = parent;
|
|
6453
|
+
}
|
|
6454
|
+
}
|
|
6440
6455
|
var MacroRegistry;
|
|
6441
6456
|
var init_macro_registry = __esm({
|
|
6442
6457
|
"src/core/workspace/macro-registry.ts"() {
|
|
6443
6458
|
"use strict";
|
|
6444
6459
|
MacroRegistry = class {
|
|
6445
6460
|
macros = /* @__PURE__ */ new Map();
|
|
6461
|
+
/** Entries as they were before the current user config was applied (undefined = absent). */
|
|
6462
|
+
configSnapshot = /* @__PURE__ */ new Map();
|
|
6463
|
+
/** Tier 3: macros discovered from Story.defineMacro() calls, keyed by lowercase name. */
|
|
6464
|
+
discovered = /* @__PURE__ */ new Map();
|
|
6465
|
+
/** Tier 4: user config entries, kept so they can be re-applied over discovered macros. */
|
|
6466
|
+
configEntries = /* @__PURE__ */ new Map();
|
|
6467
|
+
/** Warnings collected during loadBuiltins for logging. */
|
|
6468
|
+
warnings = [];
|
|
6469
|
+
/** Path of the macro-registry.json the builtins were loaded from, if any. */
|
|
6470
|
+
builtinsPath = null;
|
|
6446
6471
|
/**
|
|
6447
6472
|
* Load built-in macro metadata from @rohal12/spindle's macro-registry.json.
|
|
6448
6473
|
* This is the base layer that provides name, block, subMacros, flags, source.
|
|
6474
|
+
*
|
|
6475
|
+
* The project's own Spindle is authoritative: the registry is resolved from
|
|
6476
|
+
* `workspaceRoot` first, and from this package's install location (a
|
|
6477
|
+
* development copy, or one installed for the peer dependency) only when the
|
|
6478
|
+
* workspace has none.
|
|
6449
6479
|
*/
|
|
6450
|
-
|
|
6451
|
-
warnings = [];
|
|
6452
|
-
loadBuiltins() {
|
|
6480
|
+
loadBuiltins(workspaceRoot) {
|
|
6453
6481
|
let builtinMacros = [];
|
|
6454
6482
|
try {
|
|
6455
6483
|
const thisDir = dirname(fileURLToPath3(import.meta.url));
|
|
6456
|
-
const registryPath =
|
|
6457
|
-
if (registryPath) {
|
|
6484
|
+
const registryPath = (workspaceRoot ? findRegistryPath(workspaceRoot) : null) ?? findRegistryPath(thisDir);
|
|
6485
|
+
if (!registryPath) {
|
|
6486
|
+
this.warnings.push(
|
|
6487
|
+
"macro-registry.json not found: install @rohal12/spindle in the project. Continuing with supplements only."
|
|
6488
|
+
);
|
|
6489
|
+
} else {
|
|
6490
|
+
this.builtinsPath = registryPath;
|
|
6458
6491
|
const raw = readFileSync2(registryPath, "utf-8");
|
|
6459
6492
|
const parsed = JSON.parse(raw);
|
|
6460
6493
|
if (!Array.isArray(parsed)) {
|
|
@@ -6499,10 +6532,67 @@ var init_macro_registry = __esm({
|
|
|
6499
6532
|
/**
|
|
6500
6533
|
* Overlay user config onto the registry.
|
|
6501
6534
|
* Same format as supplements; applied last so it wins.
|
|
6535
|
+
*
|
|
6536
|
+
* Replaces any previously loaded config: entries from the last call are
|
|
6537
|
+
* reverted first, so macros removed from the config disappear (or fall
|
|
6538
|
+
* back to their builtin/supplement definition).
|
|
6502
6539
|
*/
|
|
6503
6540
|
loadConfig(config2) {
|
|
6541
|
+
for (const [key, previous] of this.configSnapshot) {
|
|
6542
|
+
if (previous) {
|
|
6543
|
+
this.macros.set(key, previous);
|
|
6544
|
+
} else {
|
|
6545
|
+
this.macros.delete(key);
|
|
6546
|
+
}
|
|
6547
|
+
}
|
|
6548
|
+
this.configSnapshot.clear();
|
|
6549
|
+
this.configEntries.clear();
|
|
6550
|
+
for (const rawKey of Object.keys(config2)) {
|
|
6551
|
+
const key = rawKey.toLowerCase();
|
|
6552
|
+
if (!this.configSnapshot.has(key)) {
|
|
6553
|
+
const existing = this.macros.get(key);
|
|
6554
|
+
this.configSnapshot.set(key, existing ? { ...existing } : void 0);
|
|
6555
|
+
}
|
|
6556
|
+
this.configEntries.set(key, { ...this.configEntries.get(key), ...config2[rawKey] });
|
|
6557
|
+
}
|
|
6504
6558
|
this.mergeEntries(config2);
|
|
6505
6559
|
}
|
|
6560
|
+
/**
|
|
6561
|
+
* Replace the set of macros discovered from Story.defineMacro() calls.
|
|
6562
|
+
* Previously discovered definitions that are no longer present are dropped,
|
|
6563
|
+
* restoring whatever the other tiers define for that name.
|
|
6564
|
+
*
|
|
6565
|
+
* Mirrors Story.defineMacro(): a macro is a block when `block: true`, or
|
|
6566
|
+
* when it declares sub-macros and does not set `block: false`. Each
|
|
6567
|
+
* sub-macro becomes a known macro that may only appear inside its parent.
|
|
6568
|
+
*/
|
|
6569
|
+
setDiscoveredMacros(macros) {
|
|
6570
|
+
this.discovered.clear();
|
|
6571
|
+
for (const m of macros) {
|
|
6572
|
+
const subMacros = m.subMacros ?? [];
|
|
6573
|
+
this.discovered.set(m.name.toLowerCase(), {
|
|
6574
|
+
name: m.name,
|
|
6575
|
+
block: m.block === true || m.block !== false && subMacros.length > 0,
|
|
6576
|
+
subMacros,
|
|
6577
|
+
storeVar: m.storeVar,
|
|
6578
|
+
interpolate: m.interpolate,
|
|
6579
|
+
merged: m.merged,
|
|
6580
|
+
description: m.description,
|
|
6581
|
+
source: "user"
|
|
6582
|
+
});
|
|
6583
|
+
}
|
|
6584
|
+
for (const m of macros) {
|
|
6585
|
+
for (const sub of m.subMacros ?? []) {
|
|
6586
|
+
const key = sub.toLowerCase();
|
|
6587
|
+
const existing = this.discovered.get(key);
|
|
6588
|
+
if (existing) {
|
|
6589
|
+
existing.parents = [...existing.parents ?? [], m.name];
|
|
6590
|
+
} else {
|
|
6591
|
+
this.discovered.set(key, { name: sub, block: false, subMacros: [], source: "user", parents: [m.name] });
|
|
6592
|
+
}
|
|
6593
|
+
}
|
|
6594
|
+
}
|
|
6595
|
+
}
|
|
6506
6596
|
/** Add or replace a single macro entry. */
|
|
6507
6597
|
addMacro(info) {
|
|
6508
6598
|
const key = info.name.toLowerCase();
|
|
@@ -6524,51 +6614,54 @@ var init_macro_registry = __esm({
|
|
|
6524
6614
|
}
|
|
6525
6615
|
/** Get a macro by name (case-insensitive). */
|
|
6526
6616
|
getMacro(name) {
|
|
6527
|
-
return this.
|
|
6617
|
+
return this.resolve(name.toLowerCase());
|
|
6528
6618
|
}
|
|
6529
6619
|
/** Check if a macro is a block (container) macro. */
|
|
6530
6620
|
isBlock(name) {
|
|
6531
|
-
return this.
|
|
6621
|
+
return this.getMacro(name)?.block ?? false;
|
|
6532
6622
|
}
|
|
6533
6623
|
/** Check if a macro is a sub-macro (has parents). */
|
|
6534
6624
|
isSubMacro(name) {
|
|
6535
|
-
const info = this.
|
|
6625
|
+
const info = this.getMacro(name);
|
|
6536
6626
|
return info?.parents != null && info.parents.length > 0;
|
|
6537
6627
|
}
|
|
6538
6628
|
/** Get all registered macros. */
|
|
6539
6629
|
getAllMacros() {
|
|
6540
|
-
|
|
6630
|
+
const keys = /* @__PURE__ */ new Set([...this.macros.keys(), ...this.discovered.keys()]);
|
|
6631
|
+
return Array.from(keys, (key) => this.resolve(key));
|
|
6541
6632
|
}
|
|
6542
6633
|
/**
|
|
6543
|
-
*
|
|
6544
|
-
*
|
|
6634
|
+
* Compose the effective entry for a lowercase key: builtins/supplements/
|
|
6635
|
+
* config (stored in `macros`), overlaid by discovered metadata, with user
|
|
6636
|
+
* config re-applied on top so it keeps precedence.
|
|
6545
6637
|
*/
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
const
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
if (
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6638
|
+
resolve(key) {
|
|
6639
|
+
const base = this.macros.get(key);
|
|
6640
|
+
const found = this.discovered.get(key);
|
|
6641
|
+
if (!found) return base;
|
|
6642
|
+
const info = {
|
|
6643
|
+
...base,
|
|
6644
|
+
name: base?.name ?? found.name,
|
|
6645
|
+
block: found.block ?? base?.block ?? false,
|
|
6646
|
+
subMacros: found.subMacros?.length ? found.subMacros : base?.subMacros ?? [],
|
|
6647
|
+
source: "user",
|
|
6648
|
+
storeVar: found.storeVar ?? base?.storeVar,
|
|
6649
|
+
interpolate: found.interpolate ?? base?.interpolate,
|
|
6650
|
+
merged: found.merged ?? base?.merged,
|
|
6651
|
+
description: found.description ?? base?.description,
|
|
6652
|
+
// A discovered sub-macro may also belong to other (e.g. built-in) parents
|
|
6653
|
+
parents: found.parents ? [.../* @__PURE__ */ new Set([...base?.parents ?? [], ...found.parents])] : base?.parents
|
|
6654
|
+
};
|
|
6655
|
+
const config2 = this.configEntries.get(key);
|
|
6656
|
+
if (config2) {
|
|
6657
|
+
if (config2.description !== void 0) info.description = config2.description;
|
|
6658
|
+
if (config2.parameters !== void 0) info.parameters = config2.parameters;
|
|
6659
|
+
if (config2.children !== void 0) info.children = config2.children;
|
|
6660
|
+
if (config2.parents !== void 0) info.parents = config2.parents;
|
|
6661
|
+
if (config2.skipArgs !== void 0) info.skipArgs = config2.skipArgs;
|
|
6662
|
+
if (config2.container !== void 0) info.block = config2.container;
|
|
6570
6663
|
}
|
|
6571
|
-
return
|
|
6664
|
+
return info;
|
|
6572
6665
|
}
|
|
6573
6666
|
/** Merge a set of supplement/config entries into the registry. */
|
|
6574
6667
|
mergeEntries(entries) {
|
|
@@ -6647,6 +6740,17 @@ function inferLiteralType(expr) {
|
|
|
6647
6740
|
if (first === "{") return "object";
|
|
6648
6741
|
return "string";
|
|
6649
6742
|
}
|
|
6743
|
+
function declarationLocation(line, name, absLine, uri) {
|
|
6744
|
+
const start = line.length - line.trimStart().length;
|
|
6745
|
+
const location = {
|
|
6746
|
+
declarationRange: {
|
|
6747
|
+
start: { line: absLine, character: start },
|
|
6748
|
+
end: { line: absLine, character: start + 1 + name.length }
|
|
6749
|
+
}
|
|
6750
|
+
};
|
|
6751
|
+
if (uri !== void 0) location.declarationUri = uri;
|
|
6752
|
+
return location;
|
|
6753
|
+
}
|
|
6650
6754
|
var varRefRegex, transientRefRegex, EXCLUDED_PASSAGES, CLEAN_PATTERNS, ARRAY_MEMBERS, VariableTracker;
|
|
6651
6755
|
var init_variable_tracker = __esm({
|
|
6652
6756
|
"src/core/workspace/variable-tracker.ts"() {
|
|
@@ -6705,7 +6809,7 @@ var init_variable_tracker = __esm({
|
|
|
6705
6809
|
* Parse the StoryVariables passage content for declarations.
|
|
6706
6810
|
* Each line like `$name = value` becomes a declaration.
|
|
6707
6811
|
*/
|
|
6708
|
-
parseStoryVariables(content, contentStartLine = 0) {
|
|
6812
|
+
parseStoryVariables(content, contentStartLine = 0, uri) {
|
|
6709
6813
|
this.declared.clear();
|
|
6710
6814
|
this._hasStoryVariables = true;
|
|
6711
6815
|
this._nullDeclarations = [];
|
|
@@ -6717,9 +6821,10 @@ var init_variable_tracker = __esm({
|
|
|
6717
6821
|
if (!match2) continue;
|
|
6718
6822
|
const name = match2[1];
|
|
6719
6823
|
const expr = match2[2].trim();
|
|
6824
|
+
const absLine = contentStartLine + i;
|
|
6825
|
+
const location = declarationLocation(lines[i], name, absLine, uri);
|
|
6720
6826
|
if (expr === "null") {
|
|
6721
6827
|
const charIdx = lines[i].indexOf("null", lines[i].indexOf("="));
|
|
6722
|
-
const absLine = contentStartLine + i;
|
|
6723
6828
|
this._nullDeclarations.push({
|
|
6724
6829
|
name,
|
|
6725
6830
|
sigil: "$",
|
|
@@ -6728,10 +6833,10 @@ var init_variable_tracker = __esm({
|
|
|
6728
6833
|
end: { line: absLine, character: charIdx + 4 }
|
|
6729
6834
|
}
|
|
6730
6835
|
});
|
|
6731
|
-
this.declared.set(name, { name, sigil: "$" });
|
|
6836
|
+
this.declared.set(name, { name, sigil: "$", ...location });
|
|
6732
6837
|
continue;
|
|
6733
6838
|
}
|
|
6734
|
-
const decl = { name, sigil: "$" };
|
|
6839
|
+
const decl = { name, sigil: "$", ...location };
|
|
6735
6840
|
const type = inferLiteralType(expr);
|
|
6736
6841
|
if (type) decl.type = type;
|
|
6737
6842
|
if (expr.startsWith("{")) {
|
|
@@ -6748,11 +6853,23 @@ var init_variable_tracker = __esm({
|
|
|
6748
6853
|
this.declared.set(name, decl);
|
|
6749
6854
|
}
|
|
6750
6855
|
}
|
|
6856
|
+
/** Forget StoryVariables declarations, e.g. after the passage was removed. */
|
|
6857
|
+
clearStoryVariables() {
|
|
6858
|
+
this.declared.clear();
|
|
6859
|
+
this._hasStoryVariables = false;
|
|
6860
|
+
this._nullDeclarations = [];
|
|
6861
|
+
}
|
|
6862
|
+
/** Forget StoryTransients declarations, e.g. after the passage was removed. */
|
|
6863
|
+
clearStoryTransients() {
|
|
6864
|
+
this.declaredTransient.clear();
|
|
6865
|
+
this._hasStoryTransients = false;
|
|
6866
|
+
this._nullTransientDeclarations = [];
|
|
6867
|
+
}
|
|
6751
6868
|
/**
|
|
6752
6869
|
* Parse the StoryTransients passage content for declarations.
|
|
6753
6870
|
* Each line like `%name = value` becomes a declaration.
|
|
6754
6871
|
*/
|
|
6755
|
-
parseStoryTransients(content, contentStartLine = 0) {
|
|
6872
|
+
parseStoryTransients(content, contentStartLine = 0, uri) {
|
|
6756
6873
|
this.declaredTransient.clear();
|
|
6757
6874
|
this._hasStoryTransients = true;
|
|
6758
6875
|
this._nullTransientDeclarations = [];
|
|
@@ -6764,9 +6881,10 @@ var init_variable_tracker = __esm({
|
|
|
6764
6881
|
if (!match2) continue;
|
|
6765
6882
|
const name = match2[1];
|
|
6766
6883
|
const expr = match2[2].trim();
|
|
6884
|
+
const absLine = contentStartLine + i;
|
|
6885
|
+
const location = declarationLocation(lines[i], name, absLine, uri);
|
|
6767
6886
|
if (expr === "null") {
|
|
6768
6887
|
const charIdx = lines[i].indexOf("null", lines[i].indexOf("="));
|
|
6769
|
-
const absLine = contentStartLine + i;
|
|
6770
6888
|
this._nullTransientDeclarations.push({
|
|
6771
6889
|
name,
|
|
6772
6890
|
sigil: "%",
|
|
@@ -6775,10 +6893,10 @@ var init_variable_tracker = __esm({
|
|
|
6775
6893
|
end: { line: absLine, character: charIdx + 4 }
|
|
6776
6894
|
}
|
|
6777
6895
|
});
|
|
6778
|
-
this.declaredTransient.set(name, { name, sigil: "%" });
|
|
6896
|
+
this.declaredTransient.set(name, { name, sigil: "%", ...location });
|
|
6779
6897
|
continue;
|
|
6780
6898
|
}
|
|
6781
|
-
const decl = { name, sigil: "%" };
|
|
6899
|
+
const decl = { name, sigil: "%", ...location };
|
|
6782
6900
|
const type = inferLiteralType(expr);
|
|
6783
6901
|
if (type) decl.type = type;
|
|
6784
6902
|
if (expr.startsWith("{")) {
|
|
@@ -6809,19 +6927,20 @@ var init_variable_tracker = __esm({
|
|
|
6809
6927
|
for (let i = 0; i < lines.length; i++) {
|
|
6810
6928
|
const header = parsePassageHeader(lines[i], i);
|
|
6811
6929
|
if (header) {
|
|
6812
|
-
passageBoundaries.push({ name: header.name, startLine: i });
|
|
6930
|
+
passageBoundaries.push({ name: header.name, tags: header.tags, startLine: i });
|
|
6813
6931
|
}
|
|
6814
6932
|
}
|
|
6815
6933
|
for (let pi = 0; pi < passageBoundaries.length; pi++) {
|
|
6816
6934
|
const passage = passageBoundaries[pi];
|
|
6817
6935
|
if (EXCLUDED_PASSAGES.has(passage.name)) continue;
|
|
6936
|
+
if (isScriptOrStylesheetPassage(passage)) continue;
|
|
6818
6937
|
const contentStartLine = passage.startLine + 1;
|
|
6819
6938
|
const contentEndLine = pi + 1 < passageBoundaries.length ? passageBoundaries[pi + 1].startLine : lines.length;
|
|
6820
6939
|
const contentLines = lines.slice(contentStartLine, contentEndLine);
|
|
6821
6940
|
const content = contentLines.join("\n");
|
|
6822
6941
|
let cleaned = content;
|
|
6823
6942
|
for (const pattern of CLEAN_PATTERNS) {
|
|
6824
|
-
cleaned = cleaned.replace(pattern, (m) => " "
|
|
6943
|
+
cleaned = cleaned.replace(pattern, (m) => m.replace(/[^\r\n]/g, " "));
|
|
6825
6944
|
}
|
|
6826
6945
|
const lineOffsets = [0];
|
|
6827
6946
|
for (let i = 0; i < cleaned.length; i++) {
|
|
@@ -6976,14 +7095,114 @@ var init_variable_tracker = __esm({
|
|
|
6976
7095
|
}
|
|
6977
7096
|
});
|
|
6978
7097
|
|
|
7098
|
+
// src/core/parsing/macro-parser.ts
|
|
7099
|
+
function buildLineStarts(text) {
|
|
7100
|
+
const starts = [0];
|
|
7101
|
+
for (let i = 0; i < text.length; i++) {
|
|
7102
|
+
if (text[i] === "\n") {
|
|
7103
|
+
starts.push(i + 1);
|
|
7104
|
+
}
|
|
7105
|
+
}
|
|
7106
|
+
return starts;
|
|
7107
|
+
}
|
|
7108
|
+
function offsetToPosition(offset, lineStarts) {
|
|
7109
|
+
let low = 0;
|
|
7110
|
+
let high = lineStarts.length - 1;
|
|
7111
|
+
while (low < high) {
|
|
7112
|
+
const mid = low + high + 1 >> 1;
|
|
7113
|
+
if (lineStarts[mid] <= offset) {
|
|
7114
|
+
low = mid;
|
|
7115
|
+
} else {
|
|
7116
|
+
high = mid - 1;
|
|
7117
|
+
}
|
|
7118
|
+
}
|
|
7119
|
+
return { line: low, character: offset - lineStarts[low] };
|
|
7120
|
+
}
|
|
7121
|
+
function parseMacros(text) {
|
|
7122
|
+
const cleaned = text.replace(variableInterpolationRegex, (match3) => {
|
|
7123
|
+
return " ".repeat(match3.length);
|
|
7124
|
+
});
|
|
7125
|
+
const lineStarts = buildLineStarts(text);
|
|
7126
|
+
const macros = [];
|
|
7127
|
+
let id = 0;
|
|
7128
|
+
macroRegex.lastIndex = 0;
|
|
7129
|
+
let match2;
|
|
7130
|
+
while ((match2 = macroRegex.exec(cleaned)) !== null) {
|
|
7131
|
+
const closeSlash = match2[1];
|
|
7132
|
+
const cssPrefix = (match2[2] || "").trim();
|
|
7133
|
+
const macroName = match2[3];
|
|
7134
|
+
const rawArgs = match2[4];
|
|
7135
|
+
const open = closeSlash !== "/";
|
|
7136
|
+
const matchStart = match2.index;
|
|
7137
|
+
const matchEnd = matchStart + match2[0].length;
|
|
7138
|
+
const startPos = offsetToPosition(matchStart, lineStarts);
|
|
7139
|
+
const endPos = offsetToPosition(matchEnd, lineStarts);
|
|
7140
|
+
const range2 = {
|
|
7141
|
+
start: startPos,
|
|
7142
|
+
end: endPos
|
|
7143
|
+
};
|
|
7144
|
+
macros.push({
|
|
7145
|
+
id,
|
|
7146
|
+
pair: -1,
|
|
7147
|
+
name: macroName,
|
|
7148
|
+
open,
|
|
7149
|
+
range: range2,
|
|
7150
|
+
cssPrefix: cssPrefix || void 0,
|
|
7151
|
+
rawArgs: rawArgs || void 0
|
|
7152
|
+
});
|
|
7153
|
+
id++;
|
|
7154
|
+
}
|
|
7155
|
+
return macros;
|
|
7156
|
+
}
|
|
7157
|
+
function pairMacros(macros, isBlock, passageStartLines = []) {
|
|
7158
|
+
const boundaries = [...passageStartLines].sort((a, b) => a - b);
|
|
7159
|
+
let nextBoundary = 0;
|
|
7160
|
+
let stack = [];
|
|
7161
|
+
for (const macro of macros) {
|
|
7162
|
+
let crossed = false;
|
|
7163
|
+
while (nextBoundary < boundaries.length && macro.range.start.line >= boundaries[nextBoundary]) {
|
|
7164
|
+
nextBoundary++;
|
|
7165
|
+
crossed = true;
|
|
7166
|
+
}
|
|
7167
|
+
if (crossed) stack = [];
|
|
7168
|
+
if (!isBlock(macro.name)) continue;
|
|
7169
|
+
if (macro.open) {
|
|
7170
|
+
stack.push(macro);
|
|
7171
|
+
continue;
|
|
7172
|
+
}
|
|
7173
|
+
const name = macro.name.toLowerCase();
|
|
7174
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
7175
|
+
if (stack[i].name.toLowerCase() === name) {
|
|
7176
|
+
const opener = stack[i];
|
|
7177
|
+
opener.pair = macro.id;
|
|
7178
|
+
macro.pair = opener.id;
|
|
7179
|
+
stack.length = i;
|
|
7180
|
+
break;
|
|
7181
|
+
}
|
|
7182
|
+
}
|
|
7183
|
+
}
|
|
7184
|
+
}
|
|
7185
|
+
var variableInterpolationRegex, macroRegex;
|
|
7186
|
+
var init_macro_parser = __esm({
|
|
7187
|
+
"src/core/parsing/macro-parser.ts"() {
|
|
7188
|
+
"use strict";
|
|
7189
|
+
variableInterpolationRegex = /(?<!\\)\{([$_@%][A-Za-z_$][\w$.]*)\}/g;
|
|
7190
|
+
macroRegex = /(?<!\\)\{(\/)?(?:((?:[#.][a-zA-Z][\w-]*\s*)*)([A-Za-z][\w-]*))(?:\s+((?:(?:`(?:\\.|[^`\\])*?`)|(?:"(?:\\.|[^"\\])*?")|(?:'(?:\\.|[^'\\])*?')|(?:\[(?:[<>]?[Ii][Mm][Gg])?\[[^\r\n]*?\]\]+)|[^}]|(?:}))*?))?\}/gmi;
|
|
7191
|
+
}
|
|
7192
|
+
});
|
|
7193
|
+
|
|
6979
7194
|
// src/core/workspace/widget-registry.ts
|
|
6980
|
-
|
|
7195
|
+
function parseParams(argString) {
|
|
7196
|
+
return argString.trim().split(/\s+/).filter((t) => /^[$_@]/.test(t) && t !== "@children");
|
|
7197
|
+
}
|
|
7198
|
+
var widgetDefRegex, WidgetRegistry;
|
|
6981
7199
|
var init_widget_registry = __esm({
|
|
6982
7200
|
"src/core/workspace/widget-registry.ts"() {
|
|
6983
7201
|
"use strict";
|
|
6984
|
-
|
|
6985
|
-
|
|
7202
|
+
init_macro_parser();
|
|
7203
|
+
widgetDefRegex = /(\{widget\s+["']?)([^\s"'}]+)["']?([^}]*)\}/gi;
|
|
6986
7204
|
WidgetRegistry = class {
|
|
7205
|
+
/** Widgets keyed by lower-cased name; Spindle resolves widgets case-insensitively. */
|
|
6987
7206
|
widgets = /* @__PURE__ */ new Map();
|
|
6988
7207
|
/** Per-URI set of lower-cased macro names opened in that document. */
|
|
6989
7208
|
invokedByUri = /* @__PURE__ */ new Map();
|
|
@@ -7009,40 +7228,43 @@ var init_widget_registry = __esm({
|
|
|
7009
7228
|
break;
|
|
7010
7229
|
}
|
|
7011
7230
|
}
|
|
7012
|
-
const
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7231
|
+
const content = lines.slice(contentStartLine, contentEndLine).join("\n");
|
|
7232
|
+
const lineStarts = buildLineStarts(content);
|
|
7233
|
+
const toPosition = (offset) => {
|
|
7234
|
+
const pos = offsetToPosition(offset, lineStarts);
|
|
7235
|
+
return { line: contentStartLine + pos.line, character: pos.character };
|
|
7236
|
+
};
|
|
7237
|
+
widgetDefRegex.lastIndex = 0;
|
|
7238
|
+
let match2;
|
|
7239
|
+
while ((match2 = widgetDefRegex.exec(content)) !== null) {
|
|
7240
|
+
const widgetName = match2[2];
|
|
7241
|
+
const nameStart = match2.index + match2[1].length;
|
|
7242
|
+
const range2 = {
|
|
7243
|
+
start: toPosition(match2.index),
|
|
7244
|
+
end: toPosition(match2.index + match2[0].length)
|
|
7245
|
+
};
|
|
7246
|
+
const nameRange = {
|
|
7247
|
+
start: toPosition(nameStart),
|
|
7248
|
+
end: toPosition(nameStart + widgetName.length)
|
|
7249
|
+
};
|
|
7250
|
+
const bodyStart = match2.index + match2[0].length;
|
|
7251
|
+
const rest = content.slice(bodyStart);
|
|
7252
|
+
const closeIdx = rest.search(/\{\/widget\}/i);
|
|
7253
|
+
const body = closeIdx >= 0 ? rest.slice(0, closeIdx) : rest;
|
|
7254
|
+
this.widgets.set(widgetName.toLowerCase(), {
|
|
7255
|
+
name: widgetName,
|
|
7256
|
+
params: parseParams(match2[3]),
|
|
7257
|
+
uri: passage.uri,
|
|
7258
|
+
range: range2,
|
|
7259
|
+
nameRange,
|
|
7260
|
+
block: /\{@children\}/.test(body)
|
|
7261
|
+
});
|
|
7040
7262
|
}
|
|
7041
7263
|
}
|
|
7042
7264
|
}
|
|
7043
|
-
/** Get a widget definition by name. */
|
|
7265
|
+
/** Get a widget definition by name (case-insensitive). */
|
|
7044
7266
|
getWidget(name) {
|
|
7045
|
-
return this.widgets.get(name);
|
|
7267
|
+
return this.widgets.get(name.toLowerCase());
|
|
7046
7268
|
}
|
|
7047
7269
|
/** Get all registered widget definitions. */
|
|
7048
7270
|
getAllWidgets() {
|
|
@@ -7076,89 +7298,111 @@ var init_widget_registry = __esm({
|
|
|
7076
7298
|
}
|
|
7077
7299
|
});
|
|
7078
7300
|
|
|
7079
|
-
// src/core/parsing/macro-
|
|
7080
|
-
function
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7301
|
+
// src/core/parsing/macro-discovery.ts
|
|
7302
|
+
function extractBalancedBraces(source, start) {
|
|
7303
|
+
let depth = 0;
|
|
7304
|
+
let inSingleQuote = false;
|
|
7305
|
+
let inDoubleQuote = false;
|
|
7306
|
+
let inBacktick = false;
|
|
7307
|
+
for (let i = start; i < source.length; i++) {
|
|
7308
|
+
const ch = source[i];
|
|
7309
|
+
const prev = i > start ? source[i - 1] : "";
|
|
7310
|
+
if (prev === "\\") continue;
|
|
7311
|
+
if (inSingleQuote) {
|
|
7312
|
+
if (ch === "'") inSingleQuote = false;
|
|
7313
|
+
continue;
|
|
7314
|
+
}
|
|
7315
|
+
if (inDoubleQuote) {
|
|
7316
|
+
if (ch === '"') inDoubleQuote = false;
|
|
7317
|
+
continue;
|
|
7318
|
+
}
|
|
7319
|
+
if (inBacktick) {
|
|
7320
|
+
if (ch === "`") inBacktick = false;
|
|
7321
|
+
continue;
|
|
7322
|
+
}
|
|
7323
|
+
if (ch === "'") {
|
|
7324
|
+
inSingleQuote = true;
|
|
7325
|
+
} else if (ch === '"') {
|
|
7326
|
+
inDoubleQuote = true;
|
|
7327
|
+
} else if (ch === "`") {
|
|
7328
|
+
inBacktick = true;
|
|
7329
|
+
} else if (ch === "{") {
|
|
7330
|
+
depth++;
|
|
7331
|
+
} else if (ch === "}") {
|
|
7332
|
+
depth--;
|
|
7333
|
+
if (depth === 0) {
|
|
7334
|
+
return source.slice(start, i + 1);
|
|
7335
|
+
}
|
|
7085
7336
|
}
|
|
7086
7337
|
}
|
|
7087
|
-
return
|
|
7338
|
+
return null;
|
|
7088
7339
|
}
|
|
7089
|
-
function
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7340
|
+
function parseConfigFields(config2) {
|
|
7341
|
+
const nameMatch = config2.match(/name:\s*['"]([^'"]+)['"]/);
|
|
7342
|
+
if (!nameMatch) return null;
|
|
7343
|
+
const macro = {
|
|
7344
|
+
name: nameMatch[1]
|
|
7345
|
+
};
|
|
7346
|
+
const boolFields = [
|
|
7347
|
+
"block",
|
|
7348
|
+
"storeVar",
|
|
7349
|
+
"merged",
|
|
7350
|
+
"interpolate"
|
|
7351
|
+
];
|
|
7352
|
+
for (const field of boolFields) {
|
|
7353
|
+
const re = new RegExp(`${field}:\\s*(true|false)`);
|
|
7354
|
+
const m = config2.match(re);
|
|
7355
|
+
if (m) {
|
|
7356
|
+
macro[field] = m[1] === "true";
|
|
7098
7357
|
}
|
|
7099
7358
|
}
|
|
7100
|
-
|
|
7359
|
+
const descMatch = config2.match(/description:\s*['"]([^'"]+)['"]/);
|
|
7360
|
+
if (descMatch) {
|
|
7361
|
+
macro.description = descMatch[1];
|
|
7362
|
+
}
|
|
7363
|
+
const subMatch = config2.match(/subMacros:\s*\[([^\]]*)\]/);
|
|
7364
|
+
if (subMatch) {
|
|
7365
|
+
const inner = subMatch[1].trim();
|
|
7366
|
+
if (inner) {
|
|
7367
|
+
macro.subMacros = inner.split(",").map(
|
|
7368
|
+
(s) => s.trim().replace(/^['"]|['"]$/g, "")
|
|
7369
|
+
).filter((s) => s.length > 0);
|
|
7370
|
+
}
|
|
7371
|
+
}
|
|
7372
|
+
return macro;
|
|
7101
7373
|
}
|
|
7102
|
-
function
|
|
7103
|
-
const cleaned = text.replace(variableInterpolationRegex, (match3) => {
|
|
7104
|
-
return " ".repeat(match3.length);
|
|
7105
|
-
});
|
|
7106
|
-
const lineStarts = buildLineStarts(text);
|
|
7374
|
+
function discoverMacrosFromSource(source) {
|
|
7107
7375
|
const macros = [];
|
|
7108
|
-
|
|
7109
|
-
macroRegex.lastIndex = 0;
|
|
7376
|
+
defineMacroRegex.lastIndex = 0;
|
|
7110
7377
|
let match2;
|
|
7111
|
-
while ((match2 =
|
|
7112
|
-
const
|
|
7113
|
-
const
|
|
7114
|
-
|
|
7115
|
-
const
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
const startPos = offsetToPosition(matchStart, lineStarts);
|
|
7120
|
-
const endPos = offsetToPosition(matchEnd, lineStarts);
|
|
7121
|
-
const range2 = {
|
|
7122
|
-
start: startPos,
|
|
7123
|
-
end: endPos
|
|
7124
|
-
};
|
|
7125
|
-
macros.push({
|
|
7126
|
-
id,
|
|
7127
|
-
pair: -1,
|
|
7128
|
-
name: macroName,
|
|
7129
|
-
open,
|
|
7130
|
-
range: range2,
|
|
7131
|
-
cssPrefix: cssPrefix || void 0,
|
|
7132
|
-
rawArgs: rawArgs || void 0
|
|
7133
|
-
});
|
|
7134
|
-
id++;
|
|
7378
|
+
while ((match2 = defineMacroRegex.exec(source)) !== null) {
|
|
7379
|
+
const braceStart = match2.index + match2[0].length - 1;
|
|
7380
|
+
const config2 = extractBalancedBraces(source, braceStart);
|
|
7381
|
+
if (!config2) continue;
|
|
7382
|
+
const macro = parseConfigFields(config2);
|
|
7383
|
+
if (macro) {
|
|
7384
|
+
macros.push(macro);
|
|
7385
|
+
}
|
|
7135
7386
|
}
|
|
7136
7387
|
return macros;
|
|
7137
7388
|
}
|
|
7138
|
-
function
|
|
7139
|
-
const
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
} else {
|
|
7147
|
-
const stack = stacks[name];
|
|
7148
|
-
if (stack && stack.length > 0) {
|
|
7149
|
-
const openId = stack.pop();
|
|
7150
|
-
macros[openId].pair = macro.id;
|
|
7151
|
-
macro.pair = openId;
|
|
7152
|
-
}
|
|
7153
|
-
}
|
|
7389
|
+
function discoverMacrosFromStoryInit(passageContent2) {
|
|
7390
|
+
const macros = [];
|
|
7391
|
+
doBlockRegex.lastIndex = 0;
|
|
7392
|
+
let doMatch;
|
|
7393
|
+
while ((doMatch = doBlockRegex.exec(passageContent2)) !== null) {
|
|
7394
|
+
const jsContent = doMatch[1];
|
|
7395
|
+
const found = discoverMacrosFromSource(jsContent);
|
|
7396
|
+
macros.push(...found);
|
|
7154
7397
|
}
|
|
7398
|
+
return macros;
|
|
7155
7399
|
}
|
|
7156
|
-
var
|
|
7157
|
-
var
|
|
7158
|
-
"src/core/parsing/macro-
|
|
7400
|
+
var defineMacroRegex, doBlockRegex;
|
|
7401
|
+
var init_macro_discovery = __esm({
|
|
7402
|
+
"src/core/parsing/macro-discovery.ts"() {
|
|
7159
7403
|
"use strict";
|
|
7160
|
-
|
|
7161
|
-
|
|
7404
|
+
defineMacroRegex = /Story\.defineMacro\s*\(\s*\{/g;
|
|
7405
|
+
doBlockRegex = /\{do\}([\s\S]*?)\{\/do\}/g;
|
|
7162
7406
|
}
|
|
7163
7407
|
});
|
|
7164
7408
|
|
|
@@ -7352,7 +7596,7 @@ var init_macro_supplements = __esm({
|
|
|
7352
7596
|
},
|
|
7353
7597
|
include: {
|
|
7354
7598
|
name: "include",
|
|
7355
|
-
description: 'Outputs the contents of the specified passage.\n\nUsage: `{include "passage"}`',
|
|
7599
|
+
description: 'Outputs the contents of the specified passage. The argument is a passage name or an expression that evaluates to one; add `inline` to render the passage as inline content without markdown processing.\n\nUsage: `{include "passage"}`, `{include $passageName}` or `{include "passage" inline}`',
|
|
7356
7600
|
parameters: ["text"]
|
|
7357
7601
|
},
|
|
7358
7602
|
passage: {
|
|
@@ -7362,28 +7606,28 @@ var init_macro_supplements = __esm({
|
|
|
7362
7606
|
},
|
|
7363
7607
|
textbox: {
|
|
7364
7608
|
name: "textbox",
|
|
7365
|
-
description: 'Creates a text input box.\n\nUsage: `{textbox
|
|
7366
|
-
parameters: ["receiver
|
|
7609
|
+
description: 'Creates a text input box bound to a story variable.\n\nUsage: `{textbox $receiver}` or `{textbox $receiver "placeholder"}`',
|
|
7610
|
+
parameters: ["receiver |+ text"]
|
|
7367
7611
|
},
|
|
7368
7612
|
numberbox: {
|
|
7369
7613
|
name: "numberbox",
|
|
7370
|
-
description: 'Creates a number input box.\n\nUsage: `{numberbox
|
|
7371
|
-
parameters: ["receiver
|
|
7614
|
+
description: 'Creates a number input box bound to a story variable.\n\nUsage: `{numberbox $receiver}` or `{numberbox $receiver "placeholder"}`',
|
|
7615
|
+
parameters: ["receiver |+ text"]
|
|
7372
7616
|
},
|
|
7373
7617
|
textarea: {
|
|
7374
7618
|
name: "textarea",
|
|
7375
|
-
description: 'Creates a multi-line text input area.\n\nUsage: `{textarea
|
|
7376
|
-
parameters: ["receiver
|
|
7619
|
+
description: 'Creates a multi-line text input area bound to a story variable.\n\nUsage: `{textarea $receiver}` or `{textarea $receiver "placeholder"}`',
|
|
7620
|
+
parameters: ["receiver |+ text"]
|
|
7377
7621
|
},
|
|
7378
7622
|
checkbox: {
|
|
7379
7623
|
name: "checkbox",
|
|
7380
|
-
description: 'Creates a checkbox
|
|
7381
|
-
parameters: ["receiver
|
|
7624
|
+
description: 'Creates a checkbox that toggles a boolean story variable.\n\nUsage: `{checkbox $receiver "label"}`',
|
|
7625
|
+
parameters: ["receiver |+ text"]
|
|
7382
7626
|
},
|
|
7383
7627
|
radiobutton: {
|
|
7384
7628
|
name: "radiobutton",
|
|
7385
|
-
description: 'Creates a radio button
|
|
7386
|
-
parameters: ["receiver &+ text
|
|
7629
|
+
description: 'Creates a radio button that sets a story variable to its value. Use the same variable for every option in a group.\n\nUsage: `{radiobutton $receiver "value" "label"}`',
|
|
7630
|
+
parameters: ["receiver &+ text |+ text"]
|
|
7387
7631
|
},
|
|
7388
7632
|
quicksave: {
|
|
7389
7633
|
name: "quicksave",
|
|
@@ -7413,8 +7657,8 @@ var init_macro_supplements = __esm({
|
|
|
7413
7657
|
dialog: {
|
|
7414
7658
|
name: "dialog",
|
|
7415
7659
|
container: true,
|
|
7416
|
-
description: '
|
|
7417
|
-
parameters: ["text"]
|
|
7660
|
+
description: 'Creates a button that opens the passage named in its body in a dialog. Add `noclose` to hide the dialog\'s close button.\n\nUsage:\n\n```\n{dialog "label"}Passage Name{/dialog}\n{dialog "label" noclose}Passage Name{/dialog}\n```',
|
|
7661
|
+
parameters: ["text |+ 'noclose'"]
|
|
7418
7662
|
},
|
|
7419
7663
|
nobr: {
|
|
7420
7664
|
name: "nobr",
|
|
@@ -7470,6 +7714,7 @@ var init_workspace_model = __esm({
|
|
|
7470
7714
|
init_variable_tracker();
|
|
7471
7715
|
init_widget_registry();
|
|
7472
7716
|
init_macro_parser();
|
|
7717
|
+
init_macro_discovery();
|
|
7473
7718
|
init_macro_supplements();
|
|
7474
7719
|
WorkspaceModel = class extends EventEmitter3 {
|
|
7475
7720
|
documents;
|
|
@@ -7492,7 +7737,7 @@ var init_workspace_model = __esm({
|
|
|
7492
7737
|
this.macros = new MacroRegistry();
|
|
7493
7738
|
this.variables = new VariableTracker();
|
|
7494
7739
|
this.widgets = new WidgetRegistry();
|
|
7495
|
-
this.macros.loadBuiltins();
|
|
7740
|
+
this.macros.loadBuiltins(config2?.workspaceRoot);
|
|
7496
7741
|
this.macros.loadSupplements(macro_supplements_default);
|
|
7497
7742
|
this.onDocumentChanged = (uri) => this.handleDocumentChange(uri);
|
|
7498
7743
|
this.onDocumentOpened = (uri) => this.handleDocumentChange(uri);
|
|
@@ -7517,6 +7762,14 @@ var init_workspace_model = __esm({
|
|
|
7517
7762
|
this.initialized = true;
|
|
7518
7763
|
this.scheduleModelReady();
|
|
7519
7764
|
}
|
|
7765
|
+
/**
|
|
7766
|
+
* Re-run cross-document analysis and schedule 'modelReady', e.g. after
|
|
7767
|
+
* the macro configuration changed without any document changing.
|
|
7768
|
+
*/
|
|
7769
|
+
refresh() {
|
|
7770
|
+
this.cascade();
|
|
7771
|
+
this.scheduleModelReady();
|
|
7772
|
+
}
|
|
7520
7773
|
/** Clean up listeners and timers. */
|
|
7521
7774
|
dispose() {
|
|
7522
7775
|
this.documents.removeListener("documentChanged", this.onDocumentChanged);
|
|
@@ -7534,6 +7787,7 @@ var init_workspace_model = __esm({
|
|
|
7534
7787
|
if (text !== void 0) {
|
|
7535
7788
|
this.passages.rebuild(uri, text);
|
|
7536
7789
|
}
|
|
7790
|
+
this.refreshDiscoveredMacros();
|
|
7537
7791
|
this.cascade();
|
|
7538
7792
|
this.emit("documentChanged", uri);
|
|
7539
7793
|
this.emit("passagesUpdated", uri);
|
|
@@ -7542,6 +7796,7 @@ var init_workspace_model = __esm({
|
|
|
7542
7796
|
/** Handle a document close: remove its passages and cascade. */
|
|
7543
7797
|
handleDocumentClose(uri) {
|
|
7544
7798
|
this.passages.remove(uri);
|
|
7799
|
+
this.refreshDiscoveredMacros();
|
|
7545
7800
|
this.cascade();
|
|
7546
7801
|
this.emit("documentClosed", uri);
|
|
7547
7802
|
this.emit("passagesUpdated", uri);
|
|
@@ -7555,8 +7810,39 @@ var init_workspace_model = __esm({
|
|
|
7555
7810
|
this.passages.rebuild(uri, text);
|
|
7556
7811
|
}
|
|
7557
7812
|
}
|
|
7813
|
+
this.refreshDiscoveredMacros();
|
|
7558
7814
|
this.cascade();
|
|
7559
7815
|
}
|
|
7816
|
+
/**
|
|
7817
|
+
* Re-run static macro discovery over the workspace and replace the
|
|
7818
|
+
* registry's discovered tier (dropping definitions whose source is gone).
|
|
7819
|
+
*
|
|
7820
|
+
* Sources scanned for Story.defineMacro({...}) calls:
|
|
7821
|
+
* - `{do}` blocks in StoryInit passages
|
|
7822
|
+
* - passages tagged `script` (Story JavaScript)
|
|
7823
|
+
* - JavaScript/TypeScript documents in the workspace
|
|
7824
|
+
*/
|
|
7825
|
+
refreshDiscoveredMacros() {
|
|
7826
|
+
const found = [];
|
|
7827
|
+
for (const uri of this.documents.getUris()) {
|
|
7828
|
+
const text = this.documents.getText(uri);
|
|
7829
|
+
if (!text) continue;
|
|
7830
|
+
if (/\.[cm]?[jt]s$/i.test(uri)) {
|
|
7831
|
+
found.push(...discoverMacrosFromSource(text));
|
|
7832
|
+
continue;
|
|
7833
|
+
}
|
|
7834
|
+
let lines;
|
|
7835
|
+
for (const passage of this.passages.getPassagesInDocument(uri)) {
|
|
7836
|
+
const isStoryInit = passage.name === "StoryInit";
|
|
7837
|
+
const isScript = passage.tags?.includes("script") ?? false;
|
|
7838
|
+
if (!isStoryInit && !isScript) continue;
|
|
7839
|
+
lines ??= text.split("\n");
|
|
7840
|
+
const content = lines.slice(passage.headerEnd.end.line + 1, passage.range.end.line + 1).join("\n");
|
|
7841
|
+
found.push(...isScript ? discoverMacrosFromSource(content) : discoverMacrosFromStoryInit(content));
|
|
7842
|
+
}
|
|
7843
|
+
}
|
|
7844
|
+
this.macros.setDiscoveredMacros(found);
|
|
7845
|
+
}
|
|
7560
7846
|
/**
|
|
7561
7847
|
* Cascade: rescan variables and widgets based on current passages.
|
|
7562
7848
|
* Called after any passage index update.
|
|
@@ -7576,8 +7862,10 @@ var init_workspace_model = __esm({
|
|
|
7576
7862
|
}
|
|
7577
7863
|
}
|
|
7578
7864
|
const content = lines.slice(contentStart, contentEnd).join("\n");
|
|
7579
|
-
this.variables.parseStoryVariables(content, contentStart);
|
|
7865
|
+
this.variables.parseStoryVariables(content, contentStart, storyVars.uri);
|
|
7580
7866
|
}
|
|
7867
|
+
} else {
|
|
7868
|
+
this.variables.clearStoryVariables();
|
|
7581
7869
|
}
|
|
7582
7870
|
const storyTransients = this.passages.getStoryTransients();
|
|
7583
7871
|
if (storyTransients) {
|
|
@@ -7593,8 +7881,10 @@ var init_workspace_model = __esm({
|
|
|
7593
7881
|
}
|
|
7594
7882
|
}
|
|
7595
7883
|
const content = lines.slice(contentStart, contentEnd).join("\n");
|
|
7596
|
-
this.variables.parseStoryTransients(content, contentStart);
|
|
7884
|
+
this.variables.parseStoryTransients(content, contentStart, storyTransients.uri);
|
|
7597
7885
|
}
|
|
7886
|
+
} else {
|
|
7887
|
+
this.variables.clearStoryTransients();
|
|
7598
7888
|
}
|
|
7599
7889
|
this.widgets.clearInvocations();
|
|
7600
7890
|
for (const uri of this.documents.getUris()) {
|
|
@@ -8353,6 +8643,30 @@ var init_parameter_validator = __esm({
|
|
|
8353
8643
|
return arg.type === 4 /* Variable */ ? null : new TypeError2("Argument is not a variable");
|
|
8354
8644
|
}
|
|
8355
8645
|
},
|
|
8646
|
+
{
|
|
8647
|
+
// The story variable a form control binds to: `$name` or `"$name"`.
|
|
8648
|
+
// Spindle strips the quotes and the `$` sigil from the first argument
|
|
8649
|
+
// and reads the rest as a dot path into the story variables.
|
|
8650
|
+
name: ["receiver"],
|
|
8651
|
+
validate(arg) {
|
|
8652
|
+
let name;
|
|
8653
|
+
if (arg.type === 0 /* String */) {
|
|
8654
|
+
name = arg.text.slice(1, -1);
|
|
8655
|
+
} else if (arg.type === 8 /* Bareword */) {
|
|
8656
|
+
name = arg.text;
|
|
8657
|
+
}
|
|
8658
|
+
if (name === void 0) {
|
|
8659
|
+
return new TypeError2("Argument is not a variable receiver");
|
|
8660
|
+
}
|
|
8661
|
+
if (/^[_@%]/.test(name)) {
|
|
8662
|
+
return new TypeError2(`Variable receiver must be a story variable ($name), got '${name}'`);
|
|
8663
|
+
}
|
|
8664
|
+
if (!/^\$?[A-Za-z_][\w$]*(?:\.[\w$]+)*$/.test(name)) {
|
|
8665
|
+
return new TypeError2(`Argument is not a valid variable receiver: '${name}'`);
|
|
8666
|
+
}
|
|
8667
|
+
return null;
|
|
8668
|
+
}
|
|
8669
|
+
},
|
|
8356
8670
|
{
|
|
8357
8671
|
name: ["passage"],
|
|
8358
8672
|
validate(arg, _args, _index, state) {
|
|
@@ -8505,58 +8819,175 @@ var init_parameter_validator = __esm({
|
|
|
8505
8819
|
});
|
|
8506
8820
|
|
|
8507
8821
|
// src/core/parsing/link-parser.ts
|
|
8508
|
-
function
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8822
|
+
function skipSelectors(text, i) {
|
|
8823
|
+
while (text[i] === "." || text[i] === "#") {
|
|
8824
|
+
i++;
|
|
8825
|
+
for (; ; ) {
|
|
8826
|
+
if (/[a-zA-Z0-9_-]/.test(text[i] ?? "")) {
|
|
8827
|
+
i++;
|
|
8828
|
+
continue;
|
|
8829
|
+
}
|
|
8830
|
+
const interpolation = /^\{[$_@][\w.]*\}/.exec(text.slice(i));
|
|
8831
|
+
if (!interpolation) break;
|
|
8832
|
+
i += interpolation[0].length;
|
|
8513
8833
|
}
|
|
8514
8834
|
}
|
|
8515
|
-
return
|
|
8835
|
+
return i;
|
|
8516
8836
|
}
|
|
8517
|
-
function
|
|
8518
|
-
let
|
|
8519
|
-
let
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8837
|
+
function locateTarget(inner) {
|
|
8838
|
+
let start = 0;
|
|
8839
|
+
let end = inner.length;
|
|
8840
|
+
const pipeIdx = inner.indexOf("|");
|
|
8841
|
+
const arrowIdx = inner.indexOf("->");
|
|
8842
|
+
const revIdx = inner.indexOf("<-");
|
|
8843
|
+
if (pipeIdx !== -1) {
|
|
8844
|
+
start = pipeIdx + 1;
|
|
8845
|
+
} else if (arrowIdx !== -1) {
|
|
8846
|
+
start = arrowIdx + 2;
|
|
8847
|
+
} else if (revIdx !== -1) {
|
|
8848
|
+
end = revIdx;
|
|
8527
8849
|
}
|
|
8528
|
-
|
|
8850
|
+
while (start < end && /\s/.test(inner[start])) start++;
|
|
8851
|
+
while (end > start && /\s/.test(inner[end - 1])) end--;
|
|
8852
|
+
return { start, end };
|
|
8529
8853
|
}
|
|
8530
8854
|
function parseLinks(text, lineOffset = 0) {
|
|
8531
|
-
const lineStarts =
|
|
8855
|
+
const lineStarts = buildLineStarts(text);
|
|
8532
8856
|
const refs = [];
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
if (
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
const
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8857
|
+
let i = text.indexOf("[[");
|
|
8858
|
+
while (i !== -1) {
|
|
8859
|
+
const linkStart = i;
|
|
8860
|
+
i += 2;
|
|
8861
|
+
if (text[i] === "." || text[i] === "#") {
|
|
8862
|
+
i = skipSelectors(text, i);
|
|
8863
|
+
if (text[i] === " ") i++;
|
|
8864
|
+
}
|
|
8865
|
+
const innerStart = i;
|
|
8866
|
+
let depth = 1;
|
|
8867
|
+
while (i < text.length) {
|
|
8868
|
+
if (text.startsWith("[[", i)) {
|
|
8869
|
+
depth++;
|
|
8870
|
+
i += 2;
|
|
8871
|
+
} else if (text.startsWith("]]", i)) {
|
|
8872
|
+
if (--depth === 0) break;
|
|
8873
|
+
i += 2;
|
|
8874
|
+
} else {
|
|
8875
|
+
i++;
|
|
8876
|
+
}
|
|
8877
|
+
}
|
|
8878
|
+
if (depth !== 0) {
|
|
8879
|
+
i = text.indexOf("[[", linkStart + 2);
|
|
8880
|
+
continue;
|
|
8881
|
+
}
|
|
8882
|
+
const target = locateTarget(text.slice(innerStart, i));
|
|
8883
|
+
if (target.end > target.start) {
|
|
8884
|
+
const nameStart = innerStart + target.start;
|
|
8885
|
+
const nameEnd = innerStart + target.end;
|
|
8886
|
+
const startPos = offsetToPosition(nameStart, lineStarts);
|
|
8887
|
+
const endPos = offsetToPosition(nameEnd, lineStarts);
|
|
8888
|
+
refs.push({
|
|
8889
|
+
name: text.slice(nameStart, nameEnd),
|
|
8890
|
+
range: {
|
|
8891
|
+
start: { line: startPos.line + lineOffset, character: startPos.character },
|
|
8892
|
+
end: { line: endPos.line + lineOffset, character: endPos.character }
|
|
8893
|
+
},
|
|
8894
|
+
source: "link"
|
|
8895
|
+
});
|
|
8896
|
+
}
|
|
8897
|
+
i = text.indexOf("[[", i + 2);
|
|
8898
|
+
}
|
|
8899
|
+
return refs;
|
|
8900
|
+
}
|
|
8901
|
+
function findPassageRefAt(text, position) {
|
|
8902
|
+
const { line, character } = position;
|
|
8903
|
+
return [...parseLinks(text), ...parseMacroPassageRefs(text)].find(({ range: { start, end } }) => (line > start.line || line === start.line && character >= start.character) && (line < end.line || line === end.line && character <= end.character));
|
|
8904
|
+
}
|
|
8905
|
+
function resolveExpressionTarget(args2) {
|
|
8906
|
+
const lead = args2.length - args2.trimStart().length;
|
|
8907
|
+
const expr = args2.trim();
|
|
8908
|
+
if (expr === "") return null;
|
|
8909
|
+
const lexed = lexArguments(expr);
|
|
8910
|
+
if (lexed.length === 1 && lexed[0].start === 0 && lexed[0].end === expr.length && (lexed[0].type === 0 /* String */ || lexed[0].type === 7 /* Expression */)) {
|
|
8911
|
+
const raw = expr.slice(1, -1);
|
|
8912
|
+
if (interpolationRegex.test(raw) || raw.includes("${")) return null;
|
|
8913
|
+
return { name: raw.replace(/\\(.)/g, "$1"), start: lead + 1, end: lead + expr.length - 1 };
|
|
8914
|
+
}
|
|
8915
|
+
if (/[$@%"'`(]/.test(expr) || temporaryRefRegex.test(expr)) return null;
|
|
8916
|
+
if (EXPRESSION_BUILTINS.has(expr)) return null;
|
|
8917
|
+
return { name: expr, start: lead, end: lead + expr.length };
|
|
8918
|
+
}
|
|
8919
|
+
function resolveIncludeTarget(args2) {
|
|
8920
|
+
const inline = /\binline\b/.exec(args2);
|
|
8921
|
+
if (!inline) return resolveExpressionTarget(args2);
|
|
8922
|
+
const cut = inline.index;
|
|
8923
|
+
const width = inline[0].length;
|
|
8924
|
+
const target = resolveExpressionTarget(args2.slice(0, cut) + args2.slice(cut + width));
|
|
8925
|
+
if (!target || target.start < cut && cut < target.end) return null;
|
|
8926
|
+
return {
|
|
8927
|
+
name: target.name,
|
|
8928
|
+
start: target.start < cut ? target.start : target.start + width,
|
|
8929
|
+
end: target.end <= cut ? target.end : target.end + width
|
|
8930
|
+
};
|
|
8931
|
+
}
|
|
8932
|
+
function resolveLinkMacroTarget(args2) {
|
|
8933
|
+
const strings = lexArguments(args2).filter((a) => a.type === 0 /* String */);
|
|
8934
|
+
if (strings.length < 2) return null;
|
|
8935
|
+
const target = strings[1];
|
|
8936
|
+
const name = target.text.slice(1, -1);
|
|
8937
|
+
if (name.includes("\\") || interpolationRegex.test(name)) return null;
|
|
8938
|
+
return { name, start: target.start + 1, end: target.end - 1 };
|
|
8939
|
+
}
|
|
8940
|
+
function parseMacroPassageRefs(text, lineOffset = 0) {
|
|
8941
|
+
const lineStarts = buildLineStarts(text);
|
|
8942
|
+
const refs = [];
|
|
8943
|
+
for (const macro of parseMacros(text)) {
|
|
8944
|
+
if (!macro.open || !macro.rawArgs) continue;
|
|
8945
|
+
const resolve4 = macroTargetResolvers[macro.name.toLowerCase()];
|
|
8946
|
+
if (!resolve4) continue;
|
|
8947
|
+
const argsEnd = lineStarts[macro.range.end.line] + macro.range.end.character - 1;
|
|
8948
|
+
const argsStart = argsEnd - macro.rawArgs.length;
|
|
8949
|
+
const target = resolve4(text.slice(argsStart, argsEnd));
|
|
8950
|
+
if (!target || target.name === "") continue;
|
|
8951
|
+
const startPos = offsetToPosition(argsStart + target.start, lineStarts);
|
|
8952
|
+
const endPos = offsetToPosition(argsStart + target.end, lineStarts);
|
|
8547
8953
|
refs.push({
|
|
8548
|
-
name:
|
|
8549
|
-
range:
|
|
8550
|
-
|
|
8954
|
+
name: target.name,
|
|
8955
|
+
range: {
|
|
8956
|
+
start: { line: startPos.line + lineOffset, character: startPos.character },
|
|
8957
|
+
end: { line: endPos.line + lineOffset, character: endPos.character }
|
|
8958
|
+
},
|
|
8959
|
+
source: "macro"
|
|
8551
8960
|
});
|
|
8552
8961
|
}
|
|
8553
8962
|
return refs;
|
|
8554
8963
|
}
|
|
8555
|
-
var
|
|
8964
|
+
var EXPRESSION_BUILTINS, interpolationRegex, temporaryRefRegex, macroTargetResolvers;
|
|
8556
8965
|
var init_link_parser = __esm({
|
|
8557
8966
|
"src/core/parsing/link-parser.ts"() {
|
|
8558
8967
|
"use strict";
|
|
8559
|
-
|
|
8968
|
+
init_macro_parser();
|
|
8969
|
+
init_argument_lexer();
|
|
8970
|
+
EXPRESSION_BUILTINS = /* @__PURE__ */ new Set([
|
|
8971
|
+
"currentPassage",
|
|
8972
|
+
"previousPassage",
|
|
8973
|
+
"visited",
|
|
8974
|
+
"hasVisited",
|
|
8975
|
+
"hasVisitedAny",
|
|
8976
|
+
"hasVisitedAll",
|
|
8977
|
+
"rendered",
|
|
8978
|
+
"hasRendered",
|
|
8979
|
+
"hasRenderedAny",
|
|
8980
|
+
"hasRenderedAll",
|
|
8981
|
+
"random",
|
|
8982
|
+
"randomInt"
|
|
8983
|
+
]);
|
|
8984
|
+
interpolationRegex = /\{[$_@%][A-Za-z_$]/;
|
|
8985
|
+
temporaryRefRegex = /(?<![.\w$@%])_[A-Za-z_$][\w$]*(?![\w$])/;
|
|
8986
|
+
macroTargetResolvers = {
|
|
8987
|
+
goto: resolveExpressionTarget,
|
|
8988
|
+
include: resolveIncludeTarget,
|
|
8989
|
+
link: resolveLinkMacroTarget
|
|
8990
|
+
};
|
|
8560
8991
|
}
|
|
8561
8992
|
});
|
|
8562
8993
|
|
|
@@ -8569,8 +9000,13 @@ function computeDiagnostics(uri, workspace, options) {
|
|
|
8569
9000
|
const passages = workspace.passages.getPassagesInDocument(uri);
|
|
8570
9001
|
if (passages.length === 0) return [];
|
|
8571
9002
|
const diagnostics = [];
|
|
8572
|
-
const
|
|
8573
|
-
|
|
9003
|
+
const markupText = maskScriptAndStylesheetPassages(text, passages);
|
|
9004
|
+
const macros = parseMacros(markupText);
|
|
9005
|
+
pairMacros(
|
|
9006
|
+
macros,
|
|
9007
|
+
(name) => workspace.macros.isBlock(name),
|
|
9008
|
+
passages.map((p) => p.range.start.line)
|
|
9009
|
+
);
|
|
8574
9010
|
const allPassages = workspace.passages.getAllPassages();
|
|
8575
9011
|
const passageNames = new Set(allPassages.map((p) => p.name));
|
|
8576
9012
|
try {
|
|
@@ -8586,7 +9022,7 @@ function computeDiagnostics(uri, workspace, options) {
|
|
|
8586
9022
|
} catch {
|
|
8587
9023
|
}
|
|
8588
9024
|
try {
|
|
8589
|
-
validateLinks(
|
|
9025
|
+
validateLinks(markupText, passages, passageNames, diagnostics);
|
|
8590
9026
|
} catch {
|
|
8591
9027
|
}
|
|
8592
9028
|
try {
|
|
@@ -8620,6 +9056,18 @@ function computeDiagnostics(uri, workspace, options) {
|
|
|
8620
9056
|
return [];
|
|
8621
9057
|
}
|
|
8622
9058
|
}
|
|
9059
|
+
function maskScriptAndStylesheetPassages(text, passages) {
|
|
9060
|
+
const excluded = passages.filter(isScriptOrStylesheetPassage);
|
|
9061
|
+
if (excluded.length === 0) return text;
|
|
9062
|
+
const lines = text.split("\n");
|
|
9063
|
+
for (const passage of excluded) {
|
|
9064
|
+
const last = Math.min(passage.range.end.line, lines.length - 1);
|
|
9065
|
+
for (let i = passage.range.start.line + 1; i <= last; i++) {
|
|
9066
|
+
lines[i] = lines[i].replace(/[^\r]/g, " ");
|
|
9067
|
+
}
|
|
9068
|
+
}
|
|
9069
|
+
return lines.join("\n");
|
|
9070
|
+
}
|
|
8623
9071
|
function validateMacros(macros, workspace, diagnostics) {
|
|
8624
9072
|
for (let curIndex = 0; curIndex < macros.length; curIndex++) {
|
|
8625
9073
|
const macro = macros[curIndex];
|
|
@@ -8732,8 +9180,13 @@ function validateArguments(macros, workspace, passageNames, diagnostics) {
|
|
|
8732
9180
|
if (info.skipArgs) continue;
|
|
8733
9181
|
if (!info.parameters) continue;
|
|
8734
9182
|
const rawArgs = macro.rawArgs ?? "";
|
|
8735
|
-
const args2 = lexArguments(rawArgs);
|
|
8736
|
-
|
|
9183
|
+
const args2 = macro.name.toLowerCase() === "include" ? includeArguments(rawArgs) : lexArguments(rawArgs);
|
|
9184
|
+
let params;
|
|
9185
|
+
try {
|
|
9186
|
+
params = new Parameters(info.parameters);
|
|
9187
|
+
} catch {
|
|
9188
|
+
continue;
|
|
9189
|
+
}
|
|
8737
9190
|
if (params.isEmpty()) {
|
|
8738
9191
|
if (args2.length > 0) {
|
|
8739
9192
|
diagnostics.push(makeDiag(
|
|
@@ -8773,6 +9226,16 @@ function validateArguments(macros, workspace, passageNames, diagnostics) {
|
|
|
8773
9226
|
}
|
|
8774
9227
|
}
|
|
8775
9228
|
}
|
|
9229
|
+
function includeArguments(rawArgs) {
|
|
9230
|
+
const expr = includeExpression(rawArgs);
|
|
9231
|
+
if (expr === "") return [];
|
|
9232
|
+
const args2 = lexArguments(expr);
|
|
9233
|
+
if (args2.length === 1) return args2;
|
|
9234
|
+
return [{ type: 7 /* Expression */, text: expr, start: 0, end: expr.length }];
|
|
9235
|
+
}
|
|
9236
|
+
function includeExpression(rawArgs) {
|
|
9237
|
+
return rawArgs.replace(/\binline\b/, "").trim();
|
|
9238
|
+
}
|
|
8776
9239
|
function validateVariables(uri, workspace, diagnostics) {
|
|
8777
9240
|
if (!workspace.variables.hasStoryVariables()) {
|
|
8778
9241
|
const undeclared = workspace.variables.getUndeclared(uri);
|
|
@@ -8874,7 +9337,7 @@ function validateArrayMemberAccess(uri, workspace, diagnostics) {
|
|
|
8874
9337
|
));
|
|
8875
9338
|
}
|
|
8876
9339
|
}
|
|
8877
|
-
function
|
|
9340
|
+
function temporaryRefRegex2(name) {
|
|
8878
9341
|
const ident = name ? escapeRegex(name) : "[A-Za-z_$][\\w$]*";
|
|
8879
9342
|
return new RegExp(`(?<![.\\w$@%])_(${ident})(?![\\w$])`, "g");
|
|
8880
9343
|
}
|
|
@@ -8950,7 +9413,7 @@ function setTemporaryTargets(rawArgs) {
|
|
|
8950
9413
|
while ((m = assignRe.exec(code)) !== null) {
|
|
8951
9414
|
const name = m[1];
|
|
8952
9415
|
const rhs = code.slice(m.index + m[0].length, statementEnd(code, m.index + m[0].length));
|
|
8953
|
-
if (
|
|
9416
|
+
if (temporaryRefRegex2(name).test(rhs)) continue;
|
|
8954
9417
|
targets.push({ name, offset: m.index });
|
|
8955
9418
|
}
|
|
8956
9419
|
return targets;
|
|
@@ -9019,7 +9482,7 @@ function validateLoopTemporaries(uri, text, macros, workspace, diagnostics) {
|
|
|
9019
9482
|
}
|
|
9020
9483
|
}
|
|
9021
9484
|
function isReadInBody(body, bodyOffset, name, macroStart, macroEnd) {
|
|
9022
|
-
const re =
|
|
9485
|
+
const re = temporaryRefRegex2(name);
|
|
9023
9486
|
let m;
|
|
9024
9487
|
while ((m = re.exec(body)) !== null) {
|
|
9025
9488
|
const offset = bodyOffset + m.index;
|
|
@@ -9030,16 +9493,16 @@ function isReadInBody(body, bodyOffset, name, macroStart, macroEnd) {
|
|
|
9030
9493
|
}
|
|
9031
9494
|
return false;
|
|
9032
9495
|
}
|
|
9033
|
-
function
|
|
9034
|
-
const expr = rawArgs
|
|
9496
|
+
function resolveIncludeTarget2(rawArgs) {
|
|
9497
|
+
const expr = includeExpression(rawArgs);
|
|
9035
9498
|
if (expr === "") return null;
|
|
9036
9499
|
const literal2 = /^(["'`])((?:\\.|(?!\1)[^\\])*)\1$/s.exec(expr);
|
|
9037
9500
|
if (literal2) {
|
|
9038
9501
|
if (literal2[1] === "`" && literal2[2].includes("${")) return null;
|
|
9039
9502
|
return literal2[2].replace(/\\(.)/g, "$1");
|
|
9040
9503
|
}
|
|
9041
|
-
if (/[$@%"'`(]/.test(expr) ||
|
|
9042
|
-
if (
|
|
9504
|
+
if (/[$@%"'`(]/.test(expr) || temporaryRefRegex2().test(expr)) return null;
|
|
9505
|
+
if (EXPRESSION_BUILTINS2.has(expr)) return null;
|
|
9043
9506
|
return expr;
|
|
9044
9507
|
}
|
|
9045
9508
|
function widgetDefinitionNames(content) {
|
|
@@ -9058,7 +9521,7 @@ function validateWidgetIncludes(text, macros, workspace, diagnostics) {
|
|
|
9058
9521
|
for (const macro of macros) {
|
|
9059
9522
|
if (!macro.open || !macro.rawArgs || macro.name.toLowerCase() !== "include") continue;
|
|
9060
9523
|
lineStarts ??= buildLineStarts(text);
|
|
9061
|
-
const target =
|
|
9524
|
+
const target = resolveIncludeTarget2(sourceArgs(macro, text, lineStarts).args);
|
|
9062
9525
|
if (target === null) continue;
|
|
9063
9526
|
const passage = workspace.passages.getPassage(target);
|
|
9064
9527
|
if (!passage?.tags?.includes("widget")) continue;
|
|
@@ -9084,10 +9547,15 @@ function validateUnusedWidgets(uri, workspace, diagnostics) {
|
|
|
9084
9547
|
}
|
|
9085
9548
|
}
|
|
9086
9549
|
function validateLineLength(text, passages, maxLength, diagnostics) {
|
|
9087
|
-
const
|
|
9088
|
-
const
|
|
9550
|
+
const excludedLines = /* @__PURE__ */ new Set();
|
|
9551
|
+
for (const passage of passages.filter(isScriptOrStylesheetPassage)) {
|
|
9552
|
+
for (let i = passage.range.start.line; i <= passage.range.end.line; i++) {
|
|
9553
|
+
excludedLines.add(i);
|
|
9554
|
+
}
|
|
9555
|
+
}
|
|
9089
9556
|
const lines = text.split("\n");
|
|
9090
9557
|
for (let i = 0; i < lines.length; i++) {
|
|
9558
|
+
if (excludedLines.has(i)) continue;
|
|
9091
9559
|
const line = lines[i];
|
|
9092
9560
|
if (/^::\s+/.test(line)) continue;
|
|
9093
9561
|
if (/^\s*<[a-zA-Z]/.test(line)) continue;
|
|
@@ -9130,7 +9598,7 @@ function toLspDiagnostic(d) {
|
|
|
9130
9598
|
message: d.message
|
|
9131
9599
|
};
|
|
9132
9600
|
}
|
|
9133
|
-
var DEFERRED_CONTAINERS,
|
|
9601
|
+
var DEFERRED_CONTAINERS, EXPRESSION_BUILTINS2, diagnosticsPlugin;
|
|
9134
9602
|
var init_diagnostics = __esm({
|
|
9135
9603
|
"src/plugins/diagnostics.ts"() {
|
|
9136
9604
|
"use strict";
|
|
@@ -9139,8 +9607,9 @@ var init_diagnostics = __esm({
|
|
|
9139
9607
|
init_argument_lexer();
|
|
9140
9608
|
init_parameter_validator();
|
|
9141
9609
|
init_link_parser();
|
|
9610
|
+
init_passage_parser();
|
|
9142
9611
|
DEFERRED_CONTAINERS = /* @__PURE__ */ new Set(["link", "button"]);
|
|
9143
|
-
|
|
9612
|
+
EXPRESSION_BUILTINS2 = /* @__PURE__ */ new Set([
|
|
9144
9613
|
"currentPassage",
|
|
9145
9614
|
"previousPassage",
|
|
9146
9615
|
"visited",
|
|
@@ -9158,22 +9627,22 @@ var init_diagnostics = __esm({
|
|
|
9158
9627
|
id: "diagnostics",
|
|
9159
9628
|
capabilities: {},
|
|
9160
9629
|
initialize(ctx) {
|
|
9161
|
-
const
|
|
9162
|
-
|
|
9163
|
-
const diags = computeDiagnostics(uri, ctx.workspace);
|
|
9164
|
-
ctx.connection.sendDiagnostics({
|
|
9165
|
-
uri,
|
|
9166
|
-
diagnostics: diags.map((d) => toLspDiagnostic(d))
|
|
9167
|
-
});
|
|
9168
|
-
}
|
|
9169
|
-
};
|
|
9170
|
-
ctx.workspace.on("modelReady", publishDiagnostics);
|
|
9171
|
-
ctx.workspace.on("documentChanged", (uri) => {
|
|
9630
|
+
const isEnabled = (d) => ctx.config.diagnostics?.[d.code] !== false;
|
|
9631
|
+
const publishFor = (uri) => {
|
|
9172
9632
|
const diags = computeDiagnostics(uri, ctx.workspace);
|
|
9173
9633
|
ctx.connection.sendDiagnostics({
|
|
9174
9634
|
uri,
|
|
9175
|
-
diagnostics: diags.map((d) => toLspDiagnostic(d))
|
|
9635
|
+
diagnostics: diags.filter(isEnabled).map((d) => toLspDiagnostic(d))
|
|
9176
9636
|
});
|
|
9637
|
+
};
|
|
9638
|
+
ctx.workspace.on("modelReady", () => {
|
|
9639
|
+
for (const uri of ctx.workspace.documents.getUris()) {
|
|
9640
|
+
publishFor(uri);
|
|
9641
|
+
}
|
|
9642
|
+
});
|
|
9643
|
+
ctx.workspace.on("documentChanged", publishFor);
|
|
9644
|
+
ctx.workspace.on("documentClosed", (uri) => {
|
|
9645
|
+
ctx.connection.sendDiagnostics({ uri, diagnostics: [] });
|
|
9177
9646
|
});
|
|
9178
9647
|
}
|
|
9179
9648
|
};
|
|
@@ -9193,9 +9662,9 @@ var require_identity = __commonJS({
|
|
|
9193
9662
|
var NODE_TYPE = Symbol.for("yaml.node.type");
|
|
9194
9663
|
var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
|
9195
9664
|
var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
|
9196
|
-
var
|
|
9665
|
+
var isMap2 = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
|
9197
9666
|
var isPair = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === PAIR;
|
|
9198
|
-
var
|
|
9667
|
+
var isScalar2 = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SCALAR;
|
|
9199
9668
|
var isSeq = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SEQ;
|
|
9200
9669
|
function isCollection(node) {
|
|
9201
9670
|
if (node && typeof node === "object")
|
|
@@ -9217,7 +9686,7 @@ var require_identity = __commonJS({
|
|
|
9217
9686
|
}
|
|
9218
9687
|
return false;
|
|
9219
9688
|
}
|
|
9220
|
-
var hasAnchor = (node) => (
|
|
9689
|
+
var hasAnchor = (node) => (isScalar2(node) || isCollection(node)) && !!node.anchor;
|
|
9221
9690
|
exports.ALIAS = ALIAS;
|
|
9222
9691
|
exports.DOC = DOC;
|
|
9223
9692
|
exports.MAP = MAP;
|
|
@@ -9229,10 +9698,10 @@ var require_identity = __commonJS({
|
|
|
9229
9698
|
exports.isAlias = isAlias;
|
|
9230
9699
|
exports.isCollection = isCollection;
|
|
9231
9700
|
exports.isDocument = isDocument;
|
|
9232
|
-
exports.isMap =
|
|
9701
|
+
exports.isMap = isMap2;
|
|
9233
9702
|
exports.isNode = isNode;
|
|
9234
9703
|
exports.isPair = isPair;
|
|
9235
|
-
exports.isScalar =
|
|
9704
|
+
exports.isScalar = isScalar2;
|
|
9236
9705
|
exports.isSeq = isSeq;
|
|
9237
9706
|
}
|
|
9238
9707
|
});
|
|
@@ -13334,9 +13803,9 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
13334
13803
|
var blockMsg = "Block collections are not allowed within flow collections";
|
|
13335
13804
|
var isBlock = (token) => token && (token.type === "block-map" || token.type === "block-seq");
|
|
13336
13805
|
function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onError, tag) {
|
|
13337
|
-
const
|
|
13338
|
-
const fcName =
|
|
13339
|
-
const NodeClass = tag?.nodeClass ?? (
|
|
13806
|
+
const isMap2 = fc.start.source === "{";
|
|
13807
|
+
const fcName = isMap2 ? "flow map" : "flow sequence";
|
|
13808
|
+
const NodeClass = tag?.nodeClass ?? (isMap2 ? YAMLMap.YAMLMap : YAMLSeq.YAMLSeq);
|
|
13340
13809
|
const coll = new NodeClass(ctx.schema);
|
|
13341
13810
|
coll.flow = true;
|
|
13342
13811
|
const atRoot = ctx.atRoot;
|
|
@@ -13372,7 +13841,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
13372
13841
|
offset = props.end;
|
|
13373
13842
|
continue;
|
|
13374
13843
|
}
|
|
13375
|
-
if (!
|
|
13844
|
+
if (!isMap2 && ctx.options.strict && utilContainsNewline.containsNewline(key))
|
|
13376
13845
|
onError(
|
|
13377
13846
|
key,
|
|
13378
13847
|
// checked by containsNewline()
|
|
@@ -13412,7 +13881,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
13412
13881
|
}
|
|
13413
13882
|
}
|
|
13414
13883
|
}
|
|
13415
|
-
if (!
|
|
13884
|
+
if (!isMap2 && !sep2 && !props.found) {
|
|
13416
13885
|
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep2, null, props, onError);
|
|
13417
13886
|
coll.items.push(valueNode);
|
|
13418
13887
|
offset = valueNode.range[2];
|
|
@@ -13435,7 +13904,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
13435
13904
|
startOnNewline: false
|
|
13436
13905
|
});
|
|
13437
13906
|
if (valueProps.found) {
|
|
13438
|
-
if (!
|
|
13907
|
+
if (!isMap2 && !props.found && ctx.options.strict) {
|
|
13439
13908
|
if (sep2)
|
|
13440
13909
|
for (const st of sep2) {
|
|
13441
13910
|
if (st === valueProps.found)
|
|
@@ -13467,7 +13936,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
13467
13936
|
const pair = new Pair.Pair(keyNode, valueNode);
|
|
13468
13937
|
if (ctx.options.keepSourceTokens)
|
|
13469
13938
|
pair.srcToken = collItem;
|
|
13470
|
-
if (
|
|
13939
|
+
if (isMap2) {
|
|
13471
13940
|
const map2 = coll;
|
|
13472
13941
|
if (utilMapIncludes.mapIncludes(ctx, map2.items, keyNode))
|
|
13473
13942
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
@@ -13483,7 +13952,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
13483
13952
|
offset = valueNode ? valueNode.range[2] : valueProps.end;
|
|
13484
13953
|
}
|
|
13485
13954
|
}
|
|
13486
|
-
const expectedEnd =
|
|
13955
|
+
const expectedEnd = isMap2 ? "}" : "]";
|
|
13487
13956
|
const [ce, ...ee] = fc.end;
|
|
13488
13957
|
let cePos = offset;
|
|
13489
13958
|
if (ce?.source === expectedEnd)
|
|
@@ -14766,7 +15235,7 @@ var require_cst = __commonJS({
|
|
|
14766
15235
|
var FLOW_END = "";
|
|
14767
15236
|
var SCALAR = "";
|
|
14768
15237
|
var isCollection = (token) => !!token && "items" in token;
|
|
14769
|
-
var
|
|
15238
|
+
var isScalar2 = (token) => !!token && (token.type === "scalar" || token.type === "single-quoted-scalar" || token.type === "double-quoted-scalar" || token.type === "block-scalar");
|
|
14770
15239
|
function prettyToken(token) {
|
|
14771
15240
|
switch (token) {
|
|
14772
15241
|
case BOM:
|
|
@@ -14850,7 +15319,7 @@ var require_cst = __commonJS({
|
|
|
14850
15319
|
exports.FLOW_END = FLOW_END;
|
|
14851
15320
|
exports.SCALAR = SCALAR;
|
|
14852
15321
|
exports.isCollection = isCollection;
|
|
14853
|
-
exports.isScalar =
|
|
15322
|
+
exports.isScalar = isScalar2;
|
|
14854
15323
|
exports.prettyToken = prettyToken;
|
|
14855
15324
|
exports.tokenType = tokenType;
|
|
14856
15325
|
}
|
|
@@ -16363,7 +16832,7 @@ var require_public_api = __commonJS({
|
|
|
16363
16832
|
return docs;
|
|
16364
16833
|
return Object.assign([], { empty: true }, composer$1.streamInfo());
|
|
16365
16834
|
}
|
|
16366
|
-
function
|
|
16835
|
+
function parseDocument2(source, options = {}) {
|
|
16367
16836
|
const { lineCounter: lineCounter2, prettyErrors } = parseOptions(options);
|
|
16368
16837
|
const parser$1 = new parser.Parser(lineCounter2?.addNewLine);
|
|
16369
16838
|
const composer$1 = new composer.Composer(options);
|
|
@@ -16389,7 +16858,7 @@ var require_public_api = __commonJS({
|
|
|
16389
16858
|
} else if (options === void 0 && reviver && typeof reviver === "object") {
|
|
16390
16859
|
options = reviver;
|
|
16391
16860
|
}
|
|
16392
|
-
const doc =
|
|
16861
|
+
const doc = parseDocument2(src, options);
|
|
16393
16862
|
if (!doc)
|
|
16394
16863
|
return null;
|
|
16395
16864
|
doc.warnings.forEach((warning) => log.warn(doc.options.logLevel, warning));
|
|
@@ -16425,7 +16894,7 @@ var require_public_api = __commonJS({
|
|
|
16425
16894
|
}
|
|
16426
16895
|
exports.parse = parse3;
|
|
16427
16896
|
exports.parseAllDocuments = parseAllDocuments;
|
|
16428
|
-
exports.parseDocument =
|
|
16897
|
+
exports.parseDocument = parseDocument2;
|
|
16429
16898
|
exports.stringify = stringify;
|
|
16430
16899
|
}
|
|
16431
16900
|
});
|
|
@@ -16515,6 +16984,22 @@ function findConfigFile(workspaceRoot) {
|
|
|
16515
16984
|
}
|
|
16516
16985
|
return null;
|
|
16517
16986
|
}
|
|
16987
|
+
function loadConfigFile(configPath) {
|
|
16988
|
+
let content;
|
|
16989
|
+
try {
|
|
16990
|
+
content = readFileSync3(configPath, "utf-8");
|
|
16991
|
+
} catch (err) {
|
|
16992
|
+
const reason = err?.code === "ENOENT" ? "file not found" : err instanceof Error ? err.message : String(err);
|
|
16993
|
+
throw new Error(`Cannot read config file '${configPath}': ${reason}`);
|
|
16994
|
+
}
|
|
16995
|
+
const format = configPath.toLowerCase().endsWith(".json") ? "json" : "yaml";
|
|
16996
|
+
try {
|
|
16997
|
+
return parseConfig(content, format);
|
|
16998
|
+
} catch (err) {
|
|
16999
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
17000
|
+
throw new Error(`Invalid ${format.toUpperCase()} in config file '${configPath}': ${reason}`);
|
|
17001
|
+
}
|
|
17002
|
+
}
|
|
16518
17003
|
function loadConfigFromDisk(workspaceRoot) {
|
|
16519
17004
|
const configPath = findConfigFile(workspaceRoot);
|
|
16520
17005
|
if (!configPath) {
|
|
@@ -16709,7 +17194,7 @@ __export(check_exports, {
|
|
|
16709
17194
|
runCheck: () => runCheck
|
|
16710
17195
|
});
|
|
16711
17196
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
16712
|
-
import { resolve } from "node:path";
|
|
17197
|
+
import { resolve as resolve2 } from "node:path";
|
|
16713
17198
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
16714
17199
|
function parseArgs(args2) {
|
|
16715
17200
|
const options = {
|
|
@@ -16782,6 +17267,15 @@ function filterBySeverity(diagnostics, minSeverity) {
|
|
|
16782
17267
|
async function runCheck(args2) {
|
|
16783
17268
|
const options = parseArgs(args2);
|
|
16784
17269
|
const cwd = process.cwd();
|
|
17270
|
+
let explicitConfig = null;
|
|
17271
|
+
if (options.configPath) {
|
|
17272
|
+
try {
|
|
17273
|
+
explicitConfig = loadConfigFile(resolve2(cwd, options.configPath));
|
|
17274
|
+
} catch (err) {
|
|
17275
|
+
console.error(`spindle-lsp check: ${err instanceof Error ? err.message : String(err)}`);
|
|
17276
|
+
return 2;
|
|
17277
|
+
}
|
|
17278
|
+
}
|
|
16785
17279
|
const files = [];
|
|
16786
17280
|
for (const pattern of options.patterns) {
|
|
16787
17281
|
const matches = await glob(pattern, {
|
|
@@ -16802,28 +17296,28 @@ async function runCheck(args2) {
|
|
|
16802
17296
|
}
|
|
16803
17297
|
return 0;
|
|
16804
17298
|
}
|
|
16805
|
-
|
|
16806
|
-
|
|
16807
|
-
|
|
17299
|
+
const commonDir = uniqueFiles.map((f) => resolve2(f, "..")).reduce((a, b) => {
|
|
17300
|
+
while (!b.startsWith(a)) a = resolve2(a, "..");
|
|
17301
|
+
return a;
|
|
17302
|
+
});
|
|
17303
|
+
let projectConfig;
|
|
17304
|
+
if (explicitConfig) {
|
|
17305
|
+
projectConfig = explicitConfig;
|
|
16808
17306
|
} else {
|
|
16809
|
-
|
|
16810
|
-
configRoot = dirs.reduce((a, b) => {
|
|
16811
|
-
while (!b.startsWith(a)) a = resolve(a, "..");
|
|
16812
|
-
return a;
|
|
16813
|
-
});
|
|
17307
|
+
let configRoot = commonDir;
|
|
16814
17308
|
let search = configRoot;
|
|
16815
17309
|
for (let i = 0; i < 10; i++) {
|
|
16816
17310
|
if (findConfigFile(search)) {
|
|
16817
17311
|
configRoot = search;
|
|
16818
17312
|
break;
|
|
16819
17313
|
}
|
|
16820
|
-
const parent =
|
|
17314
|
+
const parent = resolve2(search, "..");
|
|
16821
17315
|
if (parent === search) break;
|
|
16822
17316
|
search = parent;
|
|
16823
17317
|
}
|
|
17318
|
+
projectConfig = loadConfigFromDisk(configRoot);
|
|
16824
17319
|
}
|
|
16825
|
-
const
|
|
16826
|
-
const workspace = new WorkspaceModel();
|
|
17320
|
+
const workspace = new WorkspaceModel({ workspaceRoot: commonDir });
|
|
16827
17321
|
const fileContents = /* @__PURE__ */ new Map();
|
|
16828
17322
|
for (const filePath of uniqueFiles) {
|
|
16829
17323
|
try {
|
|
@@ -16835,7 +17329,7 @@ async function runCheck(args2) {
|
|
|
16835
17329
|
}
|
|
16836
17330
|
workspace.initialize(fileContents);
|
|
16837
17331
|
if (Object.keys(projectConfig.macros).length > 0) {
|
|
16838
|
-
workspace.macros.
|
|
17332
|
+
workspace.macros.loadConfig(projectConfig.macros);
|
|
16839
17333
|
}
|
|
16840
17334
|
const diagOptions = {};
|
|
16841
17335
|
if (options.maxLineLength !== null) {
|
|
@@ -16922,7 +17416,7 @@ function splitPassages(text) {
|
|
|
16922
17416
|
function classifyPassage(header) {
|
|
16923
17417
|
const tagMatch = header.match(/\[([^\]]*)\]/g);
|
|
16924
17418
|
if (!tagMatch) return "normal";
|
|
16925
|
-
const tags = tagMatch.
|
|
17419
|
+
const tags = tagMatch.flatMap((t) => t.slice(1, -1).toLowerCase().split(/\s+/));
|
|
16926
17420
|
if (tags.includes("script")) return "script";
|
|
16927
17421
|
if (tags.includes("stylesheet")) return "stylesheet";
|
|
16928
17422
|
return "normal";
|
|
@@ -16941,6 +17435,10 @@ function segmentRegions(body) {
|
|
|
16941
17435
|
if (/^<script(\s|>)/i.test(trimmed)) {
|
|
16942
17436
|
const scriptLines = [line];
|
|
16943
17437
|
i++;
|
|
17438
|
+
if (/<\/script\s*>/i.test(line)) {
|
|
17439
|
+
regions.push({ type: "script", lines: scriptLines });
|
|
17440
|
+
continue;
|
|
17441
|
+
}
|
|
16944
17442
|
while (i < lines.length && !/<\/script>/i.test(lines[i])) {
|
|
16945
17443
|
scriptLines.push(lines[i]);
|
|
16946
17444
|
i++;
|
|
@@ -17165,7 +17663,7 @@ function replaceSvgBlocks(html) {
|
|
|
17165
17663
|
function restoreSvgBlocks(text, tokens) {
|
|
17166
17664
|
let result = text;
|
|
17167
17665
|
for (let i = 0; i < tokens.length; i++) {
|
|
17168
|
-
result = result.replace(`<!--SVG:${i}-->`, tokens[i]);
|
|
17666
|
+
result = result.replace(`<!--SVG:${i}-->`, () => tokens[i]);
|
|
17169
17667
|
}
|
|
17170
17668
|
return result;
|
|
17171
17669
|
}
|
|
@@ -17213,8 +17711,8 @@ function replaceSpindleTokens(html) {
|
|
|
17213
17711
|
function restoreSpindleTokens(text, tokens) {
|
|
17214
17712
|
let result = text;
|
|
17215
17713
|
for (let i = 0; i < tokens.length; i++) {
|
|
17216
|
-
result = result.replace(`<!--SP:${i}-->`, tokens[i]);
|
|
17217
|
-
result = result.replace(`__SP${i}__`, tokens[i]);
|
|
17714
|
+
result = result.replace(`<!--SP:${i}-->`, () => tokens[i]);
|
|
17715
|
+
result = result.replace(`__SP${i}__`, () => tokens[i]);
|
|
17218
17716
|
}
|
|
17219
17717
|
return result;
|
|
17220
17718
|
}
|
|
@@ -17257,6 +17755,7 @@ async function formatDocument(text, options) {
|
|
|
17257
17755
|
const isDedenting = options?.isDedentingSubMacro ?? ((name) => DEFAULT_DEDENTING.has(name.toLowerCase()));
|
|
17258
17756
|
const passages = splitPassages(text);
|
|
17259
17757
|
const resultLines = [];
|
|
17758
|
+
const hardBreakLines = /* @__PURE__ */ new Set();
|
|
17260
17759
|
for (let pi = 0; pi < passages.length; pi++) {
|
|
17261
17760
|
const passage = passages[pi];
|
|
17262
17761
|
if (pi > 0 && passage.header) {
|
|
@@ -17285,6 +17784,10 @@ async function formatDocument(text, options) {
|
|
|
17285
17784
|
const regions = segmentRegions(passage.body);
|
|
17286
17785
|
for (const region of regions) {
|
|
17287
17786
|
if (region.type === "script") {
|
|
17787
|
+
if (region.lines.length === 1) {
|
|
17788
|
+
resultLines.push(region.lines[0]);
|
|
17789
|
+
continue;
|
|
17790
|
+
}
|
|
17288
17791
|
const firstLine = region.lines[0];
|
|
17289
17792
|
const lastLine = region.lines[region.lines.length - 1];
|
|
17290
17793
|
const innerLines = region.lines.slice(1, region.lines.length - 1);
|
|
@@ -17319,49 +17822,92 @@ async function formatDocument(text, options) {
|
|
|
17319
17822
|
if (options?.maxLineLength) {
|
|
17320
17823
|
indented = wrapLines(indented, options.maxLineLength);
|
|
17321
17824
|
}
|
|
17322
|
-
|
|
17825
|
+
for (const line of indented) {
|
|
17826
|
+
if (line.endsWith(" ")) hardBreakLines.add(resultLines.length);
|
|
17827
|
+
resultLines.push(line);
|
|
17828
|
+
}
|
|
17323
17829
|
}
|
|
17324
17830
|
}
|
|
17325
|
-
let output = resultLines.map((l) => l.replace(/\s+$/, "")).join("\n");
|
|
17831
|
+
let output = resultLines.map((l, i) => hardBreakLines.has(i) ? l : l.replace(/\s+$/, "")).join("\n");
|
|
17326
17832
|
output = output.replace(/\n*$/, "\n");
|
|
17327
17833
|
return output;
|
|
17328
17834
|
}
|
|
17329
17835
|
function indentMacros(lines, isBlock, isDedenting) {
|
|
17330
|
-
const
|
|
17331
|
-
|
|
17332
|
-
|
|
17333
|
-
|
|
17334
|
-
|
|
17836
|
+
const bodies = [{ openLine: -1, minCol: Infinity, keepRelative: false }];
|
|
17837
|
+
const stack = [0];
|
|
17838
|
+
const info = [];
|
|
17839
|
+
const openBody = (line) => {
|
|
17840
|
+
bodies.push({ openLine: line, minCol: Infinity, keepRelative: false });
|
|
17841
|
+
stack.push(bodies.length - 1);
|
|
17842
|
+
};
|
|
17843
|
+
const closeBody = () => stack.length > 1 ? stack.pop() : void 0;
|
|
17844
|
+
const addLine = (col, text) => {
|
|
17845
|
+
const body = bodies[stack[stack.length - 1]];
|
|
17846
|
+
body.minCol = Math.min(body.minCol, col);
|
|
17847
|
+
if (LIST_ITEM_REGEX.test(text) || CODE_FENCE_REGEX.test(text)) body.keepRelative = true;
|
|
17848
|
+
info.push({ body: stack[stack.length - 1], col, text });
|
|
17849
|
+
};
|
|
17850
|
+
for (let i = 0; i < lines.length; i++) {
|
|
17851
|
+
const trimmed = lines[i].trim();
|
|
17335
17852
|
if (trimmed === "") {
|
|
17336
|
-
|
|
17853
|
+
info.push(null);
|
|
17337
17854
|
continue;
|
|
17338
17855
|
}
|
|
17856
|
+
const col = indentColumn(lines[i]);
|
|
17339
17857
|
const dedentMatch = trimmed.match(MACRO_OPEN_REGEX);
|
|
17340
17858
|
if (dedentMatch && isDedenting(dedentMatch[1])) {
|
|
17341
|
-
|
|
17342
|
-
|
|
17343
|
-
|
|
17859
|
+
const closed2 = closeBody();
|
|
17860
|
+
if (closed2 === void 0) addLine(col, trimmed);
|
|
17861
|
+
else info.push({ body: stack[stack.length - 1], closes: closed2, col, text: trimmed });
|
|
17862
|
+
openBody(i);
|
|
17344
17863
|
continue;
|
|
17345
17864
|
}
|
|
17346
|
-
const
|
|
17347
|
-
if (
|
|
17348
|
-
|
|
17349
|
-
}
|
|
17350
|
-
result.push(indentLevel > 0 ? " ".repeat(indentLevel) + trimmed : trimmed);
|
|
17865
|
+
const closed = MACRO_CLOSE_REGEX.test(trimmed) ? closeBody() : void 0;
|
|
17866
|
+
if (closed === void 0) addLine(col, trimmed);
|
|
17867
|
+
else info.push({ body: stack[stack.length - 1], closes: closed, col, text: trimmed });
|
|
17351
17868
|
const openMatch = trimmed.match(MACRO_OPEN_REGEX);
|
|
17352
17869
|
if (openMatch && isBlock(openMatch[1])) {
|
|
17353
|
-
|
|
17870
|
+
openBody(i);
|
|
17354
17871
|
}
|
|
17355
17872
|
const closeGlobal = /\{\/[A-Za-z][\w-]*\s*\}/g;
|
|
17356
17873
|
let cm;
|
|
17357
17874
|
while ((cm = closeGlobal.exec(trimmed)) !== null) {
|
|
17358
|
-
if (cm.index > 0)
|
|
17359
|
-
indentLevel = Math.max(0, indentLevel - 1);
|
|
17360
|
-
}
|
|
17875
|
+
if (cm.index > 0) closeBody();
|
|
17361
17876
|
}
|
|
17362
17877
|
}
|
|
17878
|
+
const outCol = [];
|
|
17879
|
+
const result = [];
|
|
17880
|
+
for (let i = 0; i < info.length; i++) {
|
|
17881
|
+
const line = info[i];
|
|
17882
|
+
if (!line) {
|
|
17883
|
+
outCol.push(0);
|
|
17884
|
+
result.push("");
|
|
17885
|
+
continue;
|
|
17886
|
+
}
|
|
17887
|
+
let col;
|
|
17888
|
+
if (line.closes !== void 0) {
|
|
17889
|
+
col = outCol[bodies[line.closes].openLine];
|
|
17890
|
+
} else {
|
|
17891
|
+
const body = bodies[line.body];
|
|
17892
|
+
const isRoot = body.openLine === -1;
|
|
17893
|
+
const base = isRoot ? 0 : outCol[body.openLine] + 2;
|
|
17894
|
+
col = base + (body.keepRelative ? line.col - (isRoot ? 0 : body.minCol) : 0);
|
|
17895
|
+
}
|
|
17896
|
+
outCol.push(col);
|
|
17897
|
+
const hardBreak = / {2,}$/.test(lines[i]) && info[i + 1] ? " " : "";
|
|
17898
|
+
result.push(" ".repeat(col) + line.text + hardBreak);
|
|
17899
|
+
}
|
|
17363
17900
|
return result;
|
|
17364
17901
|
}
|
|
17902
|
+
function indentColumn(line) {
|
|
17903
|
+
let col = 0;
|
|
17904
|
+
for (const ch of line) {
|
|
17905
|
+
if (ch === " ") col++;
|
|
17906
|
+
else if (ch === " ") col += 4 - col % 4;
|
|
17907
|
+
else break;
|
|
17908
|
+
}
|
|
17909
|
+
return col;
|
|
17910
|
+
}
|
|
17365
17911
|
async function formatRange(text, _range, options) {
|
|
17366
17912
|
return formatDocument(text, options);
|
|
17367
17913
|
}
|
|
@@ -17383,6 +17929,7 @@ function wrapLines(lines, maxLen) {
|
|
|
17383
17929
|
const indentMatch = line.match(/^(\s*)/);
|
|
17384
17930
|
const indent = indentMatch ? indentMatch[1] : "";
|
|
17385
17931
|
const wrapped = wordWrap(trimmed, maxLen, indent);
|
|
17932
|
+
if (line.endsWith(" ")) wrapped[wrapped.length - 1] += " ";
|
|
17386
17933
|
result.push(...wrapped);
|
|
17387
17934
|
}
|
|
17388
17935
|
return result;
|
|
@@ -17443,7 +17990,7 @@ function normalizePassageHeader(line) {
|
|
|
17443
17990
|
}
|
|
17444
17991
|
return `:: ${name}${suffix}`;
|
|
17445
17992
|
}
|
|
17446
|
-
var PASSAGE_HEADER_REGEX2, MACRO_OPEN_REGEX, MACRO_CLOSE_REGEX, DEFAULT_DEDENTING, formatPlugin;
|
|
17993
|
+
var PASSAGE_HEADER_REGEX2, MACRO_OPEN_REGEX, MACRO_CLOSE_REGEX, DEFAULT_DEDENTING, LIST_ITEM_REGEX, CODE_FENCE_REGEX, formatPlugin;
|
|
17447
17994
|
var init_format = __esm({
|
|
17448
17995
|
"src/plugins/format.ts"() {
|
|
17449
17996
|
"use strict";
|
|
@@ -17455,6 +18002,8 @@ var init_format = __esm({
|
|
|
17455
18002
|
MACRO_OPEN_REGEX = /^\{(?:[#.][a-zA-Z][\w-]*\s*)*([A-Za-z][\w-]*)\b/;
|
|
17456
18003
|
MACRO_CLOSE_REGEX = /^\{\/([A-Za-z][\w-]*)\b/;
|
|
17457
18004
|
DEFAULT_DEDENTING = /* @__PURE__ */ new Set(["else", "elseif", "next", "case", "default"]);
|
|
18005
|
+
LIST_ITEM_REGEX = /^(?:[-+*]|\d{1,9}[.)])(?:[ \t]|$)/;
|
|
18006
|
+
CODE_FENCE_REGEX = /^(?:`{3,}|~{3,})/;
|
|
17458
18007
|
formatPlugin = {
|
|
17459
18008
|
id: "format",
|
|
17460
18009
|
capabilities: {
|
|
@@ -39794,7 +40343,7 @@ var init_protocol = __esm({
|
|
|
39794
40343
|
return;
|
|
39795
40344
|
}
|
|
39796
40345
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
39797
|
-
await new Promise((
|
|
40346
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
|
|
39798
40347
|
options?.signal?.throwIfAborted();
|
|
39799
40348
|
}
|
|
39800
40349
|
} catch (error48) {
|
|
@@ -39811,7 +40360,7 @@ var init_protocol = __esm({
|
|
|
39811
40360
|
*/
|
|
39812
40361
|
request(request, resultSchema, options) {
|
|
39813
40362
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
39814
|
-
return new Promise((
|
|
40363
|
+
return new Promise((resolve4, reject) => {
|
|
39815
40364
|
const earlyReject = (error48) => {
|
|
39816
40365
|
reject(error48);
|
|
39817
40366
|
};
|
|
@@ -39889,7 +40438,7 @@ var init_protocol = __esm({
|
|
|
39889
40438
|
if (!parseResult.success) {
|
|
39890
40439
|
reject(parseResult.error);
|
|
39891
40440
|
} else {
|
|
39892
|
-
|
|
40441
|
+
resolve4(parseResult.data);
|
|
39893
40442
|
}
|
|
39894
40443
|
} catch (error48) {
|
|
39895
40444
|
reject(error48);
|
|
@@ -40150,12 +40699,12 @@ var init_protocol = __esm({
|
|
|
40150
40699
|
}
|
|
40151
40700
|
} catch {
|
|
40152
40701
|
}
|
|
40153
|
-
return new Promise((
|
|
40702
|
+
return new Promise((resolve4, reject) => {
|
|
40154
40703
|
if (signal.aborted) {
|
|
40155
40704
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
40156
40705
|
return;
|
|
40157
40706
|
}
|
|
40158
|
-
const timeoutId = setTimeout(
|
|
40707
|
+
const timeoutId = setTimeout(resolve4, interval);
|
|
40159
40708
|
signal.addEventListener("abort", () => {
|
|
40160
40709
|
clearTimeout(timeoutId);
|
|
40161
40710
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -43182,7 +43731,7 @@ var require_compile = __commonJS({
|
|
|
43182
43731
|
const schOrFunc = root.refs[ref];
|
|
43183
43732
|
if (schOrFunc)
|
|
43184
43733
|
return schOrFunc;
|
|
43185
|
-
let _sch =
|
|
43734
|
+
let _sch = resolve4.call(this, root, ref);
|
|
43186
43735
|
if (_sch === void 0) {
|
|
43187
43736
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
43188
43737
|
const { schemaId } = this.opts;
|
|
@@ -43209,7 +43758,7 @@ var require_compile = __commonJS({
|
|
|
43209
43758
|
function sameSchemaEnv(s1, s2) {
|
|
43210
43759
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
43211
43760
|
}
|
|
43212
|
-
function
|
|
43761
|
+
function resolve4(root, ref) {
|
|
43213
43762
|
let sch;
|
|
43214
43763
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
43215
43764
|
ref = sch;
|
|
@@ -43784,7 +44333,7 @@ var require_fast_uri = __commonJS({
|
|
|
43784
44333
|
}
|
|
43785
44334
|
return uri;
|
|
43786
44335
|
}
|
|
43787
|
-
function
|
|
44336
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
43788
44337
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
43789
44338
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
43790
44339
|
schemelessOptions.skipEscape = true;
|
|
@@ -44011,7 +44560,7 @@ var require_fast_uri = __commonJS({
|
|
|
44011
44560
|
var fastUri = {
|
|
44012
44561
|
SCHEMES,
|
|
44013
44562
|
normalize: normalize2,
|
|
44014
|
-
resolve:
|
|
44563
|
+
resolve: resolve4,
|
|
44015
44564
|
resolveComponent,
|
|
44016
44565
|
equal,
|
|
44017
44566
|
serialize,
|
|
@@ -48135,7 +48684,7 @@ var init_mcp = __esm({
|
|
|
48135
48684
|
let task = createTaskResult.task;
|
|
48136
48685
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
48137
48686
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
48138
|
-
await new Promise((
|
|
48687
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
|
|
48139
48688
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
48140
48689
|
if (!updatedTask) {
|
|
48141
48690
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -48726,12 +49275,12 @@ var init_stdio2 = __esm({
|
|
|
48726
49275
|
this.onclose?.();
|
|
48727
49276
|
}
|
|
48728
49277
|
send(message) {
|
|
48729
|
-
return new Promise((
|
|
49278
|
+
return new Promise((resolve4) => {
|
|
48730
49279
|
const json2 = serializeMessage(message);
|
|
48731
49280
|
if (this._stdout.write(json2)) {
|
|
48732
|
-
|
|
49281
|
+
resolve4();
|
|
48733
49282
|
} else {
|
|
48734
|
-
this._stdout.once("drain",
|
|
49283
|
+
this._stdout.once("drain", resolve4);
|
|
48735
49284
|
}
|
|
48736
49285
|
});
|
|
48737
49286
|
}
|
|
@@ -48745,7 +49294,7 @@ __export(server_exports, {
|
|
|
48745
49294
|
startMcpServer: () => startMcpServer
|
|
48746
49295
|
});
|
|
48747
49296
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
|
|
48748
|
-
import { resolve as
|
|
49297
|
+
import { resolve as resolve3 } from "node:path";
|
|
48749
49298
|
import { pathToFileURL as pathToFileURL3, fileURLToPath as fileURLToPath5 } from "node:url";
|
|
48750
49299
|
function filterBySeverity2(diagnostics, minSeverity) {
|
|
48751
49300
|
const minIdx = SEVERITY_ORDER2.indexOf(minSeverity);
|
|
@@ -48763,9 +49312,9 @@ async function resolveFiles(pattern, cwd) {
|
|
|
48763
49312
|
return [...new Set(matches)];
|
|
48764
49313
|
}
|
|
48765
49314
|
function findConfigRoot(files) {
|
|
48766
|
-
const dirs = files.map((f) =>
|
|
49315
|
+
const dirs = files.map((f) => resolve3(f, ".."));
|
|
48767
49316
|
let configRoot = dirs.reduce((a, b) => {
|
|
48768
|
-
while (!b.startsWith(a)) a =
|
|
49317
|
+
while (!b.startsWith(a)) a = resolve3(a, "..");
|
|
48769
49318
|
return a;
|
|
48770
49319
|
});
|
|
48771
49320
|
let search = configRoot;
|
|
@@ -48774,7 +49323,7 @@ function findConfigRoot(files) {
|
|
|
48774
49323
|
configRoot = search;
|
|
48775
49324
|
break;
|
|
48776
49325
|
}
|
|
48777
|
-
const parent =
|
|
49326
|
+
const parent = resolve3(search, "..");
|
|
48778
49327
|
if (parent === search) break;
|
|
48779
49328
|
search = parent;
|
|
48780
49329
|
}
|
|
@@ -48783,7 +49332,7 @@ function findConfigRoot(files) {
|
|
|
48783
49332
|
function createWorkspace(files) {
|
|
48784
49333
|
const configRoot = findConfigRoot(files);
|
|
48785
49334
|
const projectConfig = loadConfigFromDisk(configRoot);
|
|
48786
|
-
const workspace = new WorkspaceModel();
|
|
49335
|
+
const workspace = new WorkspaceModel({ workspaceRoot: configRoot });
|
|
48787
49336
|
const fileContents = /* @__PURE__ */ new Map();
|
|
48788
49337
|
for (const filePath of files) {
|
|
48789
49338
|
try {
|
|
@@ -48795,7 +49344,7 @@ function createWorkspace(files) {
|
|
|
48795
49344
|
}
|
|
48796
49345
|
workspace.initialize(fileContents);
|
|
48797
49346
|
if (Object.keys(projectConfig.macros).length > 0) {
|
|
48798
|
-
workspace.macros.
|
|
49347
|
+
workspace.macros.loadConfig(projectConfig.macros);
|
|
48799
49348
|
}
|
|
48800
49349
|
return workspace;
|
|
48801
49350
|
}
|
|
@@ -49976,8 +50525,8 @@ var require_semaphore = __commonJS({
|
|
|
49976
50525
|
this._waiting = [];
|
|
49977
50526
|
}
|
|
49978
50527
|
lock(thunk) {
|
|
49979
|
-
return new Promise((
|
|
49980
|
-
this._waiting.push({ thunk, resolve:
|
|
50528
|
+
return new Promise((resolve4, reject) => {
|
|
50529
|
+
this._waiting.push({ thunk, resolve: resolve4, reject });
|
|
49981
50530
|
this.runNext();
|
|
49982
50531
|
});
|
|
49983
50532
|
}
|
|
@@ -51467,9 +52016,9 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
51467
52016
|
if (typeof cancellationStrategy.sender.enableCancellation === "function") {
|
|
51468
52017
|
cancellationStrategy.sender.enableCancellation(requestMessage);
|
|
51469
52018
|
}
|
|
51470
|
-
return new Promise(async (
|
|
52019
|
+
return new Promise(async (resolve4, reject) => {
|
|
51471
52020
|
const resolveWithCleanup = (r) => {
|
|
51472
|
-
|
|
52021
|
+
resolve4(r);
|
|
51473
52022
|
cancellationStrategy.sender.cleanup(id);
|
|
51474
52023
|
disposable?.dispose();
|
|
51475
52024
|
};
|
|
@@ -51880,10 +52429,10 @@ var require_ril = __commonJS({
|
|
|
51880
52429
|
return api_1.Disposable.create(() => this.stream.off("end", listener));
|
|
51881
52430
|
}
|
|
51882
52431
|
write(data, encoding) {
|
|
51883
|
-
return new Promise((
|
|
52432
|
+
return new Promise((resolve4, reject) => {
|
|
51884
52433
|
const callback = (error48) => {
|
|
51885
52434
|
if (error48 === void 0 || error48 === null) {
|
|
51886
|
-
|
|
52435
|
+
resolve4();
|
|
51887
52436
|
} else {
|
|
51888
52437
|
reject(error48);
|
|
51889
52438
|
}
|
|
@@ -52135,10 +52684,10 @@ var require_main = __commonJS({
|
|
|
52135
52684
|
exports.generateRandomPipeName = generateRandomPipeName;
|
|
52136
52685
|
function createClientPipeTransport(pipeName, encoding = "utf-8") {
|
|
52137
52686
|
let connectResolve;
|
|
52138
|
-
const connected = new Promise((
|
|
52139
|
-
connectResolve =
|
|
52687
|
+
const connected = new Promise((resolve4, _reject) => {
|
|
52688
|
+
connectResolve = resolve4;
|
|
52140
52689
|
});
|
|
52141
|
-
return new Promise((
|
|
52690
|
+
return new Promise((resolve4, reject) => {
|
|
52142
52691
|
let server = (0, net_1.createServer)((socket) => {
|
|
52143
52692
|
server.close();
|
|
52144
52693
|
connectResolve([
|
|
@@ -52149,7 +52698,7 @@ var require_main = __commonJS({
|
|
|
52149
52698
|
server.on("error", reject);
|
|
52150
52699
|
server.listen(pipeName, () => {
|
|
52151
52700
|
server.removeListener("error", reject);
|
|
52152
|
-
|
|
52701
|
+
resolve4({
|
|
52153
52702
|
onConnected: () => {
|
|
52154
52703
|
return connected;
|
|
52155
52704
|
}
|
|
@@ -52168,10 +52717,10 @@ var require_main = __commonJS({
|
|
|
52168
52717
|
exports.createServerPipeTransport = createServerPipeTransport;
|
|
52169
52718
|
function createClientSocketTransport(port, encoding = "utf-8") {
|
|
52170
52719
|
let connectResolve;
|
|
52171
|
-
const connected = new Promise((
|
|
52172
|
-
connectResolve =
|
|
52720
|
+
const connected = new Promise((resolve4, _reject) => {
|
|
52721
|
+
connectResolve = resolve4;
|
|
52173
52722
|
});
|
|
52174
|
-
return new Promise((
|
|
52723
|
+
return new Promise((resolve4, reject) => {
|
|
52175
52724
|
const server = (0, net_1.createServer)((socket) => {
|
|
52176
52725
|
server.close();
|
|
52177
52726
|
connectResolve([
|
|
@@ -52182,7 +52731,7 @@ var require_main = __commonJS({
|
|
|
52182
52731
|
server.on("error", reject);
|
|
52183
52732
|
server.listen(port, "127.0.0.1", () => {
|
|
52184
52733
|
server.removeListener("error", reject);
|
|
52185
|
-
|
|
52734
|
+
resolve4({
|
|
52186
52735
|
onConnected: () => {
|
|
52187
52736
|
return connected;
|
|
52188
52737
|
}
|
|
@@ -56968,8 +57517,8 @@ var require_server = __commonJS({
|
|
|
56968
57517
|
if (value instanceof Promise) {
|
|
56969
57518
|
return value;
|
|
56970
57519
|
} else if (Is.thenable(value)) {
|
|
56971
|
-
return new Promise((
|
|
56972
|
-
value.then((resolved) =>
|
|
57520
|
+
return new Promise((resolve4, reject) => {
|
|
57521
|
+
value.then((resolved) => resolve4(resolved), (error48) => reject(error48));
|
|
56973
57522
|
});
|
|
56974
57523
|
} else {
|
|
56975
57524
|
return Promise.resolve(value);
|
|
@@ -57239,7 +57788,7 @@ var require_files = __commonJS({
|
|
|
57239
57788
|
function isWindows() {
|
|
57240
57789
|
return process.platform === "win32";
|
|
57241
57790
|
}
|
|
57242
|
-
function
|
|
57791
|
+
function resolve4(moduleName, nodePath, cwd, tracer) {
|
|
57243
57792
|
const nodePathKey = "NODE_PATH";
|
|
57244
57793
|
const app = [
|
|
57245
57794
|
"var p = process;",
|
|
@@ -57258,7 +57807,7 @@ var require_files = __commonJS({
|
|
|
57258
57807
|
"}",
|
|
57259
57808
|
"});"
|
|
57260
57809
|
].join("");
|
|
57261
|
-
return new Promise((
|
|
57810
|
+
return new Promise((resolve5, reject) => {
|
|
57262
57811
|
let env = process.env;
|
|
57263
57812
|
let newEnv = /* @__PURE__ */ Object.create(null);
|
|
57264
57813
|
Object.keys(env).forEach((key) => newEnv[key] = env[key]);
|
|
@@ -57290,7 +57839,7 @@ var require_files = __commonJS({
|
|
|
57290
57839
|
if (message2.c === "r") {
|
|
57291
57840
|
cp.send({ c: "e" });
|
|
57292
57841
|
if (message2.s) {
|
|
57293
|
-
|
|
57842
|
+
resolve5(message2.r);
|
|
57294
57843
|
} else {
|
|
57295
57844
|
reject(new Error(`Failed to resolve module: ${moduleName}`));
|
|
57296
57845
|
}
|
|
@@ -57306,7 +57855,7 @@ var require_files = __commonJS({
|
|
|
57306
57855
|
}
|
|
57307
57856
|
});
|
|
57308
57857
|
}
|
|
57309
|
-
exports.resolve =
|
|
57858
|
+
exports.resolve = resolve4;
|
|
57310
57859
|
function resolveGlobalNodePath(tracer) {
|
|
57311
57860
|
let npmCommand = "npm";
|
|
57312
57861
|
const env = /* @__PURE__ */ Object.create(null);
|
|
@@ -57421,17 +57970,17 @@ var require_files = __commonJS({
|
|
|
57421
57970
|
if (!path2.isAbsolute(nodePath)) {
|
|
57422
57971
|
nodePath = path2.join(workspaceRoot, nodePath);
|
|
57423
57972
|
}
|
|
57424
|
-
return
|
|
57973
|
+
return resolve4(moduleName, nodePath, nodePath, tracer).then((value) => {
|
|
57425
57974
|
if (FileSystem.isParent(nodePath, value)) {
|
|
57426
57975
|
return value;
|
|
57427
57976
|
} else {
|
|
57428
57977
|
return Promise.reject(new Error(`Failed to load ${moduleName} from node path location.`));
|
|
57429
57978
|
}
|
|
57430
57979
|
}).then(void 0, (_error) => {
|
|
57431
|
-
return
|
|
57980
|
+
return resolve4(moduleName, resolveGlobalNodePath(tracer), workspaceRoot, tracer);
|
|
57432
57981
|
});
|
|
57433
57982
|
} else {
|
|
57434
|
-
return
|
|
57983
|
+
return resolve4(moduleName, resolveGlobalNodePath(tracer), workspaceRoot, tracer);
|
|
57435
57984
|
}
|
|
57436
57985
|
}
|
|
57437
57986
|
exports.resolveModulePath = resolveModulePath;
|
|
@@ -58061,7 +58610,7 @@ function getCompletions(uri, position, triggerChar, workspace) {
|
|
|
58061
58610
|
if (position.line >= lines.length) return [];
|
|
58062
58611
|
const lineText = lines[position.line].substring(0, position.character);
|
|
58063
58612
|
if (/\{\/[A-Za-z\w-]*$/.test(lineText)) {
|
|
58064
|
-
return getClosingMacroCompletions(text, position, workspace);
|
|
58613
|
+
return getClosingMacroCompletions(uri, text, position, workspace);
|
|
58065
58614
|
}
|
|
58066
58615
|
const transientDotPathMatch = /%([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)?$/.exec(lineText);
|
|
58067
58616
|
if (transientDotPathMatch) {
|
|
@@ -58091,11 +58640,18 @@ function getCompletions(uri, position, triggerChar, workspace) {
|
|
|
58091
58640
|
}
|
|
58092
58641
|
return [];
|
|
58093
58642
|
}
|
|
58094
|
-
function getClosingMacroCompletions(text, position, workspace) {
|
|
58643
|
+
function getClosingMacroCompletions(uri, text, position, workspace) {
|
|
58644
|
+
const passages = workspace.passages.getPassagesInDocument(uri);
|
|
58095
58645
|
const macros = parseMacros(text);
|
|
58096
|
-
pairMacros(
|
|
58646
|
+
pairMacros(
|
|
58647
|
+
macros,
|
|
58648
|
+
(name) => workspace.macros.isBlock(name),
|
|
58649
|
+
passages.map((p) => p.range.start.line)
|
|
58650
|
+
);
|
|
58651
|
+
const passageStart = workspace.passages.getPassageAt(uri, position.line)?.range.start.line ?? 0;
|
|
58097
58652
|
const openStack = [];
|
|
58098
58653
|
for (const macro of macros) {
|
|
58654
|
+
if (macro.range.start.line < passageStart) continue;
|
|
58099
58655
|
if (macro.range.start.line > position.line || macro.range.start.line === position.line && macro.range.start.character >= position.character) {
|
|
58100
58656
|
break;
|
|
58101
58657
|
}
|
|
@@ -58146,7 +58702,7 @@ function getMacroCompletions(workspace) {
|
|
|
58146
58702
|
kind: 3,
|
|
58147
58703
|
// CompletionItemKind.Function
|
|
58148
58704
|
detail: `(widget) ${widget.name}`,
|
|
58149
|
-
documentation: widget.params.length > 0 ? `Parameters: ${widget.params.
|
|
58705
|
+
documentation: widget.params.length > 0 ? `Parameters: ${widget.params.join(", ")}` : void 0
|
|
58150
58706
|
});
|
|
58151
58707
|
}
|
|
58152
58708
|
return items;
|
|
@@ -58421,7 +58977,7 @@ function getWidgetHover(line, position, workspace) {
|
|
|
58421
58977
|
return null;
|
|
58422
58978
|
}
|
|
58423
58979
|
function buildWidgetHover(widget, line, nameStart, nameEnd) {
|
|
58424
|
-
const sig = widget.params.length > 0 ? widget.params.
|
|
58980
|
+
const sig = widget.params.length > 0 ? widget.params.join(", ") : "no parameters";
|
|
58425
58981
|
return {
|
|
58426
58982
|
contents: `**Widget** \`${widget.name}\`
|
|
58427
58983
|
|
|
@@ -58495,7 +59051,7 @@ function getSignatureHelp(uri, position, workspace) {
|
|
|
58495
59051
|
}
|
|
58496
59052
|
const widget = workspace.widgets.getWidget(macroName);
|
|
58497
59053
|
if (widget && widget.params.length > 0) {
|
|
58498
|
-
const paramLabels = widget.params
|
|
59054
|
+
const paramLabels = widget.params;
|
|
58499
59055
|
return {
|
|
58500
59056
|
signatures: [{
|
|
58501
59057
|
label: `{${macroName} ${paramLabels.join(", ")}}`,
|
|
@@ -58551,53 +59107,21 @@ function getDefinition(uri, position, workspace) {
|
|
|
58551
59107
|
const lines = text.split("\n");
|
|
58552
59108
|
if (position.line >= lines.length) return null;
|
|
58553
59109
|
const line = lines[position.line];
|
|
58554
|
-
const
|
|
58555
|
-
if (
|
|
58556
|
-
const macroPassageResult = getMacroPassageDefinition(line, position, workspace);
|
|
58557
|
-
if (macroPassageResult) return macroPassageResult;
|
|
59110
|
+
const passageResult = getPassageRefDefinition(text, position, workspace);
|
|
59111
|
+
if (passageResult) return passageResult;
|
|
58558
59112
|
const widgetResult = getWidgetDefinition(line, position, workspace);
|
|
58559
59113
|
if (widgetResult) return widgetResult;
|
|
58560
59114
|
return null;
|
|
58561
59115
|
}
|
|
58562
|
-
function
|
|
58563
|
-
const
|
|
58564
|
-
|
|
58565
|
-
|
|
58566
|
-
|
|
58567
|
-
|
|
58568
|
-
|
|
58569
|
-
|
|
58570
|
-
|
|
58571
|
-
};
|
|
58572
|
-
}
|
|
58573
|
-
}
|
|
58574
|
-
}
|
|
58575
|
-
return null;
|
|
58576
|
-
}
|
|
58577
|
-
function getMacroPassageDefinition(line, position, workspace) {
|
|
58578
|
-
const patterns = [
|
|
58579
|
-
/\{(?:goto|include)\s+"([^"]+)"\s*\}/gi,
|
|
58580
|
-
/\{(?:link|button)\s+"[^"]*"\s+"([^"]+)"\s*\}/gi
|
|
58581
|
-
];
|
|
58582
|
-
for (const pattern of patterns) {
|
|
58583
|
-
pattern.lastIndex = 0;
|
|
58584
|
-
let match2;
|
|
58585
|
-
while ((match2 = pattern.exec(line)) !== null) {
|
|
58586
|
-
const passageName = match2[1];
|
|
58587
|
-
const nameStart = match2.index + match2[0].indexOf(passageName);
|
|
58588
|
-
const nameEnd = nameStart + passageName.length;
|
|
58589
|
-
if (position.character >= nameStart && position.character <= nameEnd) {
|
|
58590
|
-
const passage = workspace.passages.getPassage(passageName);
|
|
58591
|
-
if (passage) {
|
|
58592
|
-
return {
|
|
58593
|
-
uri: passage.uri,
|
|
58594
|
-
range: passage.headerEnd
|
|
58595
|
-
};
|
|
58596
|
-
}
|
|
58597
|
-
}
|
|
58598
|
-
}
|
|
58599
|
-
}
|
|
58600
|
-
return null;
|
|
59116
|
+
function getPassageRefDefinition(text, position, workspace) {
|
|
59117
|
+
const ref = findPassageRefAt(text, position);
|
|
59118
|
+
if (!ref) return null;
|
|
59119
|
+
const passage = workspace.passages.getPassage(ref.name);
|
|
59120
|
+
if (!passage) return null;
|
|
59121
|
+
return {
|
|
59122
|
+
uri: passage.uri,
|
|
59123
|
+
range: passage.headerEnd
|
|
59124
|
+
};
|
|
58601
59125
|
}
|
|
58602
59126
|
function getWidgetDefinition(line, position, workspace) {
|
|
58603
59127
|
const re = /\{([A-Za-z_$][\w$]*)/g;
|
|
@@ -58697,19 +59221,25 @@ function findReferences(uri, position, workspace, includeDeclaration) {
|
|
|
58697
59221
|
}
|
|
58698
59222
|
}
|
|
58699
59223
|
{
|
|
58700
|
-
const widgetRegex = /\{([A-Za-z_$][\w$]*)/g;
|
|
59224
|
+
const widgetRegex = /\{\/?([A-Za-z_$][\w$]*)/g;
|
|
58701
59225
|
let match2;
|
|
58702
59226
|
while ((match2 = widgetRegex.exec(line)) !== null) {
|
|
58703
59227
|
const name = match2[1];
|
|
58704
|
-
const nameStart = match2.index +
|
|
59228
|
+
const nameStart = match2.index + match2[0].length - name.length;
|
|
58705
59229
|
const nameEnd = nameStart + name.length;
|
|
58706
59230
|
if (position.character >= nameStart && position.character <= nameEnd) {
|
|
58707
|
-
|
|
59231
|
+
const widget = workspace.widgets.getWidget(name);
|
|
59232
|
+
const isClosing = match2[0][1] === "/";
|
|
59233
|
+
if (!workspace.macros.getMacro(name) && widget && (!isClosing || widget.block)) {
|
|
58708
59234
|
return findWidgetReferences(name, workspace, includeDeclaration);
|
|
58709
59235
|
}
|
|
58710
59236
|
}
|
|
58711
59237
|
}
|
|
58712
59238
|
}
|
|
59239
|
+
const passageRef = findPassageRefAt(text, position);
|
|
59240
|
+
if (passageRef) {
|
|
59241
|
+
return findPassageReferences(passageRef.name, workspace, includeDeclaration);
|
|
59242
|
+
}
|
|
58713
59243
|
{
|
|
58714
59244
|
const allPassages = workspace.passages.getAllPassages();
|
|
58715
59245
|
const passageNames = new Set(allPassages.map((p) => p.name));
|
|
@@ -58735,39 +59265,16 @@ function findPassageReferences(passageName, workspace, includeDeclaration) {
|
|
|
58735
59265
|
if (passage) {
|
|
58736
59266
|
locations.push({
|
|
58737
59267
|
uri: passage.uri,
|
|
58738
|
-
range: passage.
|
|
59268
|
+
range: passage.nameRange
|
|
58739
59269
|
});
|
|
58740
59270
|
}
|
|
58741
59271
|
}
|
|
58742
|
-
const gotoRegex = /\{(?:goto|include)\s+"([^"]+)"\s*\}/gi;
|
|
58743
|
-
const linkMacroRegex = /\{(?:link|button)\s+"[^"]*"\s+"([^"]+)"\s*\}/gi;
|
|
58744
59272
|
for (const docUri of workspace.documents.getUris()) {
|
|
58745
59273
|
const docText = workspace.documents.getText(docUri);
|
|
58746
59274
|
if (!docText) continue;
|
|
58747
|
-
const
|
|
58748
|
-
|
|
58749
|
-
|
|
58750
|
-
locations.push({ uri: docUri, range: link.range });
|
|
58751
|
-
}
|
|
58752
|
-
}
|
|
58753
|
-
const lines = docText.split("\n");
|
|
58754
|
-
for (let lineNum = 0; lineNum < lines.length; lineNum++) {
|
|
58755
|
-
const line = lines[lineNum];
|
|
58756
|
-
for (const regex of [gotoRegex, linkMacroRegex]) {
|
|
58757
|
-
regex.lastIndex = 0;
|
|
58758
|
-
let match2;
|
|
58759
|
-
while ((match2 = regex.exec(line)) !== null) {
|
|
58760
|
-
if (match2[1] === passageName) {
|
|
58761
|
-
const nameStart = match2.index + match2[0].indexOf(match2[1]);
|
|
58762
|
-
locations.push({
|
|
58763
|
-
uri: docUri,
|
|
58764
|
-
range: {
|
|
58765
|
-
start: { line: lineNum, character: nameStart },
|
|
58766
|
-
end: { line: lineNum, character: nameStart + match2[1].length }
|
|
58767
|
-
}
|
|
58768
|
-
});
|
|
58769
|
-
}
|
|
58770
|
-
}
|
|
59275
|
+
for (const ref of [...parseLinks(docText), ...parseMacroPassageRefs(docText)]) {
|
|
59276
|
+
if (ref.name === passageName) {
|
|
59277
|
+
locations.push({ uri: docUri, range: ref.range });
|
|
58771
59278
|
}
|
|
58772
59279
|
}
|
|
58773
59280
|
}
|
|
@@ -58806,30 +59313,30 @@ function findTransientReferences(varName, workspace, includeDeclaration) {
|
|
|
58806
59313
|
}
|
|
58807
59314
|
function findWidgetReferences(widgetName, workspace, includeDeclaration) {
|
|
58808
59315
|
const locations = [];
|
|
58809
|
-
|
|
58810
|
-
|
|
58811
|
-
|
|
58812
|
-
locations.push({ uri: widget.uri, range: widget.range });
|
|
58813
|
-
}
|
|
59316
|
+
const widget = workspace.widgets.getWidget(widgetName);
|
|
59317
|
+
if (includeDeclaration && widget) {
|
|
59318
|
+
locations.push({ uri: widget.uri, range: widget.range });
|
|
58814
59319
|
}
|
|
58815
|
-
const widgetInvocationRegex = /\{([A-Za-z_$][\w$]*)\b/g;
|
|
59320
|
+
const widgetInvocationRegex = /\{(\/)?([A-Za-z_$][\w$]*)\b/g;
|
|
59321
|
+
const lowerName = widgetName.toLowerCase();
|
|
59322
|
+
const isBlock = widget?.block ?? false;
|
|
58816
59323
|
for (const docUri of workspace.documents.getUris()) {
|
|
58817
59324
|
const docText = workspace.documents.getText(docUri);
|
|
58818
59325
|
if (!docText) continue;
|
|
58819
59326
|
const lines = docText.split("\n");
|
|
58820
59327
|
for (let lineNum = 0; lineNum < lines.length; lineNum++) {
|
|
58821
59328
|
const line = lines[lineNum];
|
|
58822
|
-
if (/\{widget\s+"/i.test(line)) continue;
|
|
58823
59329
|
widgetInvocationRegex.lastIndex = 0;
|
|
58824
59330
|
let match2;
|
|
58825
59331
|
while ((match2 = widgetInvocationRegex.exec(line)) !== null) {
|
|
58826
|
-
if (match2[1]
|
|
58827
|
-
|
|
59332
|
+
if (match2[1] && !isBlock) continue;
|
|
59333
|
+
if (match2[2].toLowerCase() === lowerName) {
|
|
59334
|
+
const nameStart = match2.index + 1 + (match2[1] ? 1 : 0);
|
|
58828
59335
|
locations.push({
|
|
58829
59336
|
uri: docUri,
|
|
58830
59337
|
range: {
|
|
58831
59338
|
start: { line: lineNum, character: nameStart },
|
|
58832
|
-
end: { line: lineNum, character: nameStart +
|
|
59339
|
+
end: { line: lineNum, character: nameStart + match2[2].length }
|
|
58833
59340
|
}
|
|
58834
59341
|
});
|
|
58835
59342
|
}
|
|
@@ -58897,10 +59404,13 @@ function computeRename(uri, position, newName, workspace) {
|
|
|
58897
59404
|
}
|
|
58898
59405
|
case "variable": {
|
|
58899
59406
|
const bareName = newName.startsWith("$") ? newName.slice(1) : newName.startsWith("%") ? newName.slice(1) : newName;
|
|
58900
|
-
const
|
|
58901
|
-
const refs = isTransient ? findTransientReferences(symbol2.name, workspace, true) : findVariableReferences(symbol2.name, workspace, true);
|
|
59407
|
+
const refs = symbol2.sigil === "%" ? findTransientReferences(symbol2.name, workspace, true) : findVariableReferences(symbol2.name, workspace, true);
|
|
58902
59408
|
for (const ref of refs) {
|
|
58903
|
-
|
|
59409
|
+
const start = ref.range.start.character + 1;
|
|
59410
|
+
addEdit(ref.uri, {
|
|
59411
|
+
start: { line: ref.range.start.line, character: start },
|
|
59412
|
+
end: { line: ref.range.start.line, character: start + symbol2.name.length }
|
|
59413
|
+
}, bareName);
|
|
58904
59414
|
}
|
|
58905
59415
|
break;
|
|
58906
59416
|
}
|
|
@@ -58911,23 +59421,7 @@ function computeRename(uri, position, newName, workspace) {
|
|
|
58911
59421
|
}
|
|
58912
59422
|
const widget = workspace.widgets.getWidget(symbol2.name);
|
|
58913
59423
|
if (widget) {
|
|
58914
|
-
|
|
58915
|
-
if (docText) {
|
|
58916
|
-
const lines = docText.split("\n");
|
|
58917
|
-
const defLine = lines[widget.range.start.line];
|
|
58918
|
-
if (defLine) {
|
|
58919
|
-
const defSlice = defLine.slice(widget.range.start.character);
|
|
58920
|
-
const nameMatch = /\{widget\s+"([^"]+)"/.exec(defSlice);
|
|
58921
|
-
if (nameMatch) {
|
|
58922
|
-
const nameOffsetInSlice = defSlice.indexOf(nameMatch[1]);
|
|
58923
|
-
const nameStart = widget.range.start.character + nameOffsetInSlice;
|
|
58924
|
-
addEdit(widget.uri, {
|
|
58925
|
-
start: { line: widget.range.start.line, character: nameStart },
|
|
58926
|
-
end: { line: widget.range.start.line, character: nameStart + symbol2.name.length }
|
|
58927
|
-
}, newName);
|
|
58928
|
-
}
|
|
58929
|
-
}
|
|
58930
|
-
}
|
|
59424
|
+
addEdit(widget.uri, widget.nameRange, newName);
|
|
58931
59425
|
}
|
|
58932
59426
|
break;
|
|
58933
59427
|
}
|
|
@@ -58969,6 +59463,7 @@ function resolveSymbolAtCursor(uri, position, workspace) {
|
|
|
58969
59463
|
return {
|
|
58970
59464
|
kind: "variable",
|
|
58971
59465
|
name: match2[1],
|
|
59466
|
+
sigil: "$",
|
|
58972
59467
|
range: {
|
|
58973
59468
|
start: { line: position.line, character: start },
|
|
58974
59469
|
end: { line: position.line, character: end }
|
|
@@ -58987,6 +59482,7 @@ function resolveSymbolAtCursor(uri, position, workspace) {
|
|
|
58987
59482
|
return {
|
|
58988
59483
|
kind: "variable",
|
|
58989
59484
|
name: match2[1],
|
|
59485
|
+
sigil: "%",
|
|
58990
59486
|
range: {
|
|
58991
59487
|
start: { line: position.line, character: start },
|
|
58992
59488
|
end: { line: position.line, character: end }
|
|
@@ -58995,34 +59491,23 @@ function resolveSymbolAtCursor(uri, position, workspace) {
|
|
|
58995
59491
|
}
|
|
58996
59492
|
}
|
|
58997
59493
|
}
|
|
58998
|
-
{
|
|
58999
|
-
const
|
|
59000
|
-
|
|
59001
|
-
|
|
59002
|
-
const name = match2[1];
|
|
59003
|
-
const nameStart = match2.index + match2[0].indexOf(name);
|
|
59004
|
-
const nameEnd = nameStart + name.length;
|
|
59005
|
-
if (position.character >= nameStart && position.character <= nameEnd) {
|
|
59006
|
-
return {
|
|
59007
|
-
kind: "widget",
|
|
59008
|
-
name,
|
|
59009
|
-
range: {
|
|
59010
|
-
start: { line: position.line, character: nameStart },
|
|
59011
|
-
end: { line: position.line, character: nameEnd }
|
|
59012
|
-
}
|
|
59013
|
-
};
|
|
59014
|
-
}
|
|
59494
|
+
for (const widget of workspace.widgets.getAllWidgets()) {
|
|
59495
|
+
const { start, end } = widget.nameRange;
|
|
59496
|
+
if (widget.uri === uri && position.line === start.line && position.character >= start.character && position.character <= end.character) {
|
|
59497
|
+
return { kind: "widget", name: widget.name, range: widget.nameRange };
|
|
59015
59498
|
}
|
|
59016
59499
|
}
|
|
59017
59500
|
{
|
|
59018
|
-
const re = /\{([A-Za-z_$][\w$]*)/g;
|
|
59501
|
+
const re = /\{\/?([A-Za-z_$][\w$]*)/g;
|
|
59019
59502
|
let match2;
|
|
59020
59503
|
while ((match2 = re.exec(line)) !== null) {
|
|
59021
59504
|
const name = match2[1];
|
|
59022
|
-
const nameStart = match2.index +
|
|
59505
|
+
const nameStart = match2.index + match2[0].length - name.length;
|
|
59023
59506
|
const nameEnd = nameStart + name.length;
|
|
59024
59507
|
if (position.character >= nameStart && position.character <= nameEnd) {
|
|
59025
|
-
|
|
59508
|
+
const widget = workspace.widgets.getWidget(name);
|
|
59509
|
+
const isClosing = match2[0][1] === "/";
|
|
59510
|
+
if (!workspace.macros.getMacro(name) && widget && (!isClosing || widget.block)) {
|
|
59026
59511
|
return {
|
|
59027
59512
|
kind: "widget",
|
|
59028
59513
|
name,
|
|
@@ -59116,7 +59601,7 @@ function computeCodeLenses(uri, workspace) {
|
|
|
59116
59601
|
});
|
|
59117
59602
|
continue;
|
|
59118
59603
|
}
|
|
59119
|
-
const widgetMatch = line.match(/\{widget\s+"([
|
|
59604
|
+
const widgetMatch = line.match(/\{widget\s+["']?([^\s"'}]+)/);
|
|
59120
59605
|
if (widgetMatch) {
|
|
59121
59606
|
const widgetName = widgetMatch[1];
|
|
59122
59607
|
const refs = findWidgetReferences(widgetName, workspace, true);
|
|
@@ -59196,34 +59681,24 @@ function computeInlayHints(uri, range2, workspace) {
|
|
|
59196
59681
|
return hints;
|
|
59197
59682
|
}
|
|
59198
59683
|
function addWidgetParamHints(text, range2, workspace, hints) {
|
|
59199
|
-
|
|
59200
|
-
if (allWidgets.length === 0) return;
|
|
59201
|
-
const widgetMap = new Map(allWidgets.map((w) => [w.name, w]));
|
|
59684
|
+
if (workspace.widgets.getAllWidgets().length === 0) return;
|
|
59202
59685
|
const macros = parseMacros(text);
|
|
59686
|
+
const lineStarts = buildLineStarts(text);
|
|
59203
59687
|
for (const macro of macros) {
|
|
59204
59688
|
if (!macro.open) continue;
|
|
59205
59689
|
if (macro.range.start.line < range2.start.line || macro.range.start.line > range2.end.line) continue;
|
|
59206
|
-
const widget =
|
|
59690
|
+
const widget = workspace.widgets.getWidget(macro.name);
|
|
59207
59691
|
if (!widget || widget.params.length === 0) continue;
|
|
59208
59692
|
if (!macro.rawArgs || macro.rawArgs.trim() === "") continue;
|
|
59209
59693
|
const args2 = lexArguments(macro.rawArgs);
|
|
59210
|
-
const
|
|
59211
|
-
const
|
|
59212
|
-
if (!macroLine) continue;
|
|
59213
|
-
const macroText = macroLine.substring(macro.range.start.character, macro.range.end.character);
|
|
59214
|
-
const nameEnd = macroText.indexOf(macro.name) + macro.name.length;
|
|
59215
|
-
const argsText = macroText.substring(nameEnd).replace(/^\s+/, "").replace(/\}$/, "");
|
|
59216
|
-
if (!argsText) continue;
|
|
59694
|
+
const macroEnd = lineStarts[macro.range.end.line] + macro.range.end.character;
|
|
59695
|
+
const argsStart = macroEnd - 1 - macro.rawArgs.length;
|
|
59217
59696
|
for (let i = 0; i < Math.min(args2.length, widget.params.length); i++) {
|
|
59218
|
-
|
|
59219
|
-
|
|
59220
|
-
|
|
59221
|
-
|
|
59222
|
-
|
|
59223
|
-
label: `@${widget.params[i]}:`,
|
|
59224
|
-
kind: "parameter"
|
|
59225
|
-
});
|
|
59226
|
-
}
|
|
59697
|
+
hints.push({
|
|
59698
|
+
position: offsetToPosition(argsStart + args2[i].start, lineStarts),
|
|
59699
|
+
label: `${widget.params[i]}:`,
|
|
59700
|
+
kind: "parameter"
|
|
59701
|
+
});
|
|
59227
59702
|
}
|
|
59228
59703
|
}
|
|
59229
59704
|
}
|
|
@@ -59506,12 +59981,15 @@ var init_semantic_tokens = __esm({
|
|
|
59506
59981
|
});
|
|
59507
59982
|
|
|
59508
59983
|
// src/plugins/code-actions.ts
|
|
59509
|
-
|
|
59984
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
59985
|
+
import { basename, dirname as dirname2, join as join3 } from "node:path";
|
|
59986
|
+
import { fileURLToPath as fileURLToPath6, pathToFileURL as pathToFileURL4 } from "node:url";
|
|
59987
|
+
function computeCodeActions(uri, diagnostics, workspace, options = {}) {
|
|
59510
59988
|
const actions = [];
|
|
59511
59989
|
for (const diag of diagnostics) {
|
|
59512
59990
|
switch (diag.code) {
|
|
59513
59991
|
case DiagnosticCode.UndefinedMacro: {
|
|
59514
|
-
const action = fixUndefinedMacro(diag);
|
|
59992
|
+
const action = fixUndefinedMacro(uri, diag, workspace, options);
|
|
59515
59993
|
if (action) actions.push(action);
|
|
59516
59994
|
break;
|
|
59517
59995
|
}
|
|
@@ -59539,27 +60017,141 @@ function computeCodeActions(uri, diagnostics, workspace) {
|
|
|
59539
60017
|
}
|
|
59540
60018
|
return actions;
|
|
59541
60019
|
}
|
|
59542
|
-
function fixUndefinedMacro(diag) {
|
|
60020
|
+
function fixUndefinedMacro(uri, diag, workspace, options) {
|
|
59543
60021
|
const match2 = diag.message.match(/\{(\w[\w-]*)\}/);
|
|
59544
60022
|
if (!match2) return null;
|
|
59545
60023
|
const macroName = match2[1];
|
|
59546
|
-
const
|
|
59547
|
-
|
|
59548
|
-
|
|
59549
|
-
|
|
59550
|
-
|
|
59551
|
-
|
|
59552
|
-
title: `Add '${macroName}' to
|
|
60024
|
+
const root = resolveConfigRoot(uri, options.workspaceRoot);
|
|
60025
|
+
if (!root) return null;
|
|
60026
|
+
const existingPath = findConfigFile(root);
|
|
60027
|
+
const configPath = existingPath ?? join3(root, DEFAULT_CONFIG_FILENAME);
|
|
60028
|
+
const configUri = pathToFileURL4(configPath).toString();
|
|
60029
|
+
const action = {
|
|
60030
|
+
title: `Add '${macroName}' to ${basename(configPath)}`,
|
|
59553
60031
|
kind: "quickfix",
|
|
59554
|
-
diagnosticCodes: [DiagnosticCode.UndefinedMacro]
|
|
59555
|
-
|
|
59556
|
-
|
|
59557
|
-
|
|
59558
|
-
|
|
59559
|
-
|
|
59560
|
-
|
|
59561
|
-
|
|
59562
|
-
|
|
60032
|
+
diagnosticCodes: [DiagnosticCode.UndefinedMacro]
|
|
60033
|
+
};
|
|
60034
|
+
if (!existingPath) {
|
|
60035
|
+
const start = { line: 0, character: 0 };
|
|
60036
|
+
return {
|
|
60037
|
+
...action,
|
|
60038
|
+
createFile: configUri,
|
|
60039
|
+
edits: [{
|
|
60040
|
+
uri: configUri,
|
|
60041
|
+
range: { start, end: start },
|
|
60042
|
+
newText: (0, import_yaml2.stringify)({ macros: { [macroName]: NEW_MACRO_ENTRY } })
|
|
60043
|
+
}]
|
|
60044
|
+
};
|
|
60045
|
+
}
|
|
60046
|
+
let text = workspace.documents.getText(configUri);
|
|
60047
|
+
if (text === void 0) {
|
|
60048
|
+
try {
|
|
60049
|
+
text = readFileSync7(existingPath, "utf-8");
|
|
60050
|
+
} catch {
|
|
60051
|
+
return null;
|
|
60052
|
+
}
|
|
60053
|
+
}
|
|
60054
|
+
const edit = configPath.toLowerCase().endsWith(".json") ? addMacroToJsonConfig(text, macroName) : addMacroToYamlConfig(text, macroName);
|
|
60055
|
+
if (!edit) return null;
|
|
60056
|
+
return { ...action, edits: [{ uri: configUri, ...edit }] };
|
|
60057
|
+
}
|
|
60058
|
+
function resolveConfigRoot(uri, workspaceRoot) {
|
|
60059
|
+
if (workspaceRoot) {
|
|
60060
|
+
return workspaceRoot.startsWith("file:") ? fileURLToPath6(workspaceRoot) : workspaceRoot;
|
|
60061
|
+
}
|
|
60062
|
+
if (!uri.startsWith("file:")) return null;
|
|
60063
|
+
const docDir = dirname2(fileURLToPath6(uri));
|
|
60064
|
+
let search = docDir;
|
|
60065
|
+
for (let i = 0; i < 10; i++) {
|
|
60066
|
+
if (findConfigFile(search)) return search;
|
|
60067
|
+
const parent = dirname2(search);
|
|
60068
|
+
if (parent === search) break;
|
|
60069
|
+
search = parent;
|
|
60070
|
+
}
|
|
60071
|
+
return docDir;
|
|
60072
|
+
}
|
|
60073
|
+
function macrosPath(root) {
|
|
60074
|
+
const legacy = root?.["spindle-0"];
|
|
60075
|
+
return legacy !== null && typeof legacy === "object" ? ["spindle-0", "macros"] : ["macros"];
|
|
60076
|
+
}
|
|
60077
|
+
function definesMacro(macros, macroName) {
|
|
60078
|
+
if (macros === null || typeof macros !== "object") return false;
|
|
60079
|
+
const lower = macroName.toLowerCase();
|
|
60080
|
+
return Object.keys(macros).some((k) => k.toLowerCase() === lower);
|
|
60081
|
+
}
|
|
60082
|
+
function addMacroToYamlConfig(text, macroName) {
|
|
60083
|
+
const doc = (0, import_yaml2.parseDocument)(text);
|
|
60084
|
+
if (doc.errors.length > 0) return null;
|
|
60085
|
+
if (doc.contents !== null && !(0, import_yaml2.isMap)(doc.contents)) return null;
|
|
60086
|
+
const path2 = macrosPath(doc.toJS());
|
|
60087
|
+
const parent = path2.length > 1 ? doc.getIn(path2.slice(0, -1), true) : doc.contents;
|
|
60088
|
+
const macros = doc.getIn(path2, true);
|
|
60089
|
+
if ((0, import_yaml2.isMap)(macros) && definesMacro(macros.toJS(doc), macroName)) return null;
|
|
60090
|
+
if ((0, import_yaml2.isMap)(parent) && (0, import_yaml2.isMap)(macros) && !macros.flow && macros.items.length > 0 && macros.range) {
|
|
60091
|
+
const macrosKey = parent.items.find((p) => (0, import_yaml2.isScalar)(p.key) && p.key.value === "macros")?.key;
|
|
60092
|
+
const firstKey = macros.items[0].key;
|
|
60093
|
+
if ((0, import_yaml2.isScalar)(macrosKey) && macrosKey.range && (0, import_yaml2.isScalar)(firstKey) && firstKey.range) {
|
|
60094
|
+
const indent = columnOf(text, firstKey.range[0]);
|
|
60095
|
+
const step = Math.max(indent - columnOf(text, macrosKey.range[0]), 1);
|
|
60096
|
+
const entry = (0, import_yaml2.stringify)({ [macroName]: NEW_MACRO_ENTRY }, { indent: step }).replace(/^(?=.)/gm, " ".repeat(indent));
|
|
60097
|
+
let offset = macros.range[1];
|
|
60098
|
+
if (offset > 0 && text[offset - 1] !== "\n") {
|
|
60099
|
+
const nl = text.indexOf("\n", offset);
|
|
60100
|
+
offset = nl === -1 ? text.length : nl + 1;
|
|
60101
|
+
}
|
|
60102
|
+
const lead = offset === text.length && text.length > 0 && !text.endsWith("\n") ? "\n" : "";
|
|
60103
|
+
const pos = offsetToPosition2(text, offset);
|
|
60104
|
+
return { range: { start: pos, end: pos }, newText: lead + entry };
|
|
60105
|
+
}
|
|
60106
|
+
}
|
|
60107
|
+
if ((0, import_yaml2.isMap)(macros)) {
|
|
60108
|
+
macros.set(macroName, doc.createNode(NEW_MACRO_ENTRY));
|
|
60109
|
+
} else {
|
|
60110
|
+
doc.setIn(path2, doc.createNode({ [macroName]: NEW_MACRO_ENTRY }));
|
|
60111
|
+
}
|
|
60112
|
+
return minimalEdit(text, doc.toString({ lineWidth: 0 }));
|
|
60113
|
+
}
|
|
60114
|
+
function addMacroToJsonConfig(text, macroName) {
|
|
60115
|
+
let raw;
|
|
60116
|
+
try {
|
|
60117
|
+
raw = text.trim() ? JSON.parse(text) : {};
|
|
60118
|
+
} catch {
|
|
60119
|
+
return null;
|
|
60120
|
+
}
|
|
60121
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
60122
|
+
const path2 = macrosPath(raw);
|
|
60123
|
+
const container = path2.length > 1 ? raw[path2[0]] : raw;
|
|
60124
|
+
const macros = container.macros;
|
|
60125
|
+
if (definesMacro(macros, macroName)) return null;
|
|
60126
|
+
if (macros !== null && typeof macros === "object" && !Array.isArray(macros)) {
|
|
60127
|
+
macros[macroName] = NEW_MACRO_ENTRY;
|
|
60128
|
+
} else {
|
|
60129
|
+
container.macros = { [macroName]: NEW_MACRO_ENTRY };
|
|
60130
|
+
}
|
|
60131
|
+
const indent = text.match(/^[ \t]+(?=")/m)?.[0] ?? " ";
|
|
60132
|
+
const newline = text.endsWith("\n") || !text.trim() ? "\n" : "";
|
|
60133
|
+
return minimalEdit(text, JSON.stringify(raw, null, indent) + newline);
|
|
60134
|
+
}
|
|
60135
|
+
function columnOf(text, offset) {
|
|
60136
|
+
return offset - (text.lastIndexOf("\n", offset - 1) + 1);
|
|
60137
|
+
}
|
|
60138
|
+
function offsetToPosition2(text, offset) {
|
|
60139
|
+
const before = text.slice(0, offset);
|
|
60140
|
+
const lineStart = before.lastIndexOf("\n") + 1;
|
|
60141
|
+
return { line: before.split("\n").length - 1, character: offset - lineStart };
|
|
60142
|
+
}
|
|
60143
|
+
function minimalEdit(oldText, newText) {
|
|
60144
|
+
const max = Math.min(oldText.length, newText.length);
|
|
60145
|
+
let prefix = 0;
|
|
60146
|
+
while (prefix < max && oldText[prefix] === newText[prefix]) prefix++;
|
|
60147
|
+
let suffix = 0;
|
|
60148
|
+
while (suffix < max - prefix && oldText[oldText.length - 1 - suffix] === newText[newText.length - 1 - suffix]) suffix++;
|
|
60149
|
+
return {
|
|
60150
|
+
range: {
|
|
60151
|
+
start: offsetToPosition2(oldText, prefix),
|
|
60152
|
+
end: offsetToPosition2(oldText, oldText.length - suffix)
|
|
60153
|
+
},
|
|
60154
|
+
newText: newText.slice(prefix, newText.length - suffix)
|
|
59563
60155
|
};
|
|
59564
60156
|
}
|
|
59565
60157
|
function fixUndeclaredVariable(diag, workspace) {
|
|
@@ -59669,11 +60261,15 @@ function toLspRange6(r) {
|
|
|
59669
60261
|
end: { line: r.end.line, character: r.end.character }
|
|
59670
60262
|
};
|
|
59671
60263
|
}
|
|
59672
|
-
var codeActionsPlugin;
|
|
60264
|
+
var import_yaml2, DEFAULT_CONFIG_FILENAME, NEW_MACRO_ENTRY, codeActionsPlugin;
|
|
59673
60265
|
var init_code_actions = __esm({
|
|
59674
60266
|
"src/plugins/code-actions.ts"() {
|
|
59675
60267
|
"use strict";
|
|
60268
|
+
import_yaml2 = __toESM(require_dist(), 1);
|
|
59676
60269
|
init_diagnostic_codes();
|
|
60270
|
+
init_config_loader();
|
|
60271
|
+
DEFAULT_CONFIG_FILENAME = "spindle.config.yaml";
|
|
60272
|
+
NEW_MACRO_ENTRY = { description: "" };
|
|
59677
60273
|
codeActionsPlugin = {
|
|
59678
60274
|
id: "code-actions",
|
|
59679
60275
|
capabilities: {
|
|
@@ -59696,7 +60292,8 @@ var init_code_actions = __esm({
|
|
|
59696
60292
|
const actions = computeCodeActions(
|
|
59697
60293
|
params.textDocument.uri,
|
|
59698
60294
|
diagnostics,
|
|
59699
|
-
ctx.workspace
|
|
60295
|
+
ctx.workspace,
|
|
60296
|
+
{ workspaceRoot: ctx.config.workspaceRoot }
|
|
59700
60297
|
);
|
|
59701
60298
|
return actions.map((a) => ({
|
|
59702
60299
|
title: a.title,
|
|
@@ -59704,7 +60301,16 @@ var init_code_actions = __esm({
|
|
|
59704
60301
|
diagnostics: params.context.diagnostics.filter(
|
|
59705
60302
|
(d) => a.diagnosticCodes.includes(String(d.code))
|
|
59706
60303
|
),
|
|
59707
|
-
edit: {
|
|
60304
|
+
edit: a.createFile ? {
|
|
60305
|
+
// Resource operations are only expressible via documentChanges
|
|
60306
|
+
documentChanges: [
|
|
60307
|
+
{ kind: "create", uri: a.createFile, options: { ignoreIfExists: true } },
|
|
60308
|
+
...a.edits.map((e) => ({
|
|
60309
|
+
textDocument: { uri: e.uri, version: null },
|
|
60310
|
+
edits: [{ range: toLspRange6(e.range), newText: e.newText }]
|
|
60311
|
+
}))
|
|
60312
|
+
]
|
|
60313
|
+
} : {
|
|
59708
60314
|
changes: Object.fromEntries(
|
|
59709
60315
|
a.edits.map((e) => [
|
|
59710
60316
|
e.uri,
|
|
@@ -59744,7 +60350,7 @@ function computeDocumentSymbols(uri, workspace) {
|
|
|
59744
60350
|
if (passage.tags?.includes("widget")) {
|
|
59745
60351
|
const contentStart = passage.range.start.line + 1;
|
|
59746
60352
|
const contentEnd = passage.range.end.line + 1;
|
|
59747
|
-
const widgetDefRegex2 = /\{widget\s+"([
|
|
60353
|
+
const widgetDefRegex2 = /\{widget\s+["']?([^\s"'}]+)["']?[^}]*\}/gi;
|
|
59748
60354
|
for (let i = contentStart; i < contentEnd && i < lines.length; i++) {
|
|
59749
60355
|
widgetDefRegex2.lastIndex = 0;
|
|
59750
60356
|
let match2;
|
|
@@ -59849,14 +60455,19 @@ function searchWorkspaceSymbols(query, workspace) {
|
|
|
59849
60455
|
range: widget.range
|
|
59850
60456
|
});
|
|
59851
60457
|
}
|
|
59852
|
-
|
|
59853
|
-
|
|
60458
|
+
const declarations = [
|
|
60459
|
+
...workspace.variables.getDeclared().values(),
|
|
60460
|
+
...workspace.variables.getDeclaredTransient().values()
|
|
60461
|
+
];
|
|
60462
|
+
for (const decl of declarations) {
|
|
60463
|
+
const displayName = decl.sigil + decl.name;
|
|
59854
60464
|
if (lowerQuery && !displayName.toLowerCase().includes(lowerQuery)) continue;
|
|
60465
|
+
if (!decl.declarationUri || !decl.declarationRange) continue;
|
|
59855
60466
|
results.push({
|
|
59856
60467
|
name: displayName,
|
|
59857
60468
|
kind: import_vscode_languageserver3.SymbolKind.Variable,
|
|
59858
|
-
uri: decl.declarationUri
|
|
59859
|
-
range: decl.declarationRange
|
|
60469
|
+
uri: decl.declarationUri,
|
|
60470
|
+
range: decl.declarationRange
|
|
59860
60471
|
});
|
|
59861
60472
|
}
|
|
59862
60473
|
return results;
|
|
@@ -59912,7 +60523,11 @@ function computeFoldingRanges(uri, workspace) {
|
|
|
59912
60523
|
}
|
|
59913
60524
|
}
|
|
59914
60525
|
const macros = parseMacros(text);
|
|
59915
|
-
pairMacros(
|
|
60526
|
+
pairMacros(
|
|
60527
|
+
macros,
|
|
60528
|
+
(name) => workspace.macros.isBlock(name),
|
|
60529
|
+
passages.map((p) => p.range.start.line)
|
|
60530
|
+
);
|
|
59916
60531
|
for (const macro of macros) {
|
|
59917
60532
|
if (macro.open && macro.pair !== -1) {
|
|
59918
60533
|
const closingMacro = macros[macro.pair];
|
|
@@ -60059,17 +60674,22 @@ var server_exports2 = {};
|
|
|
60059
60674
|
__export(server_exports2, {
|
|
60060
60675
|
startServer: () => startServer
|
|
60061
60676
|
});
|
|
60062
|
-
import { fileURLToPath as
|
|
60063
|
-
import { readFileSync as
|
|
60677
|
+
import { fileURLToPath as fileURLToPath7, pathToFileURL as pathToFileURL5 } from "node:url";
|
|
60678
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
60679
|
+
import { basename as basename2 } from "node:path";
|
|
60064
60680
|
function uriToFsPath(uri) {
|
|
60065
60681
|
try {
|
|
60066
|
-
return
|
|
60682
|
+
return fileURLToPath7(uri);
|
|
60067
60683
|
} catch {
|
|
60068
60684
|
return uri;
|
|
60069
60685
|
}
|
|
60070
60686
|
}
|
|
60071
60687
|
function fsPathToUri(fsPath) {
|
|
60072
|
-
return
|
|
60688
|
+
return pathToFileURL5(fsPath).toString();
|
|
60689
|
+
}
|
|
60690
|
+
function isConfigFileUri(uri) {
|
|
60691
|
+
const name = basename2(uriToFsPath(uri));
|
|
60692
|
+
return name.startsWith("spindle.config.") || name.includes("twee-config.");
|
|
60073
60693
|
}
|
|
60074
60694
|
function startServer(_args) {
|
|
60075
60695
|
const connection = (0, import_node.createConnection)(import_node.ProposedFeatures.all);
|
|
@@ -60087,15 +60707,17 @@ function startServer(_args) {
|
|
|
60087
60707
|
diagnostics: initOptions.diagnostics,
|
|
60088
60708
|
workspaceRoot
|
|
60089
60709
|
};
|
|
60090
|
-
workspace = new WorkspaceModel();
|
|
60710
|
+
workspace = new WorkspaceModel(workspaceRoot ? { workspaceRoot } : void 0);
|
|
60091
60711
|
console.error("[spindle-lsp] workspaceRoot:", workspaceRoot ?? "undefined");
|
|
60712
|
+
console.error("[spindle-lsp] builtin macros:", workspace.macros.builtinsPath ?? "not found");
|
|
60713
|
+
for (const warning of workspace.macros.warnings) console.error("[spindle-lsp]", warning);
|
|
60092
60714
|
activePlugins = loadPlugins(allPlugins, config2);
|
|
60093
60715
|
console.error("[spindle-lsp] plugins loaded:", activePlugins.map((p) => p.id).join(", "));
|
|
60094
60716
|
for (const plugin of activePlugins) {
|
|
60095
60717
|
plugin.initialize({ connection, workspace, config: config2 });
|
|
60096
60718
|
}
|
|
60097
60719
|
if (Object.keys(projectConfig.macros).length > 0) {
|
|
60098
|
-
workspace.macros.
|
|
60720
|
+
workspace.macros.loadConfig(projectConfig.macros);
|
|
60099
60721
|
console.error("[spindle-lsp] loaded config macros:", Object.keys(projectConfig.macros).length);
|
|
60100
60722
|
}
|
|
60101
60723
|
return {
|
|
@@ -60119,6 +60741,9 @@ function startServer(_args) {
|
|
|
60119
60741
|
try {
|
|
60120
60742
|
const fileContents = await scanWorkspaceFiles(workspaceRoot);
|
|
60121
60743
|
console.error("[spindle-lsp] scanned", fileContents.size, "files from root:", workspaceRoot ?? "undefined");
|
|
60744
|
+
for (const uri of documents.keys()) {
|
|
60745
|
+
fileContents.delete(uri);
|
|
60746
|
+
}
|
|
60122
60747
|
workspace.initialize(fileContents);
|
|
60123
60748
|
console.error("[spindle-lsp] workspace initialized, macros:", workspace.macros.getAllMacros().length);
|
|
60124
60749
|
} catch (err) {
|
|
@@ -60158,23 +60783,40 @@ function startServer(_args) {
|
|
|
60158
60783
|
if (workspace) {
|
|
60159
60784
|
try {
|
|
60160
60785
|
const fsPath = uriToFsPath(textDocument.uri);
|
|
60161
|
-
const text =
|
|
60786
|
+
const text = readFileSync8(fsPath, "utf-8");
|
|
60162
60787
|
workspace.documents.update(textDocument.uri, text);
|
|
60163
60788
|
} catch {
|
|
60164
60789
|
workspace.documents.close(textDocument.uri);
|
|
60165
60790
|
}
|
|
60166
60791
|
}
|
|
60167
60792
|
});
|
|
60793
|
+
function reloadProjectConfig() {
|
|
60794
|
+
if (!workspaceRoot) return;
|
|
60795
|
+
try {
|
|
60796
|
+
const projectConfig = loadConfigFromDisk(workspaceRoot);
|
|
60797
|
+
workspace.macros.loadConfig(projectConfig.macros);
|
|
60798
|
+
console.error("[spindle-lsp] reloaded config macros:", Object.keys(projectConfig.macros).length);
|
|
60799
|
+
} catch (err) {
|
|
60800
|
+
console.error("[spindle-lsp] config reload failed:", err);
|
|
60801
|
+
return;
|
|
60802
|
+
}
|
|
60803
|
+
workspace.refresh();
|
|
60804
|
+
}
|
|
60168
60805
|
connection.onDidChangeWatchedFiles(({ changes }) => {
|
|
60169
60806
|
if (!workspace) return;
|
|
60807
|
+
let configChanged = false;
|
|
60170
60808
|
for (const change of changes) {
|
|
60809
|
+
if (isConfigFileUri(change.uri)) {
|
|
60810
|
+
configChanged = true;
|
|
60811
|
+
continue;
|
|
60812
|
+
}
|
|
60813
|
+
if (documents.has(change.uri)) continue;
|
|
60171
60814
|
if (change.type === import_node.FileChangeType.Deleted) {
|
|
60172
60815
|
workspace.documents.close(change.uri);
|
|
60173
|
-
documents.delete(change.uri);
|
|
60174
60816
|
} else {
|
|
60175
60817
|
try {
|
|
60176
60818
|
const fsPath = uriToFsPath(change.uri);
|
|
60177
|
-
const text =
|
|
60819
|
+
const text = readFileSync8(fsPath, "utf-8");
|
|
60178
60820
|
if (workspace.documents.has(change.uri)) {
|
|
60179
60821
|
workspace.documents.update(change.uri, text);
|
|
60180
60822
|
} else {
|
|
@@ -60184,6 +60826,9 @@ function startServer(_args) {
|
|
|
60184
60826
|
}
|
|
60185
60827
|
}
|
|
60186
60828
|
}
|
|
60829
|
+
if (configChanged) {
|
|
60830
|
+
reloadProjectConfig();
|
|
60831
|
+
}
|
|
60187
60832
|
});
|
|
60188
60833
|
connection.onShutdown(() => {
|
|
60189
60834
|
for (const plugin of activePlugins) {
|
|
@@ -60204,7 +60849,7 @@ async function scanWorkspaceFiles(root) {
|
|
|
60204
60849
|
});
|
|
60205
60850
|
for (const filePath of files) {
|
|
60206
60851
|
try {
|
|
60207
|
-
const text =
|
|
60852
|
+
const text = readFileSync8(filePath, "utf-8");
|
|
60208
60853
|
const uri = fsPathToUri(filePath);
|
|
60209
60854
|
contents.set(uri, text);
|
|
60210
60855
|
} catch {
|
|
@@ -60231,7 +60876,7 @@ var init_server4 = __esm({
|
|
|
60231
60876
|
|
|
60232
60877
|
// src/bin.ts
|
|
60233
60878
|
var args = process.argv.slice(2);
|
|
60234
|
-
var VERSION = "0.9.
|
|
60879
|
+
var VERSION = "0.9.2";
|
|
60235
60880
|
var HELP = `spindle-lsp v${VERSION}
|
|
60236
60881
|
Language Server Protocol server for Spindle story format
|
|
60237
60882
|
|