@rohal12/spindle-lsp 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -2397,8 +2397,11 @@ function parseConfig(content, format) {
2397
2397
  return { macros: {} };
2398
2398
  }
2399
2399
  const obj = raw;
2400
+ const spindle0 = obj["spindle-0"];
2401
+ const source = spindle0 && typeof spindle0 === "object" ? spindle0 : obj;
2400
2402
  return {
2401
- macros: typeof obj.macros === "object" && obj.macros !== null ? obj.macros : {}
2403
+ macros: typeof source.macros === "object" && source.macros !== null ? source.macros : {},
2404
+ enums: typeof source.enums === "object" && source.enums !== null ? source.enums : void 0
2402
2405
  };
2403
2406
  }
2404
2407
  function findConfigFile(workspaceRoot) {
@@ -2426,7 +2429,10 @@ var init_config_loader = __esm({
2426
2429
  CONFIG_FILENAMES = [
2427
2430
  "spindle.config.yaml",
2428
2431
  "spindle.config.yml",
2429
- "spindle.config.json"
2432
+ "spindle.config.json",
2433
+ "t3lt.twee-config.yaml",
2434
+ "t3lt.twee-config.yml",
2435
+ "t3lt.twee-config.json"
2430
2436
  ];
2431
2437
  EMPTY_CONFIG = { macros: {} };
2432
2438
  }
@@ -2685,7 +2691,26 @@ async function runCheck(args2) {
2685
2691
  }
2686
2692
  return 0;
2687
2693
  }
2688
- const configRoot = options.configPath ? resolve(cwd, options.configPath, "..") : cwd;
2694
+ let configRoot;
2695
+ if (options.configPath) {
2696
+ configRoot = resolve(cwd, options.configPath, "..");
2697
+ } else {
2698
+ const dirs = uniqueFiles.map((f) => resolve(f, ".."));
2699
+ configRoot = dirs.reduce((a, b) => {
2700
+ while (!b.startsWith(a)) a = resolve(a, "..");
2701
+ return a;
2702
+ });
2703
+ let search = configRoot;
2704
+ for (let i = 0; i < 10; i++) {
2705
+ if (findConfigFile(search)) {
2706
+ configRoot = search;
2707
+ break;
2708
+ }
2709
+ const parent = resolve(search, "..");
2710
+ if (parent === search) break;
2711
+ search = parent;
2712
+ }
2713
+ }
2689
2714
  const projectConfig = loadConfigFromDisk(configRoot);
2690
2715
  const workspace = new WorkspaceModel();
2691
2716
  const fileContents = /* @__PURE__ */ new Map();
@@ -4453,6 +4478,299 @@ var init_code_actions = __esm({
4453
4478
  }
4454
4479
  });
4455
4480
 
