@rohal12/spindle-lsp 0.15.52 → 0.15.54

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 CHANGED
@@ -55,7 +55,7 @@ var VERSION;
55
55
  var init_version = __esm({
56
56
  "src/version.ts"() {
57
57
  "use strict";
58
- VERSION = false ? pkg.version : "0.15.52";
58
+ VERSION = false ? pkg.version : "0.15.54";
59
59
  }
60
60
  });
61
61
 
@@ -35316,7 +35316,7 @@ var init_workspace_model = __esm({
35316
35316
  const text3 = this.documents.getText(uri);
35317
35317
  if (!text3) continue;
35318
35318
  if (isMacroSource(uri)) {
35319
- found.push(...discoverMacros(text3));
35319
+ for (const macro of discoverMacros(text3)) found.push(macro);
35320
35320
  continue;
35321
35321
  }
35322
35322
  for (const source of this.passages.getPassagesInDocument(uri)) {
@@ -35328,8 +35328,9 @@ var init_workspace_model = __esm({
35328
35328
  const isScript = passage.tags?.includes("script") ?? false;
35329
35329
  if (!isStoryInit && !isScript) continue;
35330
35330
  const content2 = this.markup.get(passage.uri)?.passages.find((p) => p.passage === passage)?.content ?? "";
35331
- if (isScript) found.push(...discoverMacros(content2));
35332
- else init.push(passage);
35331
+ if (isScript) {
35332
+ for (const macro of discoverMacros(content2)) found.push(macro);
35333
+ } else init.push(passage);
35333
35334
  }
35334
35335
  }
35335
35336
  this.macros.setDiscoveredMacros(found);
@@ -35337,7 +35338,9 @@ var init_workspace_model = __esm({
35337
35338
  this.rescanWidgets();
35338
35339
  for (const passage of init) {
35339
35340
  const markup = this.markup.get(passage.uri)?.passages.find((p) => p.passage === passage);
35340
- if (markup) found.push(...storyInitMacros(markup));
35341
+ if (markup) {
35342
+ for (const macro of storyInitMacros(markup)) found.push(macro);
35343
+ }
35341
35344
  }
35342
35345
  this.macros.setDiscoveredMacros(found);
35343
35346
  }
@@ -35909,6 +35912,12 @@ function buildReport(documents, workspace) {
35909
35912
  }
35910
35913
  const sources = widgetSources(passages, macros);
35911
35914
  const widgetList = [...sources].map(([definition2, passage]) => ({ definition: definition2, passage }));
35915
+ const widgetNamesByPassage = /* @__PURE__ */ new Map();
35916
+ for (const { definition: definition2, passage } of widgetList) {
35917
+ const names = widgetNamesByPassage.get(passage.passage);
35918
+ if (names) names.push(definition2.name);
35919
+ else widgetNamesByPassage.set(passage.passage, [definition2.name]);
35920
+ }
35912
35921
  const widgets = new Map(effectiveWidgetDefinitions([...sources.keys()]).map((definition2) => [
35913
35922
  definition2.name.toLowerCase(),
35914
35923
  { definition: definition2, passage: sources.get(definition2) }
@@ -35929,6 +35938,7 @@ function buildReport(documents, workspace) {
35929
35938
  markup,
35930
35939
  widgets,
35931
35940
  widgetList,
35941
+ widgetNamesByPassage,
35932
35942
  invoked,
35933
35943
  variables: declarationsOf(workspace, "StoryVariables"),
35934
35944
  transients: declarationsOf(workspace, "StoryTransients"),
@@ -36348,7 +36358,6 @@ function argumentDiagnostics(passage, workspace, getPassageNames) {
36348
36358
  function widgetDiagnostics(passage, story, workspace) {
36349
36359
  if (!passage.isMarkup) return [];
36350
36360
  const diagnostics = [];
36351
- const macros = [...macroTokens(passage)];
36352
36361
  for (const token of passage.invocations) {
36353
36362
  if (workspace.getEffectiveMacro(token.name)) continue;
36354
36363
  const widget = story.widgets.get(token.name.toLowerCase());
@@ -36364,14 +36373,22 @@ function widgetDiagnostics(passage, story, workspace) {
36364
36373
  }
36365
36374
  }
36366
36375
  if (workspace.getEffectiveMacro("include")?.source !== "builtin") return diagnostics;
36376
+ const includes = [...macroTokens(passage)].filter((token) => !token.isClose && token.name.toLowerCase() === "include").sort((a, b) => a.start - b.start);
36367
36377
  for (const piece of passage.pieces) {
36368
36378
  if (piece.kind !== "passage" || piece.macro !== "include") continue;
36369
36379
  const target = workspace.passages.getEffectivePassage(piece.name);
36370
36380
  if (!target?.tags?.includes("widget")) continue;
36371
- const defined = story.widgetList.filter((widget) => widget.passage.passage === target).map((widget) => widget.definition.name);
36381
+ const defined = story.widgetNamesByPassage.get(target) ?? [];
36372
36382
  if (defined.length === 0) continue;
36373
- const include = macros.find((token) => !token.isClose && token.name.toLowerCase() === "include" && token.start <= piece.offset && piece.offset < token.end);
36374
- if (!include) continue;
36383
+ let low = 0;
36384
+ let high = includes.length;
36385
+ while (low < high) {
36386
+ const mid = low + high >>> 1;
36387
+ if (includes[mid].start <= piece.offset) low = mid + 1;
36388
+ else high = mid;
36389
+ }
36390
+ const include = includes[low - 1];
36391
+ if (!include || piece.offset >= include.end) continue;
36375
36392
  const names = defined.map((name) => `{${name}}`).join(", ");
36376
36393
  diagnostics.push(makeDiag(
36377
36394
  passage.range(include.start, include.end),
@@ -89824,15 +89841,31 @@ var init_semantic_tokens = __esm({
89824
89841
 
89825
89842
  // src/plugins/code-actions.ts
89826
89843
  import { readFileSync as readFileSync7 } from "node:fs";
89844
+ import { createRequire as createCompilerRequire4 } from "node:module";
89827
89845
  import { basename as basename2, dirname as dirname5, join as join4 } from "node:path";
89828
89846
  import { fileURLToPath as fileURLToPath4, pathToFileURL as pathToFileURL6 } from "node:url";
89829
89847
  import { isDeepStrictEqual } from "node:util";
89830
89848
  function computeCodeActions(uri, diagnostics, workspace, options = {}) {
89831
89849
  const actions = [];
89832
89850
  const current2 = computeDiagnostics(uri, workspace);
89851
+ const identity = (diag) => JSON.stringify([
89852
+ diag.code,
89853
+ diag.range.start.line,
89854
+ diag.range.start.character,
89855
+ diag.range.end.line,
89856
+ diag.range.end.character
89857
+ ]);
89858
+ const byIdentity = /* @__PURE__ */ new Map();
89859
+ for (const candidate of current2) {
89860
+ const key = identity(candidate);
89861
+ const group = byIdentity.get(key);
89862
+ if (group) group.push(candidate);
89863
+ else byIdentity.set(key, [candidate]);
89864
+ }
89833
89865
  for (const diag of diagnostics) {
89834
- const fresh = current2.find((candidate) => candidate.code === diag.code && isDeepStrictEqual(candidate.range, diag.range) && isDeepStrictEqual(candidate.data, diag.data));
89866
+ const fresh = byIdentity.get(identity(diag))?.find((candidate) => isDeepStrictEqual(candidate.range, diag.range) && isDeepStrictEqual(candidate.data, diag.data));
89835
89867
  if (!fresh && diag.code !== DiagnosticCode.NoStoryVariables) continue;
89868
+ const firstAction = actions.length;
89836
89869
  switch (diag.code) {
89837
89870
  case DiagnosticCode.UndefinedMacro:
89838
89871
  actions.push(...fixUndefinedMacro(uri, diag, workspace, options));
@@ -89859,6 +89892,7 @@ function computeCodeActions(uri, diagnostics, workspace, options = {}) {
89859
89892
  actions.push(...fixBrokenLink(uri, diag, workspace));
89860
89893
  break;
89861
89894
  }
89895
+ for (let i2 = firstAction; i2 < actions.length; i2++) actions[i2].diagnostics = [diag];
89862
89896
  }
89863
89897
  return actions;
89864
89898
  }
@@ -90119,7 +90153,7 @@ function fixBrokenLink(uri, diag, workspace) {
90119
90153
  });
90120
90154
  }
90121
90155
  const encoded = encodePassageName(name);
90122
- if (!workspace.passages.getPassage(name) && encoded !== void 0) {
90156
+ if (!workspace.passages.getPassage(name) && encoded !== void 0 && emptyPassageIsDestination(name)) {
90123
90157
  const edit = insertLinesAt(text3, splitLines(text3).length, `
90124
90158
  :: ${encoded}
90125
90159
  `, lineEndingFor(workspace, uri));
@@ -90132,6 +90166,13 @@ function fixBrokenLink(uri, diag, workspace) {
90132
90166
  }
90133
90167
  return actions;
90134
90168
  }
90169
+ function emptyPassageIsDestination(name) {
90170
+ const { StoryBuilder, passageOmission } = createCompilerRequire4(import.meta.url)("@rohal12/twee-ts");
90171
+ const passage = { name, text: "", tags: [] };
90172
+ const builder = new StoryBuilder();
90173
+ builder.add(passage, []);
90174
+ return passageOmission(builder.build(), passage, "twine2") === void 0;
90175
+ }
90135
90176
  function passageNameEdit(uri, diag, name, workspace) {
90136
90177
  const markup = workspace.markup.get(uri);
90137
90178
  const passage = markup?.passageAt(diag.range.start);
@@ -90203,18 +90244,23 @@ var init_code_actions = __esm({
90203
90244
  },
90204
90245
  initialize(ctx) {
90205
90246
  ctx.connection.onCodeAction((params) => {
90206
- const diagnostics = params.context.diagnostics.filter((d) => d.source === "spindle").map((d) => ({
90207
- range: {
90208
- start: { line: d.range.start.line, character: d.range.start.character },
90209
- end: { line: d.range.end.line, character: d.range.end.character }
90210
- },
90211
- // LSP 3.18 lets a message be markup; our diagnostics are always plain text
90212
- message: typeof d.message === "string" ? d.message : d.message.value,
90213
- severity: d.severity === 1 ? "error" : d.severity === 2 ? "warning" : d.severity === 3 ? "info" : "hint",
90214
- code: String(d.code ?? ""),
90215
- source: d.source ?? "spindle",
90216
- data: d.data
90217
- }));
90247
+ const originals = /* @__PURE__ */ new Map();
90248
+ const diagnostics = params.context.diagnostics.filter((d) => d.source === "spindle").map((d) => {
90249
+ const diagnostic = {
90250
+ range: {
90251
+ start: { line: d.range.start.line, character: d.range.start.character },
90252
+ end: { line: d.range.end.line, character: d.range.end.character }
90253
+ },
90254
+ // LSP 3.18 lets a message be markup; our diagnostics are always plain text
90255
+ message: typeof d.message === "string" ? d.message : d.message.value,
90256
+ severity: d.severity === 1 ? "error" : d.severity === 2 ? "warning" : d.severity === 3 ? "info" : "hint",
90257
+ code: String(d.code ?? ""),
90258
+ source: d.source ?? "spindle",
90259
+ data: d.data
90260
+ };
90261
+ originals.set(diagnostic, d);
90262
+ return diagnostic;
90263
+ });
90218
90264
  const actions = computeCodeActions(
90219
90265
  params.textDocument.uri,
90220
90266
  diagnostics,
@@ -90224,9 +90270,7 @@ var init_code_actions = __esm({
90224
90270
  return actions.map((a) => ({
90225
90271
  title: a.title,
90226
90272
  kind: a.kind,
90227
- diagnostics: params.context.diagnostics.filter(
90228
- (d) => a.diagnosticCodes.includes(String(d.code))
90229
- ),
90273
+ diagnostics: a.diagnostics?.map((d) => originals.get(d)) ?? [],
90230
90274
  edit: a.createFile ? {
90231
90275
  // Resource operations are only expressible via documentChanges
90232
90276
  documentChanges: [