@rohal12/spindle-lsp 0.15.40 → 0.15.41

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.40";
58
+ VERSION = false ? pkg.version : "0.15.41";
59
59
  }
60
60
  });
61
61
 
@@ -16097,13 +16097,6 @@ function pairingError(position, error62) {
16097
16097
  function tokenizeMarkup$1(source, options = {}) {
16098
16098
  return run$1(source, "Tokens", options);
16099
16099
  }
16100
- function parseSelectors(source, at3 = 0) {
16101
- const found = run$1(source.slice(at3), "SelectorsPrefix", {});
16102
- return {
16103
- ...found,
16104
- end: at3 + found.end
16105
- };
16106
- }
16107
16100
  function tokenizeMarkupTolerant$1(source, options = {}) {
16108
16101
  const { tokens: tokens2, errors } = scanMarkupTolerant(source, options);
16109
16102
  return {
@@ -17090,8 +17083,11 @@ function locate(text3, part, from) {
17090
17083
  const anywhere = text3.indexOf(part);
17091
17084
  return anywhere >= 0 ? anywhere : from;
17092
17085
  }
17093
- function completionContext(source, cursor, macros = []) {
17094
- return readCompletion(source.slice(0, cursor), cursor, macros, false, source.length);
17086
+ function completionTarget(source, cursor, macros = []) {
17087
+ return readCompletion(source, cursor, macros, true);
17088
+ }
17089
+ function completionScopes(source, cursor, macros, visit2) {
17090
+ readCompletion(source, cursor, macros, true, source.length, visit2);
17095
17091
  }
17096
17092
  function readCompletion(source, cursor, macros, full, sourceLength = source.length, visit2) {
17097
17093
  if (!Number.isInteger(cursor) || cursor < 0 || cursor > sourceLength) throw new RangeError("cursor must be a UTF-16 offset within source");
@@ -22676,6 +22672,21 @@ function macroClassifier(all) {
22676
22672
  return calls;
22677
22673
  };
22678
22674
  }
22675
+ function macroCallAt(source, cursor, macros = []) {
22676
+ const all = effectiveToolingMacros(macros);
22677
+ const classify2 = macroClassifier(all);
22678
+ let selected;
22679
+ completionScopes(source, cursor, all, (tokens2, map2) => {
22680
+ const call = classify2(tokens2).find(({ token }) => map2(token.start) < cursor && cursor <= map2(token.end));
22681
+ if (call) selected = {
22682
+ ...call,
22683
+ token: mapOffsets(call.token, map2),
22684
+ ...call.owner && { owner: mapOffsets(call.owner, map2) }
22685
+ };
22686
+ return !call || call.kind === "invocation";
22687
+ });
22688
+ return selected;
22689
+ }
22679
22690
  function passagePieces(source, macros = []) {
22680
22691
  const all = effectiveToolingMacros(macros);
22681
22692
  const parametersOf2 = parameterLookup(all);
@@ -34149,7 +34160,11 @@ var init_passage_markup = __esm({
34149
34160
  }
34150
34161
  /** Whether the cursor is executable, with decoded code mapped back to `content`. */
34151
34162
  completionAt(offset2) {
34152
- return this.isMarkup ? completionContext(this.content, offset2, this.doc.context.macros) : { kind: "literal" };
34163
+ return this.isMarkup ? completionTarget(this.content, offset2, this.doc.context.macros) : { kind: "literal" };
34164
+ }
34165
+ /** Contextual dispatch at a complete or unfinished macro head. */
34166
+ macroCallAt(offset2) {
34167
+ return this.isMarkup ? macroCallAt(this.content, offset2, this.doc.context.macros) : void 0;
34153
34168
  }
34154
34169
  /** The declarations of a StoryVariables / StoryTransients passage. */
34155
34170
  get declarations() {
@@ -34395,10 +34410,21 @@ var init_variable_tracker = __esm({
34395
34410
  getUsages(name) {
34396
34411
  return usagesOf(this.usagesByUri, name);
34397
34412
  }
34413
+ /** Count every story binding's executable usages in one workspace pass. */
34414
+ getUsageCounts() {
34415
+ const counts = /* @__PURE__ */ new Map();
34416
+ for (const usages of this.usagesByUri.values()) {
34417
+ for (const usage of usages) counts.set(usage.baseName, (counts.get(usage.baseName) ?? 0) + 1);
34418
+ }
34419
+ return counts;
34420
+ }
34421
+ /** All declaration occurrences, including repeated defaults, in source order. */
34422
+ getAllDeclarations(sigil) {
34423
+ return (sigil === "$" ? this.variables : this.transients).occurrences;
34424
+ }
34398
34425
  /** Every declaration location of a story or transient binding, in source order. */
34399
34426
  getDeclarations(name, sigil) {
34400
- const declarations = sigil === "$" ? this.variables : this.transients;
34401
- return declarations.occurrences.flatMap((d) => d.name === name && d.declarationUri !== void 0 && d.declarationRange ? [{ uri: d.declarationUri, range: d.declarationRange }] : []);
34427
+ return this.getAllDeclarations(sigil).flatMap((d) => d.name === name && d.declarationUri !== void 0 && d.declarationRange ? [{ uri: d.declarationUri, range: d.declarationRange }] : []);
34402
34428
  }
34403
34429
  /** The executable usage or declaration containing the cursor, in source coordinates. */
34404
34430
  referenceAt(uri, position) {
@@ -88360,31 +88386,33 @@ var init_markup_cursor = __esm({
88360
88386
  }
88361
88387
  return this.cachedRegions = regions.reverse();
88362
88388
  }
88363
- /**
88364
- * The innermost macro whose arguments the cursor is in and that `known`
88365
- * accepts. A macro still being typed has no token: it is the macro of an
88366
- * `unclosed-macro` error, whose `offset` is its `{` and whose `end` the end
88367
- * of its name.
88368
- */
88389
+ /** The runtime's contextual dispatch of the macro arguments being typed. */
88369
88390
  enclosingMacro(known) {
88370
- const { at: at3 } = this;
88371
- for (const region of this.regions) {
88372
- const found = [];
88373
- for (const token of region.tokens) {
88374
- if (token.type !== "macro" || token.isClose || token.nameEnd >= at3 || at3 >= token.end) continue;
88375
- found.push({ start: token.start, name: token.name, invocation: this.passage.invocations.some((call) => call.start === token.start), argsBefore: at3 >= token.argsStart ? region.view.text.slice(viewIndex(region.view, token.argsStart), viewIndex(region.view, at3)) : "" });
88376
- }
88377
- for (const error62 of region.errors) {
88378
- const source = region.view.text;
88379
- const end = viewIndex(region.view, error62.end);
88380
- if (error62.code !== "unclosed-macro" || error62.offset >= at3 || error62.end >= at3 || !/\s/.test(source[end] ?? "")) continue;
88381
- const name = source.slice(parseSelectors(source, viewIndex(region.view, error62.offset) + 1).end, end);
88382
- if (name && name[0] !== "/") found.push({ start: error62.offset, name, argsBefore: source.slice(end, viewIndex(region.view, at3)).trimStart() });
88383
- }
88384
- const innermost = found.filter((macro) => known(macro.name)).sort((a, b) => b.start - a.start)[0];
88385
- if (innermost) return innermost;
88391
+ let call = this.passage.macroCallAt(this.at);
88392
+ const active = (candidate) => !!candidate && candidate.token.nameEnd < this.at && known(candidate.token.name) && !(candidate.token.end === this.at && this.regions.some((region) => region.tokens.some((token2) => token2.type === "macro" && token2.start === candidate.token.start && token2.end === this.at)));
88393
+ if (!active(call)) {
88394
+ call = void 0;
88395
+ const consider = (start, nameEnd) => {
88396
+ if (nameEnd >= this.at) return;
88397
+ const candidate = this.passage.macroCallAt(nameEnd + 1);
88398
+ if (candidate?.token.start === start && active(candidate) && (!call || start > call.token.start)) call = candidate;
88399
+ };
88400
+ for (const region of this.regions) {
88401
+ for (const token2 of region.tokens) {
88402
+ if (token2.type === "macro" && !token2.isClose && token2.start < this.at && this.at < token2.end) {
88403
+ consider(token2.start, token2.nameEnd);
88404
+ }
88405
+ }
88406
+ for (const error62 of region.errors) {
88407
+ if (error62.code === "unclosed-macro" && error62.offset < this.at && error62.end < this.at) consider(error62.offset, error62.end);
88408
+ }
88409
+ }
88410
+ if (!call) return void 0;
88386
88411
  }
88387
- return void 0;
88412
+ const { token } = call;
88413
+ const view = sourceView(this.passage, token.argsStart, this.at);
88414
+ const argsBefore = this.at >= token.argsEnd ? token.rawArgs + (token.argsEnd < this.at ? " " : "") : view.text.slice(viewIndex(view, token.argsStart), viewIndex(view, this.at));
88415
+ return { name: call.token.name, invocation: call.kind === "invocation", argsBefore };
88388
88416
  }
88389
88417
  /**
88390
88418
  * The macro name or closer being typed at the cursor (`{`, `{na`, `{/`),
@@ -88495,8 +88523,8 @@ function getCompletions(uri, position, triggerChar, workspace) {
88495
88523
  const cursor = markupAt(workspace, uri, position);
88496
88524
  if (!cursor?.passage.isMarkup) return [];
88497
88525
  const { passage, content: content2, at: at3 } = cursor;
88498
- const editing = (items, start, end) => {
88499
- const range2 = passage.range(start, end);
88526
+ const editing = (items, start, end2) => {
88527
+ const range2 = passage.range(start, end2);
88500
88528
  return items.map((item) => ({ ...item, textEdit: { range: range2, newText: item.insertText ?? item.label } }));
88501
88529
  };
88502
88530
  const typedEdit = (items, typed, tailPattern = /^[\w$]*/) => editing(items, at3 - typed, at3 + tailPattern.exec(content2.slice(at3))[0].length);
@@ -88510,41 +88538,35 @@ function getCompletions(uri, position, triggerChar, workspace) {
88510
88538
  if (head && !head.typed.startsWith("_")) return typedEdit(getMacroCompletions(workspace), head.typed.length, /^[\w-]*/);
88511
88539
  const context = passage.completionAt(at3);
88512
88540
  if (context.kind !== "code") return [];
88513
- const before = context.code.slice(0, context.cursor);
88541
+ const identifier = context.identifier;
88542
+ if (!identifier) return [];
88514
88543
  const codeOffset = (index) => pieceOffset(context, index);
88515
- const variableEdit = (items, typed) => editing(items, codeOffset(context.cursor - typed), at3 + /^[\w$]*/.exec(content2.slice(at3))[0].length);
88516
- const dotPath = /([$%])([\w$]+)\.([A-Za-z_$][\w$]*)?$/.exec(before);
88517
- if (dotPath) {
88518
- const sigil = dotPath[1];
88519
- const typed = (dotPath[3] ?? "").length;
88520
- const end = at3 + /^[\w$]*/.exec(content2.slice(at3))[0].length;
88521
- return getDotPathCompletions(sigil, dotPath[2], workspace).map((item) => {
88522
- const identifier = /^[A-Za-z_$][\w$]*$/.test(item.label);
88523
- const start = codeOffset(context.cursor - typed - (identifier ? 0 : 1));
88544
+ const end = codeOffset(identifier.end);
88545
+ if (identifier.kind === "member" && identifier.dotStart !== void 0) {
88546
+ let root;
88547
+ lexJs(context.code.slice(0, identifier.dotStart), {
88548
+ variable(sigil, name, _start, _nesting, end2) {
88549
+ if ((sigil === "$" || sigil === "%") && end2 === identifier.dotStart) root = { sigil, name };
88550
+ }
88551
+ }, context.goal);
88552
+ if (!root) return [];
88553
+ return getDotPathCompletions(root.sigil, root.name, workspace).map((item) => {
88554
+ const isIdentifier = /^[A-Za-z_$][\w$]*$/.test(item.label);
88555
+ const start = codeOffset(isIdentifier ? identifier.start : identifier.dotStart);
88556
+ const optional2 = context.code.slice(identifier.dotStart, identifier.start).startsWith("?.") ? "?." : "";
88524
88557
  return {
88525
88558
  ...item,
88526
88559
  textEdit: {
88527
88560
  range: passage.range(start, end),
88528
- newText: identifier ? item.label : encodeCompletion(`[${JSON.stringify(item.label)}]`, context.containers)
88561
+ newText: encodeCompletion(isIdentifier ? item.label : `${optional2}[${JSON.stringify(item.label)}]`, context.containers)
88529
88562
  }
88530
88563
  };
88531
88564
  });
88532
88565
  }
88533
- const storyVar = /\$([A-Za-z_$]?[\w$]*)$/.exec(before);
88534
- if (storyVar) {
88535
- return variableEdit(getVariableCompletions("$", workspace), storyVar[1].length);
88536
- }
88537
- const tempVar = /_([A-Za-z_$]?[\w$]*)$/.exec(before);
88538
- if (tempVar) {
88539
- return variableEdit(getDocumentVariableCompletions("_", cursor, workspace), tempVar[1].length);
88540
- }
88541
- const localVar = /@([A-Za-z_$]?[\w$]*)$/.exec(before);
88542
- if (localVar) {
88543
- return variableEdit(getDocumentVariableCompletions("@", cursor, workspace), localVar[1].length);
88544
- }
88545
- const transientVar = /%([A-Za-z_$]?[\w$]*)$/.exec(before);
88546
- if (transientVar) {
88547
- return variableEdit(getVariableCompletions("%", workspace), transientVar[1].length);
88566
+ if (identifier.kind === "root") {
88567
+ const sigil = context.code[identifier.start];
88568
+ const items = sigil === "$" || sigil === "%" ? getVariableCompletions(sigil, workspace) : sigil === "_" || sigil === "@" ? getDocumentVariableCompletions(sigil, cursor, workspace) : [];
88569
+ return editing(items, codeOffset(identifier.start + 1), end);
88548
88570
  }
88549
88571
  return [];
88550
88572
  }
@@ -89602,7 +89624,13 @@ function computeCodeLenses(uri, workspace) {
89602
89624
  command: { title }
89603
89625
  });
89604
89626
  };
89605
- const variableLines = new Map([...workspace.variables.getDeclared().keys()].flatMap((name) => workspace.variables.getDeclarations(name, "$").filter((declaration) => declaration.uri === uri).map((declaration) => [declaration.range.start.line, name])));
89627
+ const variableLines = /* @__PURE__ */ new Map();
89628
+ for (const declaration of workspace.variables.getAllDeclarations("$")) {
89629
+ if (declaration.declarationUri === uri && declaration.declarationRange) {
89630
+ variableLines.set(declaration.declarationRange.start.line, declaration.name);
89631
+ }
89632
+ }
89633
+ const variableCounts = variableLines.size > 0 ? workspace.variables.getUsageCounts() : /* @__PURE__ */ new Map();
89606
89634
  const widgetLines = new Map(workspace.widgets.getAllWidgets().filter((w) => w.uri === uri).map((w) => [w.range.start.line, w.name]));
89607
89635
  for (let lineNum = 0; lineNum < lines.length; lineNum++) {
89608
89636
  const line = lines[lineNum];
@@ -89621,7 +89649,7 @@ function computeCodeLenses(uri, workspace) {
89621
89649
  }
89622
89650
  const varName = variableLines.get(lineNum);
89623
89651
  if (varName !== void 0) {
89624
- const usageCount = findVariableReferences(varName, workspace, false).length;
89652
+ const usageCount = variableCounts.get(varName) ?? 0;
89625
89653
  addLens(lineNum, `${usageCount} usage${usageCount !== 1 ? "s" : ""}`);
89626
89654
  }
89627
89655
  }