4481
+ // src/plugins/document-symbol.ts
4482
+ import { SymbolKind } from "vscode-languageserver";
4483
+ function computeDocumentSymbols(uri, workspace) {
4484
+ const text = workspace.documents.getText(uri);
4485
+ if (text === void 0) return [];
4486
+ const passages = workspace.passages.getPassagesInDocument(uri);
4487
+ if (passages.length === 0) return [];
4488
+ const storyVarsPassage = workspace.passages.getStoryVariables();
4489
+ const lines = text.split("\n");
4490
+ const symbols = [];
4491
+ for (const passage of passages) {
4492
+ const headerLine = passage.range.start.line;
4493
+ const selectionRange = {
4494
+ start: { line: headerLine, character: 0 },
4495
+ end: { line: headerLine, character: lines[headerLine]?.length ?? 0 }
4496
+ };
4497
+ const passageSymbol = {
4498
+ name: passage.name,
4499
+ kind: SymbolKind.Namespace,
4500
+ range: passage.range,
4501
+ selectionRange,
4502
+ children: []
4503
+ };
4504
+ if (passage.tags?.includes("widget")) {
4505
+ const contentStart = passage.range.start.line + 1;
4506
+ const contentEnd = passage.range.end.line + 1;
4507
+ const widgetDefRegex2 = /\{widget\s+"([^"]+)"[^}]*\}/gi;
4508
+ for (let i = contentStart; i < contentEnd && i < lines.length; i++) {
4509
+ widgetDefRegex2.lastIndex = 0;
4510
+ let match;
4511
+ while ((match = widgetDefRegex2.exec(lines[i])) !== null) {
4512
+ const charStart = match.index;
4513
+ const charEnd = charStart + match[0].length;
4514
+ passageSymbol.children.push({
4515
+ name: match[1],
4516
+ kind: SymbolKind.Function,
4517
+ range: {
4518
+ start: { line: i, character: charStart },
4519
+ end: { line: i, character: charEnd }
4520
+ },
4521
+ selectionRange: {
4522
+ start: { line: i, character: charStart },
4523
+ end: { line: i, character: charEnd }
4524
+ }
4525
+ });
4526
+ }
4527
+ }
4528
+ }
4529
+ if (storyVarsPassage && storyVarsPassage.uri === uri && passage.name === "StoryVariables") {
4530
+ const contentStart = passage.range.start.line + 1;
4531
+ const contentEnd = passage.range.end.line + 1;
4532
+ for (let i = contentStart; i < contentEnd && i < lines.length; i++) {
4533
+ const varMatch = lines[i].match(/^\$([A-Za-z_$][\w$]*)\s*=/);
4534
+ if (varMatch) {
4535
+ const charEnd = varMatch[0].length;
4536
+ passageSymbol.children.push({
4537
+ name: "$" + varMatch[1],
4538
+ kind: SymbolKind.Variable,
4539
+ range: {
4540
+ start: { line: i, character: 0 },
4541
+ end: { line: i, character: lines[i].length }
4542
+ },
4543
+ selectionRange: {
4544
+ start: { line: i, character: 0 },
4545
+ end: { line: i, character: charEnd }
4546
+ }
4547
+ });
4548
+ }
4549
+ }
4550
+ }
4551
+ symbols.push(passageSymbol);
4552
+ }
4553
+ return symbols;
4554
+ }
4555
+ function toLspRange7(r) {
4556
+ return {
4557
+ start: { line: r.start.line, character: r.start.character },
4558
+ end: { line: r.end.line, character: r.end.character }
4559
+ };
4560
+ }
4561
+ function toLspDocumentSymbol(sym) {
4562
+ return {
4563
+ name: sym.name,
4564
+ kind: sym.kind,
4565
+ range: toLspRange7(sym.range),
4566
+ selectionRange: toLspRange7(sym.selectionRange),
4567
+ children: sym.children?.map(toLspDocumentSymbol)
4568
+ };
4569
+ }
4570
+ var documentSymbolPlugin;
4571
+ var init_document_symbol = __esm({
4572
+ "src/plugins/document-symbol.ts"() {
4573
+ "use strict";
4574
+ documentSymbolPlugin = {
4575
+ id: "document-symbol",
4576
+ capabilities: {
4577
+ documentSymbolProvider: true
4578
+ },
4579
+ initialize(ctx) {
4580
+ ctx.connection.onDocumentSymbol((params) => {
4581
+ const symbols = computeDocumentSymbols(params.textDocument.uri, ctx.workspace);
4582
+ return symbols.map(toLspDocumentSymbol);
4583
+ });
4584
+ }
4585
+ };
4586
+ }
4587
+ });
4588
+
4589
+ // src/plugins/workspace-symbol.ts
4590
+ import { SymbolKind as SymbolKind2 } from "vscode-languageserver";
4591
+ function searchWorkspaceSymbols(query, workspace) {
4592
+ const lowerQuery = query.toLowerCase();
4593
+ const results = [];
4594
+ for (const passage of workspace.passages.getAllPassages()) {
4595
+ if (lowerQuery && !passage.name.toLowerCase().includes(lowerQuery)) continue;
4596
+ results.push({
4597
+ name: passage.name,
4598
+ kind: SymbolKind2.Namespace,
4599
+ uri: passage.uri,
4600
+ range: passage.range
4601
+ });
4602
+ }
4603
+ for (const widget of workspace.widgets.getAllWidgets()) {
4604
+ if (lowerQuery && !widget.name.toLowerCase().includes(lowerQuery)) continue;
4605
+ results.push({
4606
+ name: widget.name,
4607
+ kind: SymbolKind2.Function,
4608
+ uri: widget.uri,
4609
+ range: widget.range
4610
+ });
4611
+ }
4612
+ for (const [name, decl] of workspace.variables.getDeclared()) {
4613
+ const displayName = "$" + name;
4614
+ if (lowerQuery && !displayName.toLowerCase().includes(lowerQuery)) continue;
4615
+ results.push({
4616
+ name: displayName,
4617
+ kind: SymbolKind2.Variable,
4618
+ uri: decl.declarationUri ?? "",
4619
+ range: decl.declarationRange ?? { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } }
4620
+ });
4621
+ }
4622
+ return results;
4623
+ }
4624
+ function toLspRange8(r) {
4625
+ return {
4626
+ start: { line: r.start.line, character: r.start.character },
4627
+ end: { line: r.end.line, character: r.end.character }
4628
+ };
4629
+ }
4630
+ var workspaceSymbolPlugin;
4631
+ var init_workspace_symbol = __esm({
4632
+ "src/plugins/workspace-symbol.ts"() {
4633
+ "use strict";
4634
+ workspaceSymbolPlugin = {
4635
+ id: "workspace-symbol",
4636
+ capabilities: {
4637
+ workspaceSymbolProvider: true
4638
+ },
4639
+ initialize(ctx) {
4640
+ ctx.connection.onWorkspaceSymbol((params) => {
4641
+ const symbols = searchWorkspaceSymbols(params.query, ctx.workspace);
4642
+ return symbols.map((s) => ({
4643
+ name: s.name,
4644
+ kind: s.kind,
4645
+ location: {
4646
+ uri: s.uri,
4647
+ range: toLspRange8(s.range)
4648
+ }
4649
+ }));
4650
+ });
4651
+ }
4652
+ };
4653
+ }
4654
+ });
4655
+
4656
+ // src/plugins/folding-range.ts
4657
+ import { FoldingRangeKind } from "vscode-languageserver";
4658
+ function computeFoldingRanges(uri, workspace) {
4659
+ const text = workspace.documents.getText(uri);
4660
+ if (text === void 0) return [];
4661
+ const ranges = [];
4662
+ const passages = workspace.passages.getPassagesInDocument(uri);
4663
+ for (const passage of passages) {
4664
+ const startLine = passage.range.start.line;
4665
+ const endLine = passage.range.end.line;
4666
+ if (endLine > startLine) {
4667
+ ranges.push({
4668
+ startLine,
4669
+ endLine,
4670
+ kind: "region"
4671
+ });
4672
+ }
4673
+ }
4674
+ const macros = parseMacros(text);
4675
+ pairMacros(macros, (name) => workspace.macros.isBlock(name));
4676
+ for (const macro of macros) {
4677
+ if (macro.open && macro.pair !== -1) {
4678
+ const closingMacro = macros[macro.pair];
4679
+ const startLine = macro.range.start.line;
4680
+ const endLine = closingMacro.range.start.line;
4681
+ if (endLine > startLine) {
4682
+ ranges.push({
4683
+ startLine,
4684
+ endLine
4685
+ });
4686
+ }
4687
+ }
4688
+ }
4689
+ return ranges;
4690
+ }
4691
+ var foldingRangePlugin;
4692
+ var init_folding_range = __esm({
4693
+ "src/plugins/folding-range.ts"() {
4694
+ "use strict";
4695
+ init_macro_parser();
4696
+ foldingRangePlugin = {
4697
+ id: "folding-range",
4698
+ capabilities: {
4699
+ foldingRangeProvider: true
4700
+ },
4701
+ initialize(ctx) {
4702
+ ctx.connection.onFoldingRanges((params) => {
4703
+ const ranges = computeFoldingRanges(params.textDocument.uri, ctx.workspace);
4704
+ return ranges.map((r) => ({
4705
+ startLine: r.startLine,
4706
+ endLine: r.endLine,
4707
+ kind: r.kind === "region" ? FoldingRangeKind.Region : void 0
4708
+ }));
4709
+ });
4710
+ }
4711
+ };
4712
+ }
4713
+ });
4714
+
4715
+ // src/plugins/document-link.ts
4716
+ function computeDocumentLinks(uri, workspace) {
4717
+ const text = workspace.documents.getText(uri);
4718
+ if (text === void 0) return [];
4719
+ const passages = workspace.passages.getPassagesInDocument(uri);
4720
+ if (passages.length === 0) return [];
4721
+ const links = [];
4722
+ for (const passage of passages) {
4723
+ const contentStartLine = passage.range.start.line + 1;
4724
+ const contentEndLine = passage.range.end.line + 1;
4725
+ const lines = text.split("\n");
4726
+ const contentLines = lines.slice(contentStartLine, contentEndLine);
4727
+ const content = contentLines.join("\n");
4728
+ const passageLinks = parseLinks(content, contentStartLine);
4729
+ for (const ref of passageLinks) {
4730
+ const targetPassage = workspace.passages.getPassage(ref.name);
4731
+ let target;
4732
+ if (targetPassage) {
4733
+ target = `${targetPassage.uri}#L${targetPassage.range.start.line + 1}`;
4734
+ }
4735
+ links.push({
4736
+ range: ref.range,
4737
+ target
4738
+ });
4739
+ }
4740
+ }
4741
+ return links;
4742
+ }
4743
+ function toLspRange9(r) {
4744
+ return {
4745
+ start: { line: r.start.line, character: r.start.character },
4746
+ end: { line: r.end.line, character: r.end.character }
4747
+ };
4748
+ }
4749
+ var documentLinkPlugin;
4750
+ var init_document_link = __esm({
4751
+ "src/plugins/document-link.ts"() {
4752
+ "use strict";
4753
+ init_link_parser();
4754
+ documentLinkPlugin = {
4755
+ id: "document-link",
4756
+ capabilities: {
4757
+ documentLinkProvider: {
4758
+ resolveProvider: false
4759
+ }
4760
+ },
4761
+ initialize(ctx) {
4762
+ ctx.connection.onDocumentLinks((params) => {
4763
+ const links = computeDocumentLinks(params.textDocument.uri, ctx.workspace);
4764
+ return links.map((l) => ({
4765
+ range: toLspRange9(l.range),
4766
+ target: l.target
4767
+ }));
4768
+ });
4769
+ }
4770
+ };
4771
+ }
4772
+ });
4773
+
4456
4774
  // src/plugins/index.ts
4457
4775
  var allPlugins;
4458
4776
  var init_plugins = __esm({
@@ -4470,6 +4788,10 @@ var init_plugins = __esm({
4470
4788
  init_semantic_tokens();
4471
4789
  init_code_actions();
4472
4790
  init_format();
4791
+ init_document_symbol();
4792
+ init_workspace_symbol();
4793
+ init_folding_range();
4794
+ init_document_link();
4473
4795
  allPlugins = [
4474
4796
  diagnosticsPlugin,
4475
4797
  completionsPlugin,
@@ -4482,7 +4804,11 @@ var init_plugins = __esm({
4482
4804
  inlayHintsPlugin,
4483
4805
  semanticTokensPlugin,
4484
4806
  codeActionsPlugin,
4485
- formatPlugin
4807
+ formatPlugin,
4808
+ documentSymbolPlugin,
4809
+ workspaceSymbolPlugin,
4810
+ foldingRangePlugin,
4811
+ documentLinkPlugin
4486
4812
  ];
4487
4813
  }
4488
4814
  });
@@ -4546,7 +4872,8 @@ function startServer(_args) {
4546
4872
  { globPattern: "**/*.twee" },
4547
4873
  { globPattern: "**/*.js" },
4548
4874
  { globPattern: "**/*.ts" },
4549
- { globPattern: "**/spindle.config.*" }
4875
+ { globPattern: "**/spindle.config.*" },
4876
+ { globPattern: "**/*twee-config.*" }
4550
4877
  ]
4551
4878
  });
4552
4879
  if (workspace) {