@rejot-dev/thalo-lsp 0.1.0 → 0.2.1
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/handlers/definition.js +1 -1
- package/dist/handlers/definition.js.map +1 -1
- package/dist/handlers/hover.js +1 -1
- package/dist/handlers/hover.js.map +1 -1
- package/dist/handlers/references.js +1 -1
- package/dist/handlers/references.js.map +1 -1
- package/dist/handlers/semantic-tokens.js +1 -1
- package/dist/handlers/semantic-tokens.js.map +1 -1
- package/dist/server.bundled.js +8 -2
- package/dist/server.js +8 -2
- package/dist/server.js.map +1 -1
- package/package.json +6 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseDocument } from "@rejot-dev/thalo/
|
|
1
|
+
import { parseDocument } from "@rejot-dev/thalo/node";
|
|
2
2
|
import { findDefinition, findEntityDefinition, findFieldDefinition, findNodeAtPosition, findSectionDefinition } from "@rejot-dev/thalo";
|
|
3
3
|
|
|
4
4
|
//#region src/handlers/definition.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.js","names":[],"sources":["../../src/handlers/definition.ts"],"sourcesContent":["import type { Position, Location } from \"vscode-languageserver\";\nimport type { TextDocument } from \"vscode-languageserver-textdocument\";\nimport {\n findNodeAtPosition,\n findDefinition,\n findEntityDefinition,\n findFieldDefinition,\n findSectionDefinition,\n type Workspace,\n type Position as ThaloPosition,\n} from \"@rejot-dev/thalo\";\nimport { parseDocument } from \"@rejot-dev/thalo/
|
|
1
|
+
{"version":3,"file":"definition.js","names":[],"sources":["../../src/handlers/definition.ts"],"sourcesContent":["import type { Position, Location } from \"vscode-languageserver\";\nimport type { TextDocument } from \"vscode-languageserver-textdocument\";\nimport {\n findNodeAtPosition,\n findDefinition,\n findEntityDefinition,\n findFieldDefinition,\n findSectionDefinition,\n type Workspace,\n type Position as ThaloPosition,\n} from \"@rejot-dev/thalo\";\nimport { parseDocument } from \"@rejot-dev/thalo/node\";\n\n/**\n * Convert a file path to a URI\n */\nfunction pathToUri(path: string): string {\n // Add file:// prefix if not present\n if (!path.startsWith(\"file://\")) {\n return `file://${encodeURIComponent(path).replace(/%2F/g, \"/\")}`;\n }\n return path;\n}\n\n/**\n * Get the file type from a URI\n */\nfunction getFileType(uri: string): \"thalo\" | \"markdown\" {\n if (uri.endsWith(\".thalo\")) {\n return \"thalo\";\n }\n if (uri.endsWith(\".md\")) {\n return \"markdown\";\n }\n return \"thalo\";\n}\n\n/**\n * Convert LSP Position to thalo Position (both are 0-based).\n */\nfunction lspToThaloPosition(pos: Position): ThaloPosition {\n return { line: pos.line, column: pos.character };\n}\n\n/**\n * Handle textDocument/definition request\n *\n * Finds the definition location for various syntax elements at the given position:\n * - ^link-id → Entry definition\n * - Entity name in instance/alter-entity → define-entity\n * - Metadata key → Field definition in schema\n * - Section header → Section definition in schema\n *\n * Supports both standalone .thalo files and thalo blocks embedded in markdown.\n *\n * @param workspace - The thalo workspace\n * @param document - The text document\n * @param position - The position in the document (line/character)\n * @returns The definition location, or null if not found\n */\nexport function handleDefinition(\n workspace: Workspace,\n document: TextDocument,\n position: Position,\n): Location | null {\n const fileType = getFileType(document.uri);\n\n try {\n // Parse the document\n const parsed = parseDocument(document.getText(), {\n fileType,\n filename: document.uri,\n });\n\n // Find what element is at the position using the AST\n const context = findNodeAtPosition(parsed, lspToThaloPosition(position));\n\n switch (context.kind) {\n case \"link\": {\n // Find the definition for this link\n const result = findDefinition(workspace, context.linkId);\n if (result) {\n return {\n uri: pathToUri(result.file),\n range: {\n start: {\n line: result.location.startPosition.row,\n character: result.location.startPosition.column,\n },\n end: {\n line: result.location.endPosition.row,\n character: result.location.endPosition.column,\n },\n },\n };\n }\n return null;\n }\n\n case \"entity\":\n case \"schema_entity\": {\n // Find the define-entity for this entity\n const entityName = context.kind === \"entity\" ? context.entityName : context.entityName;\n const result = findEntityDefinition(workspace, entityName);\n if (result) {\n return {\n uri: pathToUri(result.file),\n range: {\n start: {\n line: result.location.startPosition.row,\n character: result.location.startPosition.column,\n },\n end: {\n line: result.location.endPosition.row,\n character: result.location.endPosition.column,\n },\n },\n };\n }\n return null;\n }\n\n case \"metadata_key\": {\n // Find the field definition in the schema\n const result = findFieldDefinition(workspace, context.key, context.entityContext);\n if (result) {\n return {\n uri: pathToUri(result.file),\n range: {\n start: {\n line: result.location.startPosition.row,\n character: result.location.startPosition.column,\n },\n end: {\n line: result.location.endPosition.row,\n character: result.location.endPosition.column,\n },\n },\n };\n }\n return null;\n }\n\n case \"section_header\": {\n // Find the section definition in the schema\n const result = findSectionDefinition(workspace, context.sectionName, context.entityContext);\n if (result) {\n return {\n uri: pathToUri(result.file),\n range: {\n start: {\n line: result.location.startPosition.row,\n character: result.location.startPosition.column,\n },\n end: {\n line: result.location.endPosition.row,\n character: result.location.endPosition.column,\n },\n },\n };\n }\n return null;\n }\n\n case \"field_name\": {\n // In schema definitions, go to the field definition itself\n const result = findFieldDefinition(workspace, context.fieldName, context.entityContext);\n if (result) {\n return {\n uri: pathToUri(result.file),\n range: {\n start: {\n line: result.location.startPosition.row,\n character: result.location.startPosition.column,\n },\n end: {\n line: result.location.endPosition.row,\n character: result.location.endPosition.column,\n },\n },\n };\n }\n return null;\n }\n\n case \"section_name\": {\n // In schema definitions, go to the section definition itself\n const result = findSectionDefinition(workspace, context.sectionName, context.entityContext);\n if (result) {\n return {\n uri: pathToUri(result.file),\n range: {\n start: {\n line: result.location.startPosition.row,\n character: result.location.startPosition.column,\n },\n end: {\n line: result.location.endPosition.row,\n character: result.location.endPosition.column,\n },\n },\n };\n }\n return null;\n }\n\n default:\n return null;\n }\n } catch (error) {\n console.error(`[thalo-lsp] Error in definition handler:`, error);\n return null;\n }\n}\n"],"mappings":"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"}
|
package/dist/handlers/hover.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hover.js","names":["hover: Hover"],"sources":["../../src/handlers/hover.ts"],"sourcesContent":["import type { Hover, Position } from \"vscode-languageserver\";\nimport type { TextDocument } from \"vscode-languageserver-textdocument\";\nimport {\n findNodeAtPosition,\n getHoverInfo,\n type Workspace,\n type Position as ThaloPosition,\n} from \"@rejot-dev/thalo\";\nimport { parseDocument } from \"@rejot-dev/thalo/
|
|
1
|
+
{"version":3,"file":"hover.js","names":["hover: Hover"],"sources":["../../src/handlers/hover.ts"],"sourcesContent":["import type { Hover, Position } from \"vscode-languageserver\";\nimport type { TextDocument } from \"vscode-languageserver-textdocument\";\nimport {\n findNodeAtPosition,\n getHoverInfo,\n type Workspace,\n type Position as ThaloPosition,\n} from \"@rejot-dev/thalo\";\nimport { parseDocument } from \"@rejot-dev/thalo/node\";\n\n/**\n * Get the file type from a URI\n */\nfunction getFileType(uri: string): \"thalo\" | \"markdown\" {\n if (uri.endsWith(\".thalo\")) {\n return \"thalo\";\n }\n if (uri.endsWith(\".md\")) {\n return \"markdown\";\n }\n return \"thalo\";\n}\n\n/**\n * Convert LSP Position to thalo Position (both are 0-based).\n */\nfunction lspToThaloPosition(pos: Position): ThaloPosition {\n return { line: pos.line, column: pos.character };\n}\n\n/**\n * Handle textDocument/hover request\n *\n * Provides hover information for various syntax elements:\n * - ^link-id: Shows target entry details\n * - #tag: Shows tag usage statistics\n * - Directives: Shows documentation\n * - Entity names: Shows schema with fields and sections\n * - Metadata keys: Shows field type and description\n * - Type expressions: Shows type documentation\n * - Section headers: Shows section description\n * - Timestamps: Shows entry info or link reference hint\n *\n * Supports both standalone .thalo files and thalo blocks embedded in markdown.\n *\n * @param workspace - The thalo workspace\n * @param document - The text document\n * @param position - The hover position\n * @returns Hover information, or null if nothing to show\n */\nexport function handleHover(\n workspace: Workspace,\n document: TextDocument,\n position: Position,\n): Hover | null {\n const fileType = getFileType(document.uri);\n\n try {\n // Parse the document\n const parsed = parseDocument(document.getText(), {\n fileType,\n filename: document.uri,\n });\n\n // Find what element is at the position using the AST\n const context = findNodeAtPosition(parsed, lspToThaloPosition(position));\n\n // Get hover info from the service\n const result = getHoverInfo(workspace, context);\n\n if (!result) {\n return null;\n }\n\n // Convert to LSP Hover format\n const hover: Hover = {\n contents: {\n kind: \"markdown\",\n value: result.content,\n },\n };\n\n // Add range if available\n if (result.range) {\n hover.range = {\n start: {\n line: result.range.startPosition.row,\n character: result.range.startPosition.column,\n },\n end: {\n line: result.range.endPosition.row,\n character: result.range.endPosition.column,\n },\n };\n }\n\n return hover;\n } catch (error) {\n console.error(`[thalo-lsp] Error in hover handler:`, error);\n return null;\n }\n}\n"],"mappings":";;;;;;;AAaA,SAAS,YAAY,KAAmC;AACtD,KAAI,IAAI,SAAS,SAAS,CACxB,QAAO;AAET,KAAI,IAAI,SAAS,MAAM,CACrB,QAAO;AAET,QAAO;;;;;AAMT,SAAS,mBAAmB,KAA8B;AACxD,QAAO;EAAE,MAAM,IAAI;EAAM,QAAQ,IAAI;EAAW;;;;;;;;;;;;;;;;;;;;;;AAuBlD,SAAgB,YACd,WACA,UACA,UACc;CACd,MAAM,WAAW,YAAY,SAAS,IAAI;AAE1C,KAAI;EAWF,MAAM,SAAS,aAAa,WAHZ,mBAND,cAAc,SAAS,SAAS,EAAE;GAC/C;GACA,UAAU,SAAS;GACpB,CAAC,EAGyC,mBAAmB,SAAS,CAAC,CAGzB;AAE/C,MAAI,CAAC,OACH,QAAO;EAIT,MAAMA,QAAe,EACnB,UAAU;GACR,MAAM;GACN,OAAO,OAAO;GACf,EACF;AAGD,MAAI,OAAO,MACT,OAAM,QAAQ;GACZ,OAAO;IACL,MAAM,OAAO,MAAM,cAAc;IACjC,WAAW,OAAO,MAAM,cAAc;IACvC;GACD,KAAK;IACH,MAAM,OAAO,MAAM,YAAY;IAC/B,WAAW,OAAO,MAAM,YAAY;IACrC;GACF;AAGH,SAAO;UACA,OAAO;AACd,UAAQ,MAAM,uCAAuC,MAAM;AAC3D,SAAO"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseDocument } from "@rejot-dev/thalo/
|
|
1
|
+
import { parseDocument } from "@rejot-dev/thalo/node";
|
|
2
2
|
import { findEntityReferences, findFieldReferences, findNodeAtPosition, findReferences, findSectionReferences, findTagReferences } from "@rejot-dev/thalo";
|
|
3
3
|
|
|
4
4
|
//#region src/handlers/references.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"references.js","names":["locations: Location[]"],"sources":["../../src/handlers/references.ts"],"sourcesContent":["import type { Position, Location, ReferenceContext } from \"vscode-languageserver\";\nimport type { TextDocument } from \"vscode-languageserver-textdocument\";\nimport {\n findNodeAtPosition,\n findReferences,\n findTagReferences,\n findEntityReferences,\n findFieldReferences,\n findSectionReferences,\n type Workspace,\n type Position as ThaloPosition,\n} from \"@rejot-dev/thalo\";\nimport { parseDocument } from \"@rejot-dev/thalo/native\";\n\n/**\n * Convert a file path to a URI\n */\nfunction pathToUri(path: string): string {\n if (!path.startsWith(\"file://\")) {\n return `file://${encodeURIComponent(path).replace(/%2F/g, \"/\")}`;\n }\n return path;\n}\n\n/**\n * Get the file type from a URI\n */\nfunction getFileType(uri: string): \"thalo\" | \"markdown\" {\n if (uri.endsWith(\".thalo\")) {\n return \"thalo\";\n }\n if (uri.endsWith(\".md\")) {\n return \"markdown\";\n }\n return \"thalo\";\n}\n\n/**\n * Convert LSP Position to thalo Position (both are 0-based).\n */\nfunction lspToThaloPosition(pos: Position): ThaloPosition {\n return { line: pos.line, column: pos.character };\n}\n\n/**\n * Handle textDocument/references request\n *\n * Finds all references to various syntax elements at the given position:\n * - ^link-id → All usages of that link\n * - #tag → All entries with that tag\n * - Entity name → All entries using that entity type\n * - Metadata key → All entries using that field\n * - Section header → All entries with that section\n *\n * Supports both standalone .thalo files and thalo blocks embedded in markdown.\n *\n * @param workspace - The thalo workspace\n * @param document - The text document\n * @param position - The position in the document (line/character)\n * @param context - Reference context (includeDeclaration)\n * @returns Array of reference locations, or null if not found\n */\nexport function handleReferences(\n workspace: Workspace,\n document: TextDocument,\n position: Position,\n context: ReferenceContext,\n): Location[] | null {\n const fileType = getFileType(document.uri);\n\n try {\n // Parse the document\n const parsed = parseDocument(document.getText(), {\n fileType,\n filename: document.uri,\n });\n\n // Find what element is at the position using the AST\n const nodeContext = findNodeAtPosition(parsed, lspToThaloPosition(position));\n\n switch (nodeContext.kind) {\n case \"link\": {\n // Find all references to this link\n const result = findReferences(workspace, nodeContext.linkId, context.includeDeclaration);\n if (result) {\n return result.locations.map((loc) => ({\n uri: pathToUri(loc.file),\n range: {\n start: {\n line: loc.location.startPosition.row,\n character: loc.location.startPosition.column,\n },\n end: {\n line: loc.location.endPosition.row,\n character: loc.location.endPosition.column,\n },\n },\n }));\n }\n return null;\n }\n\n case \"tag\": {\n // Find all entries with this tag\n const result = findTagReferences(workspace, nodeContext.tagName);\n return result.references.map((ref) => ({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n }));\n }\n\n case \"entity\":\n case \"schema_entity\": {\n // Find all entries using this entity type\n const entityName =\n nodeContext.kind === \"entity\" ? nodeContext.entityName : nodeContext.entityName;\n const result = findEntityReferences(workspace, entityName, context.includeDeclaration);\n return result.locations.map((loc) => ({\n uri: pathToUri(loc.file),\n range: {\n start: {\n line: loc.location.startPosition.row,\n character: loc.location.startPosition.column,\n },\n end: {\n line: loc.location.endPosition.row,\n character: loc.location.endPosition.column,\n },\n },\n }));\n }\n\n case \"metadata_key\": {\n // Find all entries using this field\n const result = findFieldReferences(workspace, nodeContext.key, nodeContext.entityContext);\n const locations: Location[] = [];\n\n // Include definition if requested\n if (context.includeDeclaration && result.definition) {\n locations.push({\n uri: pathToUri(result.definition.file),\n range: {\n start: {\n line: result.definition.location.startPosition.row,\n character: result.definition.location.startPosition.column,\n },\n end: {\n line: result.definition.location.endPosition.row,\n character: result.definition.location.endPosition.column,\n },\n },\n });\n }\n\n // Add all references\n for (const ref of result.references) {\n locations.push({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n });\n }\n\n return locations;\n }\n\n case \"section_header\": {\n // Find all entries with this section\n const result = findSectionReferences(\n workspace,\n nodeContext.sectionName,\n nodeContext.entityContext,\n );\n const locations: Location[] = [];\n\n // Include definition if requested\n if (context.includeDeclaration && result.definition) {\n locations.push({\n uri: pathToUri(result.definition.file),\n range: {\n start: {\n line: result.definition.location.startPosition.row,\n character: result.definition.location.startPosition.column,\n },\n end: {\n line: result.definition.location.endPosition.row,\n character: result.definition.location.endPosition.column,\n },\n },\n });\n }\n\n // Add all references\n for (const ref of result.references) {\n locations.push({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n });\n }\n\n return locations;\n }\n\n case \"field_name\": {\n // In schema definitions, find all usages of this field\n const result = findFieldReferences(\n workspace,\n nodeContext.fieldName,\n nodeContext.entityContext,\n );\n const locations: Location[] = [];\n\n // Include definition if requested\n if (context.includeDeclaration && result.definition) {\n locations.push({\n uri: pathToUri(result.definition.file),\n range: {\n start: {\n line: result.definition.location.startPosition.row,\n character: result.definition.location.startPosition.column,\n },\n end: {\n line: result.definition.location.endPosition.row,\n character: result.definition.location.endPosition.column,\n },\n },\n });\n }\n\n for (const ref of result.references) {\n locations.push({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n });\n }\n\n return locations;\n }\n\n case \"section_name\": {\n // In schema definitions, find all usages of this section\n const result = findSectionReferences(\n workspace,\n nodeContext.sectionName,\n nodeContext.entityContext,\n );\n const locations: Location[] = [];\n\n // Include definition if requested\n if (context.includeDeclaration && result.definition) {\n locations.push({\n uri: pathToUri(result.definition.file),\n range: {\n start: {\n line: result.definition.location.startPosition.row,\n character: result.definition.location.startPosition.column,\n },\n end: {\n line: result.definition.location.endPosition.row,\n character: result.definition.location.endPosition.column,\n },\n },\n });\n }\n\n for (const ref of result.references) {\n locations.push({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n });\n }\n\n return locations;\n }\n\n default:\n return null;\n }\n } catch (error) {\n console.error(`[thalo-lsp] Error in references handler:`, error);\n return null;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"references.js","names":["locations: Location[]"],"sources":["../../src/handlers/references.ts"],"sourcesContent":["import type { Position, Location, ReferenceContext } from \"vscode-languageserver\";\nimport type { TextDocument } from \"vscode-languageserver-textdocument\";\nimport {\n findNodeAtPosition,\n findReferences,\n findTagReferences,\n findEntityReferences,\n findFieldReferences,\n findSectionReferences,\n type Workspace,\n type Position as ThaloPosition,\n} from \"@rejot-dev/thalo\";\nimport { parseDocument } from \"@rejot-dev/thalo/node\";\n\n/**\n * Convert a file path to a URI\n */\nfunction pathToUri(path: string): string {\n if (!path.startsWith(\"file://\")) {\n return `file://${encodeURIComponent(path).replace(/%2F/g, \"/\")}`;\n }\n return path;\n}\n\n/**\n * Get the file type from a URI\n */\nfunction getFileType(uri: string): \"thalo\" | \"markdown\" {\n if (uri.endsWith(\".thalo\")) {\n return \"thalo\";\n }\n if (uri.endsWith(\".md\")) {\n return \"markdown\";\n }\n return \"thalo\";\n}\n\n/**\n * Convert LSP Position to thalo Position (both are 0-based).\n */\nfunction lspToThaloPosition(pos: Position): ThaloPosition {\n return { line: pos.line, column: pos.character };\n}\n\n/**\n * Handle textDocument/references request\n *\n * Finds all references to various syntax elements at the given position:\n * - ^link-id → All usages of that link\n * - #tag → All entries with that tag\n * - Entity name → All entries using that entity type\n * - Metadata key → All entries using that field\n * - Section header → All entries with that section\n *\n * Supports both standalone .thalo files and thalo blocks embedded in markdown.\n *\n * @param workspace - The thalo workspace\n * @param document - The text document\n * @param position - The position in the document (line/character)\n * @param context - Reference context (includeDeclaration)\n * @returns Array of reference locations, or null if not found\n */\nexport function handleReferences(\n workspace: Workspace,\n document: TextDocument,\n position: Position,\n context: ReferenceContext,\n): Location[] | null {\n const fileType = getFileType(document.uri);\n\n try {\n // Parse the document\n const parsed = parseDocument(document.getText(), {\n fileType,\n filename: document.uri,\n });\n\n // Find what element is at the position using the AST\n const nodeContext = findNodeAtPosition(parsed, lspToThaloPosition(position));\n\n switch (nodeContext.kind) {\n case \"link\": {\n // Find all references to this link\n const result = findReferences(workspace, nodeContext.linkId, context.includeDeclaration);\n if (result) {\n return result.locations.map((loc) => ({\n uri: pathToUri(loc.file),\n range: {\n start: {\n line: loc.location.startPosition.row,\n character: loc.location.startPosition.column,\n },\n end: {\n line: loc.location.endPosition.row,\n character: loc.location.endPosition.column,\n },\n },\n }));\n }\n return null;\n }\n\n case \"tag\": {\n // Find all entries with this tag\n const result = findTagReferences(workspace, nodeContext.tagName);\n return result.references.map((ref) => ({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n }));\n }\n\n case \"entity\":\n case \"schema_entity\": {\n // Find all entries using this entity type\n const entityName =\n nodeContext.kind === \"entity\" ? nodeContext.entityName : nodeContext.entityName;\n const result = findEntityReferences(workspace, entityName, context.includeDeclaration);\n return result.locations.map((loc) => ({\n uri: pathToUri(loc.file),\n range: {\n start: {\n line: loc.location.startPosition.row,\n character: loc.location.startPosition.column,\n },\n end: {\n line: loc.location.endPosition.row,\n character: loc.location.endPosition.column,\n },\n },\n }));\n }\n\n case \"metadata_key\": {\n // Find all entries using this field\n const result = findFieldReferences(workspace, nodeContext.key, nodeContext.entityContext);\n const locations: Location[] = [];\n\n // Include definition if requested\n if (context.includeDeclaration && result.definition) {\n locations.push({\n uri: pathToUri(result.definition.file),\n range: {\n start: {\n line: result.definition.location.startPosition.row,\n character: result.definition.location.startPosition.column,\n },\n end: {\n line: result.definition.location.endPosition.row,\n character: result.definition.location.endPosition.column,\n },\n },\n });\n }\n\n // Add all references\n for (const ref of result.references) {\n locations.push({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n });\n }\n\n return locations;\n }\n\n case \"section_header\": {\n // Find all entries with this section\n const result = findSectionReferences(\n workspace,\n nodeContext.sectionName,\n nodeContext.entityContext,\n );\n const locations: Location[] = [];\n\n // Include definition if requested\n if (context.includeDeclaration && result.definition) {\n locations.push({\n uri: pathToUri(result.definition.file),\n range: {\n start: {\n line: result.definition.location.startPosition.row,\n character: result.definition.location.startPosition.column,\n },\n end: {\n line: result.definition.location.endPosition.row,\n character: result.definition.location.endPosition.column,\n },\n },\n });\n }\n\n // Add all references\n for (const ref of result.references) {\n locations.push({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n });\n }\n\n return locations;\n }\n\n case \"field_name\": {\n // In schema definitions, find all usages of this field\n const result = findFieldReferences(\n workspace,\n nodeContext.fieldName,\n nodeContext.entityContext,\n );\n const locations: Location[] = [];\n\n // Include definition if requested\n if (context.includeDeclaration && result.definition) {\n locations.push({\n uri: pathToUri(result.definition.file),\n range: {\n start: {\n line: result.definition.location.startPosition.row,\n character: result.definition.location.startPosition.column,\n },\n end: {\n line: result.definition.location.endPosition.row,\n character: result.definition.location.endPosition.column,\n },\n },\n });\n }\n\n for (const ref of result.references) {\n locations.push({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n });\n }\n\n return locations;\n }\n\n case \"section_name\": {\n // In schema definitions, find all usages of this section\n const result = findSectionReferences(\n workspace,\n nodeContext.sectionName,\n nodeContext.entityContext,\n );\n const locations: Location[] = [];\n\n // Include definition if requested\n if (context.includeDeclaration && result.definition) {\n locations.push({\n uri: pathToUri(result.definition.file),\n range: {\n start: {\n line: result.definition.location.startPosition.row,\n character: result.definition.location.startPosition.column,\n },\n end: {\n line: result.definition.location.endPosition.row,\n character: result.definition.location.endPosition.column,\n },\n },\n });\n }\n\n for (const ref of result.references) {\n locations.push({\n uri: pathToUri(ref.file),\n range: {\n start: {\n line: ref.location.startPosition.row,\n character: ref.location.startPosition.column,\n },\n end: {\n line: ref.location.endPosition.row,\n character: ref.location.endPosition.column,\n },\n },\n });\n }\n\n return locations;\n }\n\n default:\n return null;\n }\n } catch (error) {\n console.error(`[thalo-lsp] Error in references handler:`, error);\n return null;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic-tokens.js","names":[],"sources":["../../src/handlers/semantic-tokens.ts"],"sourcesContent":["import type { SemanticTokens } from \"vscode-languageserver\";\nimport type { TextDocument } from \"vscode-languageserver-textdocument\";\nimport { extractSemanticTokens, encodeSemanticTokens, type FileType } from \"@rejot-dev/thalo\";\nimport { parseDocument } from \"@rejot-dev/thalo/
|
|
1
|
+
{"version":3,"file":"semantic-tokens.js","names":[],"sources":["../../src/handlers/semantic-tokens.ts"],"sourcesContent":["import type { SemanticTokens } from \"vscode-languageserver\";\nimport type { TextDocument } from \"vscode-languageserver-textdocument\";\nimport { extractSemanticTokens, encodeSemanticTokens, type FileType } from \"@rejot-dev/thalo\";\nimport { parseDocument } from \"@rejot-dev/thalo/node\";\n\n/**\n * Get the file type from a URI\n */\nfunction getFileType(uri: string): FileType {\n if (uri.endsWith(\".thalo\")) {\n return \"thalo\";\n }\n if (uri.endsWith(\".md\")) {\n return \"markdown\";\n }\n return \"thalo\";\n}\n\n/**\n * Handle textDocument/semanticTokens/full request\n *\n * Returns semantic tokens for syntax highlighting.\n *\n * @param document - The text document\n * @returns Semantic tokens in LSP format\n */\nexport function handleSemanticTokens(document: TextDocument): SemanticTokens {\n const fileType = getFileType(document.uri);\n\n try {\n // Parse the document\n const parsed = parseDocument(document.getText(), {\n fileType,\n filename: document.uri,\n });\n\n // Extract semantic tokens\n const tokens = extractSemanticTokens(parsed);\n\n // Encode in LSP delta format\n const data = encodeSemanticTokens(tokens);\n\n return { data };\n } catch (error) {\n console.error(`[thalo-lsp] Error extracting semantic tokens:`, error);\n return { data: [] };\n }\n}\n"],"mappings":";;;;;;;AAQA,SAAS,YAAY,KAAuB;AAC1C,KAAI,IAAI,SAAS,SAAS,CACxB,QAAO;AAET,KAAI,IAAI,SAAS,MAAM,CACrB,QAAO;AAET,QAAO;;;;;;;;;;AAWT,SAAgB,qBAAqB,UAAwC;CAC3E,MAAM,WAAW,YAAY,SAAS,IAAI;AAE1C,KAAI;AAaF,SAAO,EAAE,MAFI,qBAHE,sBANA,cAAc,SAAS,SAAS,EAAE;GAC/C;GACA,UAAU,SAAS;GACpB,CAAC,CAG0C,CAGH,EAE1B;UACR,OAAO;AACd,UAAQ,MAAM,iDAAiD,MAAM;AACrE,SAAO,EAAE,MAAM,EAAE,EAAE"}
|
package/dist/server.bundled.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { DidChangeConfigurationNotification, FileChangeType, ProposedFeatures, createConnection as createConnection$1 } from "vscode-languageserver/node.js";
|
|
4
4
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
5
|
-
import { createWorkspace, parseDocument } from "@rejot-dev/thalo/
|
|
5
|
+
import { createWorkspace, initParser, parseDocument } from "@rejot-dev/thalo/node";
|
|
6
6
|
import { ALL_DIRECTIVES, INSTANCE_DIRECTIVES, PRIMITIVE_TYPES, SCHEMA_BLOCK_HEADERS, SCHEMA_DIRECTIVES, TypeExpr, checkDocument, encodeSemanticTokens, extractSemanticTokens, findDefinition, findEntityDefinition, findEntityReferences, findFieldDefinition, findFieldReferences, findNodeAtPosition, findReferences, findSectionDefinition, findSectionReferences, findTagReferences, getHoverInfo, isInstanceDirective, isSchemaDirective, isSyntaxError, isSynthesisDirective, tokenModifiers, tokenTypes } from "@rejot-dev/thalo";
|
|
7
7
|
|
|
8
8
|
//#region src/capabilities.ts
|
|
@@ -1758,7 +1758,13 @@ function startServer(connection = createConnection()) {
|
|
|
1758
1758
|
connection.listen();
|
|
1759
1759
|
console.error("[thalo-lsp] Server started");
|
|
1760
1760
|
}
|
|
1761
|
-
if (import.meta.url === `file://${process.argv[1]}`)
|
|
1761
|
+
if (import.meta.url === `file://${process.argv[1]}`) initParser().then(() => {
|
|
1762
|
+
startServer();
|
|
1763
|
+
}).catch((err) => {
|
|
1764
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1765
|
+
console.error(`[thalo-lsp] Failed to initialize parser: ${message}`);
|
|
1766
|
+
process.exit(1);
|
|
1767
|
+
});
|
|
1762
1768
|
|
|
1763
1769
|
//#endregion
|
|
1764
1770
|
export { createConnection, startServer, tokenLegend };
|
package/dist/server.js
CHANGED
|
@@ -9,7 +9,7 @@ import * as fs from "node:fs";
|
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
import { DidChangeConfigurationNotification, FileChangeType, ProposedFeatures, createConnection as createConnection$1 } from "vscode-languageserver/node.js";
|
|
11
11
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
12
|
-
import { createWorkspace } from "@rejot-dev/thalo/
|
|
12
|
+
import { createWorkspace, initParser } from "@rejot-dev/thalo/node";
|
|
13
13
|
|
|
14
14
|
//#region src/server.ts
|
|
15
15
|
/**
|
|
@@ -360,7 +360,13 @@ function startServer(connection = createConnection()) {
|
|
|
360
360
|
connection.listen();
|
|
361
361
|
console.error("[thalo-lsp] Server started");
|
|
362
362
|
}
|
|
363
|
-
if (import.meta.url === `file://${process.argv[1]}`)
|
|
363
|
+
if (import.meta.url === `file://${process.argv[1]}`) initParser().then(() => {
|
|
364
|
+
startServer();
|
|
365
|
+
}).catch((err) => {
|
|
366
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
367
|
+
console.error(`[thalo-lsp] Failed to initialize parser: ${message}`);
|
|
368
|
+
process.exit(1);
|
|
369
|
+
});
|
|
364
370
|
|
|
365
371
|
//#endregion
|
|
366
372
|
export { createConnection, startServer, tokenLegend };
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":["files: string[]","path","createLspConnection","allAffectedFiles: string[]"],"sources":["../src/server.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n createConnection as createLspConnection,\n ProposedFeatures,\n InitializeParams,\n InitializeResult,\n type Connection,\n DidChangeConfigurationNotification,\n FileChangeType,\n} from \"vscode-languageserver/node.js\";\nimport { TextDocument } from \"vscode-languageserver-textdocument\";\nimport type { FileType } from \"@rejot-dev/thalo\";\nimport { createWorkspace, Workspace } from \"@rejot-dev/thalo/native\";\n\nimport { serverCapabilities, tokenLegend } from \"./capabilities.js\";\nimport { handleDefinition } from \"./handlers/definition.js\";\nimport { handleReferences } from \"./handlers/references.js\";\nimport { handleSemanticTokens } from \"./handlers/semantic-tokens.js\";\nimport { getDiagnostics } from \"./handlers/diagnostics.js\";\nimport { handleHover } from \"./handlers/hover.js\";\nimport { handleCompletion, handleCompletionResolve } from \"./handlers/completions/completions.js\";\n\n/**\n * Server state\n */\ninterface ServerState {\n /** The thalo workspace for cross-file features */\n workspace: Workspace;\n /** Text documents managed by the server */\n documents: Map<string, TextDocument>;\n /** The LSP connection */\n connection: Connection;\n /** Workspace folder paths (file system paths, not URIs) */\n workspaceFolders: string[];\n}\n\n/**\n * Create the initial server state\n */\nfunction createServerState(connection: Connection): ServerState {\n return {\n workspace: createWorkspace(),\n documents: new Map(),\n connection,\n workspaceFolders: [],\n };\n}\n\n/**\n * Get the file type from a URI\n */\nfunction getFileType(uri: string): FileType {\n if (uri.endsWith(\".thalo\")) {\n return \"thalo\";\n }\n if (uri.endsWith(\".md\")) {\n return \"markdown\";\n }\n // Default to thalo\n return \"thalo\";\n}\n\n/**\n * Convert a URI to a file path\n */\nfunction uriToPath(uri: string): string {\n // Remove file:// prefix\n if (uri.startsWith(\"file://\")) {\n return decodeURIComponent(uri.slice(7));\n }\n return uri;\n}\n\n/**\n * Collect all .thalo and .md files from a directory recursively\n */\nfunction collectThaloFiles(dir: string): string[] {\n const files: string[] = [];\n\n function walk(currentDir: string): void {\n let entries;\n try {\n entries = fs.readdirSync(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip hidden directories and node_modules\n if (!entry.name.startsWith(\".\") && entry.name !== \"node_modules\") {\n walk(fullPath);\n }\n } else if (entry.isFile()) {\n if (entry.name.endsWith(\".thalo\") || entry.name.endsWith(\".md\")) {\n files.push(fullPath);\n }\n }\n }\n }\n\n walk(dir);\n return files;\n}\n\n/**\n * Load all thalo files from the workspace folders into the workspace.\n * This ensures cross-file features work correctly even for files not yet opened.\n */\nfunction loadWorkspaceFiles(state: ServerState): void {\n for (const folder of state.workspaceFolders) {\n const files = collectThaloFiles(folder);\n\n for (const file of files) {\n // Skip if already loaded (e.g., from an open document)\n if (state.workspace.getModel(file)) {\n continue;\n }\n\n try {\n const source = fs.readFileSync(file, \"utf-8\");\n const fileType = getFileType(file);\n state.workspace.addDocument(source, { filename: file, fileType });\n } catch (err) {\n console.error(\n `[thalo-lsp] Error loading ${file}: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n\n console.error(`[thalo-lsp] Loaded ${files.length} files from ${folder}`);\n }\n}\n\n/**\n * Publish diagnostics for a single document\n */\nfunction publishDiagnosticsForDocument(state: ServerState, doc: TextDocument): void {\n try {\n const diagnostics = getDiagnostics(state.workspace, doc);\n state.connection.sendDiagnostics({\n uri: doc.uri,\n diagnostics,\n });\n } catch (error) {\n const path = uriToPath(doc.uri);\n console.error(`[thalo-lsp] Error getting diagnostics for ${path}:`, error);\n state.connection.sendDiagnostics({\n uri: doc.uri,\n diagnostics: [\n {\n range: {\n start: { line: 0, character: 0 },\n end: { line: 0, character: 0 },\n },\n severity: 1, // Error\n source: \"thalo\",\n message: `Diagnostic error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n });\n }\n}\n\n/**\n * Refresh diagnostics for specific files based on invalidation result.\n * Only refreshes open documents that are in the affected files list.\n */\nfunction refreshDiagnosticsForFiles(\n state: ServerState,\n affectedFiles: string[],\n changedFile: string,\n): void {\n const affectedSet = new Set(affectedFiles);\n\n // Always refresh the changed file\n for (const doc of state.documents.values()) {\n const docPath = uriToPath(doc.uri);\n if (docPath === changedFile || affectedSet.has(docPath)) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n}\n\n/**\n * Update a document in the workspace and publish diagnostics\n */\nfunction updateDocument(state: ServerState, doc: TextDocument): void {\n const filePath = uriToPath(doc.uri);\n\n try {\n // Use the new updateDocument method which returns affected files\n const invalidation = state.workspace.updateDocument(filePath, doc.getText());\n\n // Refresh diagnostics for affected files only (more efficient)\n if (invalidation.schemasChanged || invalidation.linksChanged) {\n // If schemas or links changed, we might affect other files\n refreshDiagnosticsForFiles(state, invalidation.affectedFiles, filePath);\n } else {\n // Only the changed file is affected\n publishDiagnosticsForDocument(state, doc);\n }\n } catch (error) {\n // Log parse errors but don't crash\n console.error(`[thalo-lsp] Parse error in ${filePath}:`, error);\n\n // Send a parse error diagnostic for the changed document\n state.connection.sendDiagnostics({\n uri: doc.uri,\n diagnostics: [\n {\n range: {\n start: { line: 0, character: 0 },\n end: { line: 0, character: 0 },\n },\n severity: 1, // Error\n source: \"thalo\",\n message: `Parse error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n });\n }\n}\n\n/**\n * Create a new LSP connection\n */\nexport function createConnection(): Connection {\n return createLspConnection(ProposedFeatures.all);\n}\n\n/**\n * Start the LSP server\n *\n * @param connection - The LSP connection to use (defaults to stdio)\n */\nexport function startServer(connection: Connection = createConnection()): void {\n const state = createServerState(connection);\n\n // Initialize handler\n connection.onInitialize((params: InitializeParams): InitializeResult => {\n console.error(`[thalo-lsp] Initializing with workspace: ${params.workspaceFolders?.[0]?.uri}`);\n\n // Store workspace folders for later file scanning\n if (params.workspaceFolders) {\n state.workspaceFolders = params.workspaceFolders.map((folder) => uriToPath(folder.uri));\n } else if (params.rootUri) {\n state.workspaceFolders = [uriToPath(params.rootUri)];\n }\n\n return {\n capabilities: serverCapabilities,\n serverInfo: {\n name: \"thalo-lsp\",\n version: \"0.0.0\",\n },\n };\n });\n\n connection.onInitialized(() => {\n console.error(\"[thalo-lsp] Server initialized\");\n\n // Register for configuration changes\n connection.client.register(DidChangeConfigurationNotification.type, undefined);\n\n // Load all workspace files for cross-file features (entity definitions, links, etc.)\n loadWorkspaceFiles(state);\n });\n\n // Document lifecycle\n connection.onDidOpenTextDocument((params) => {\n const doc = TextDocument.create(\n params.textDocument.uri,\n params.textDocument.languageId,\n params.textDocument.version,\n params.textDocument.text,\n );\n state.documents.set(params.textDocument.uri, doc);\n updateDocument(state, doc);\n\n console.error(`[thalo-lsp] Opened: ${params.textDocument.uri}`);\n });\n\n connection.onDidChangeTextDocument((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (doc) {\n const updated = TextDocument.update(doc, params.contentChanges, params.textDocument.version);\n state.documents.set(params.textDocument.uri, updated);\n updateDocument(state, updated);\n }\n });\n\n connection.onDidCloseTextDocument((params) => {\n state.documents.delete(params.textDocument.uri);\n const filePath = uriToPath(params.textDocument.uri);\n\n // Reload from disk to pick up saved changes and keep cross-file features working\n try {\n if (fs.existsSync(filePath)) {\n const source = fs.readFileSync(filePath, \"utf-8\");\n const fileType = getFileType(params.textDocument.uri);\n state.workspace.addDocument(source, { filename: filePath, fileType });\n } else {\n // File was deleted, remove from workspace\n state.workspace.removeDocument(filePath);\n }\n } catch {\n // If we can't read the file, remove it from the workspace\n state.workspace.removeDocument(filePath);\n }\n\n // Clear diagnostics for closed document (not actively editing it)\n connection.sendDiagnostics({\n uri: params.textDocument.uri,\n diagnostics: [],\n });\n\n console.error(`[thalo-lsp] Closed: ${params.textDocument.uri}`);\n });\n\n // File watcher notifications - handles external file changes\n connection.onDidChangeWatchedFiles((params) => {\n const allAffectedFiles: string[] = [];\n\n for (const change of params.changes) {\n const filePath = uriToPath(change.uri);\n\n // Only process thalo and markdown files\n if (!filePath.endsWith(\".thalo\") && !filePath.endsWith(\".md\")) {\n continue;\n }\n\n // For delete events, always process - even if file is open in editor\n // (VSCode may keep deleted file tabs open, but workspace should reflect reality)\n if (change.type === FileChangeType.Deleted) {\n // Get affected files before removing\n const affected = state.workspace.getAffectedFiles(filePath);\n allAffectedFiles.push(...affected);\n state.workspace.removeDocument(filePath);\n state.documents.delete(change.uri);\n // Clear diagnostics for the deleted file\n connection.sendDiagnostics({ uri: change.uri, diagnostics: [] });\n console.error(`[thalo-lsp] Removed deleted file: ${filePath}`);\n continue;\n }\n\n // Skip create/change if the file is currently open (handled by document lifecycle)\n if (state.documents.has(change.uri)) {\n continue;\n }\n\n switch (change.type) {\n case FileChangeType.Created:\n case FileChangeType.Changed: {\n // Load/reload the file into workspace\n try {\n if (fs.existsSync(filePath)) {\n const source = fs.readFileSync(filePath, \"utf-8\");\n const invalidation = state.workspace.updateDocument(filePath, source);\n allAffectedFiles.push(...invalidation.affectedFiles);\n console.error(`[thalo-lsp] Loaded external file: ${filePath}`);\n }\n } catch (err) {\n console.error(\n `[thalo-lsp] Error loading ${filePath}: ${err instanceof Error ? err.message : err}`,\n );\n }\n break;\n }\n }\n }\n\n // Refresh diagnostics only for affected open documents\n if (allAffectedFiles.length > 0) {\n const affectedSet = new Set(allAffectedFiles);\n for (const doc of state.documents.values()) {\n if (affectedSet.has(uriToPath(doc.uri))) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n }\n });\n\n // File operation notifications - handles user-initiated file operations in the editor\n connection.workspace.onDidCreateFiles((params) => {\n const allAffectedFiles: string[] = [];\n\n for (const file of params.files) {\n const filePath = uriToPath(file.uri);\n\n // Only process thalo and markdown files\n if (!filePath.endsWith(\".thalo\") && !filePath.endsWith(\".md\")) {\n continue;\n }\n\n // Load the new file into workspace\n try {\n if (fs.existsSync(filePath)) {\n const source = fs.readFileSync(filePath, \"utf-8\");\n const invalidation = state.workspace.updateDocument(filePath, source);\n allAffectedFiles.push(...invalidation.affectedFiles);\n console.error(`[thalo-lsp] Loaded created file: ${filePath}`);\n }\n } catch (err) {\n console.error(\n `[thalo-lsp] Error loading created file ${filePath}: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n\n // Refresh diagnostics for affected files\n if (allAffectedFiles.length > 0) {\n const affectedSet = new Set(allAffectedFiles);\n for (const doc of state.documents.values()) {\n if (affectedSet.has(uriToPath(doc.uri))) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n }\n });\n\n connection.workspace.onDidDeleteFiles((params) => {\n const allAffectedFiles: string[] = [];\n\n for (const file of params.files) {\n const filePath = uriToPath(file.uri);\n\n // Only process thalo and markdown files\n if (!filePath.endsWith(\".thalo\") && !filePath.endsWith(\".md\")) {\n continue;\n }\n\n // Get affected files before removing\n const affected = state.workspace.getAffectedFiles(filePath);\n allAffectedFiles.push(...affected);\n state.workspace.removeDocument(filePath);\n console.error(`[thalo-lsp] Removed file: ${filePath}`);\n }\n\n // Refresh diagnostics for affected files\n if (allAffectedFiles.length > 0) {\n const affectedSet = new Set(allAffectedFiles);\n for (const doc of state.documents.values()) {\n if (affectedSet.has(uriToPath(doc.uri))) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n }\n });\n\n connection.workspace.onDidRenameFiles((params) => {\n const allAffectedFiles: string[] = [];\n\n for (const file of params.files) {\n const oldPath = uriToPath(file.oldUri);\n const newPath = uriToPath(file.newUri);\n\n // Only process thalo and markdown files\n const oldIsThalo = oldPath.endsWith(\".thalo\") || oldPath.endsWith(\".md\");\n const newIsThalo = newPath.endsWith(\".thalo\") || newPath.endsWith(\".md\");\n\n if (oldIsThalo) {\n // Get affected files before removing\n const affected = state.workspace.getAffectedFiles(oldPath);\n allAffectedFiles.push(...affected);\n state.workspace.removeDocument(oldPath);\n console.error(`[thalo-lsp] Removed renamed file: ${oldPath}`);\n }\n\n if (newIsThalo) {\n // Load the file at its new location\n try {\n if (fs.existsSync(newPath)) {\n const source = fs.readFileSync(newPath, \"utf-8\");\n const invalidation = state.workspace.updateDocument(newPath, source);\n allAffectedFiles.push(...invalidation.affectedFiles);\n console.error(`[thalo-lsp] Loaded renamed file: ${newPath}`);\n }\n } catch (err) {\n console.error(\n `[thalo-lsp] Error loading renamed file ${newPath}: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n }\n\n // Refresh diagnostics for affected files\n if (allAffectedFiles.length > 0) {\n const affectedSet = new Set(allAffectedFiles);\n for (const doc of state.documents.values()) {\n if (affectedSet.has(uriToPath(doc.uri))) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n }\n });\n\n // Go to Definition\n connection.onDefinition((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return null;\n }\n\n return handleDefinition(state.workspace, doc, params.position);\n });\n\n // Find All References\n connection.onReferences((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return null;\n }\n\n return handleReferences(state.workspace, doc, params.position, params.context);\n });\n\n // Hover\n connection.onHover((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return null;\n }\n\n return handleHover(state.workspace, doc, params.position);\n });\n\n // Completion\n connection.onCompletion((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return [];\n }\n\n return handleCompletion(state.workspace, doc, params);\n });\n\n // Completion resolve\n connection.onCompletionResolve((item) => {\n return handleCompletionResolve(item);\n });\n\n // Semantic Tokens (full)\n connection.onRequest(\"textDocument/semanticTokens/full\", (params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return { data: [] };\n }\n\n return handleSemanticTokens(doc);\n });\n\n // Start listening\n connection.listen();\n console.error(\"[thalo-lsp] Server started\");\n}\n\n// Run server when executed directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n startServer();\n}\n\n// Export for testing\nexport { tokenLegend };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":["files: string[]","path","createLspConnection","allAffectedFiles: string[]"],"sources":["../src/server.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n createConnection as createLspConnection,\n ProposedFeatures,\n InitializeParams,\n InitializeResult,\n type Connection,\n DidChangeConfigurationNotification,\n FileChangeType,\n} from \"vscode-languageserver/node.js\";\nimport { TextDocument } from \"vscode-languageserver-textdocument\";\nimport type { FileType } from \"@rejot-dev/thalo\";\nimport { initParser, createWorkspace, Workspace } from \"@rejot-dev/thalo/node\";\n\nimport { serverCapabilities, tokenLegend } from \"./capabilities.js\";\nimport { handleDefinition } from \"./handlers/definition.js\";\nimport { handleReferences } from \"./handlers/references.js\";\nimport { handleSemanticTokens } from \"./handlers/semantic-tokens.js\";\nimport { getDiagnostics } from \"./handlers/diagnostics.js\";\nimport { handleHover } from \"./handlers/hover.js\";\nimport { handleCompletion, handleCompletionResolve } from \"./handlers/completions/completions.js\";\n\n/**\n * Server state\n */\ninterface ServerState {\n /** The thalo workspace for cross-file features */\n workspace: Workspace;\n /** Text documents managed by the server */\n documents: Map<string, TextDocument>;\n /** The LSP connection */\n connection: Connection;\n /** Workspace folder paths (file system paths, not URIs) */\n workspaceFolders: string[];\n}\n\n/**\n * Create the initial server state\n */\nfunction createServerState(connection: Connection): ServerState {\n return {\n workspace: createWorkspace(),\n documents: new Map(),\n connection,\n workspaceFolders: [],\n };\n}\n\n/**\n * Get the file type from a URI\n */\nfunction getFileType(uri: string): FileType {\n if (uri.endsWith(\".thalo\")) {\n return \"thalo\";\n }\n if (uri.endsWith(\".md\")) {\n return \"markdown\";\n }\n // Default to thalo\n return \"thalo\";\n}\n\n/**\n * Convert a URI to a file path\n */\nfunction uriToPath(uri: string): string {\n // Remove file:// prefix\n if (uri.startsWith(\"file://\")) {\n return decodeURIComponent(uri.slice(7));\n }\n return uri;\n}\n\n/**\n * Collect all .thalo and .md files from a directory recursively\n */\nfunction collectThaloFiles(dir: string): string[] {\n const files: string[] = [];\n\n function walk(currentDir: string): void {\n let entries;\n try {\n entries = fs.readdirSync(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip hidden directories and node_modules\n if (!entry.name.startsWith(\".\") && entry.name !== \"node_modules\") {\n walk(fullPath);\n }\n } else if (entry.isFile()) {\n if (entry.name.endsWith(\".thalo\") || entry.name.endsWith(\".md\")) {\n files.push(fullPath);\n }\n }\n }\n }\n\n walk(dir);\n return files;\n}\n\n/**\n * Load all thalo files from the workspace folders into the workspace.\n * This ensures cross-file features work correctly even for files not yet opened.\n */\nfunction loadWorkspaceFiles(state: ServerState): void {\n for (const folder of state.workspaceFolders) {\n const files = collectThaloFiles(folder);\n\n for (const file of files) {\n // Skip if already loaded (e.g., from an open document)\n if (state.workspace.getModel(file)) {\n continue;\n }\n\n try {\n const source = fs.readFileSync(file, \"utf-8\");\n const fileType = getFileType(file);\n state.workspace.addDocument(source, { filename: file, fileType });\n } catch (err) {\n console.error(\n `[thalo-lsp] Error loading ${file}: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n\n console.error(`[thalo-lsp] Loaded ${files.length} files from ${folder}`);\n }\n}\n\n/**\n * Publish diagnostics for a single document\n */\nfunction publishDiagnosticsForDocument(state: ServerState, doc: TextDocument): void {\n try {\n const diagnostics = getDiagnostics(state.workspace, doc);\n state.connection.sendDiagnostics({\n uri: doc.uri,\n diagnostics,\n });\n } catch (error) {\n const path = uriToPath(doc.uri);\n console.error(`[thalo-lsp] Error getting diagnostics for ${path}:`, error);\n state.connection.sendDiagnostics({\n uri: doc.uri,\n diagnostics: [\n {\n range: {\n start: { line: 0, character: 0 },\n end: { line: 0, character: 0 },\n },\n severity: 1, // Error\n source: \"thalo\",\n message: `Diagnostic error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n });\n }\n}\n\n/**\n * Refresh diagnostics for specific files based on invalidation result.\n * Only refreshes open documents that are in the affected files list.\n */\nfunction refreshDiagnosticsForFiles(\n state: ServerState,\n affectedFiles: string[],\n changedFile: string,\n): void {\n const affectedSet = new Set(affectedFiles);\n\n // Always refresh the changed file\n for (const doc of state.documents.values()) {\n const docPath = uriToPath(doc.uri);\n if (docPath === changedFile || affectedSet.has(docPath)) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n}\n\n/**\n * Update a document in the workspace and publish diagnostics\n */\nfunction updateDocument(state: ServerState, doc: TextDocument): void {\n const filePath = uriToPath(doc.uri);\n\n try {\n // Use the new updateDocument method which returns affected files\n const invalidation = state.workspace.updateDocument(filePath, doc.getText());\n\n // Refresh diagnostics for affected files only (more efficient)\n if (invalidation.schemasChanged || invalidation.linksChanged) {\n // If schemas or links changed, we might affect other files\n refreshDiagnosticsForFiles(state, invalidation.affectedFiles, filePath);\n } else {\n // Only the changed file is affected\n publishDiagnosticsForDocument(state, doc);\n }\n } catch (error) {\n // Log parse errors but don't crash\n console.error(`[thalo-lsp] Parse error in ${filePath}:`, error);\n\n // Send a parse error diagnostic for the changed document\n state.connection.sendDiagnostics({\n uri: doc.uri,\n diagnostics: [\n {\n range: {\n start: { line: 0, character: 0 },\n end: { line: 0, character: 0 },\n },\n severity: 1, // Error\n source: \"thalo\",\n message: `Parse error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n });\n }\n}\n\n/**\n * Create a new LSP connection\n */\nexport function createConnection(): Connection {\n return createLspConnection(ProposedFeatures.all);\n}\n\n/**\n * Start the LSP server\n *\n * @param connection - The LSP connection to use (defaults to stdio)\n */\nexport function startServer(connection: Connection = createConnection()): void {\n const state = createServerState(connection);\n\n // Initialize handler\n connection.onInitialize((params: InitializeParams): InitializeResult => {\n console.error(`[thalo-lsp] Initializing with workspace: ${params.workspaceFolders?.[0]?.uri}`);\n\n // Store workspace folders for later file scanning\n if (params.workspaceFolders) {\n state.workspaceFolders = params.workspaceFolders.map((folder) => uriToPath(folder.uri));\n } else if (params.rootUri) {\n state.workspaceFolders = [uriToPath(params.rootUri)];\n }\n\n return {\n capabilities: serverCapabilities,\n serverInfo: {\n name: \"thalo-lsp\",\n version: \"0.0.0\",\n },\n };\n });\n\n connection.onInitialized(() => {\n console.error(\"[thalo-lsp] Server initialized\");\n\n // Register for configuration changes\n connection.client.register(DidChangeConfigurationNotification.type, undefined);\n\n // Load all workspace files for cross-file features (entity definitions, links, etc.)\n loadWorkspaceFiles(state);\n });\n\n // Document lifecycle\n connection.onDidOpenTextDocument((params) => {\n const doc = TextDocument.create(\n params.textDocument.uri,\n params.textDocument.languageId,\n params.textDocument.version,\n params.textDocument.text,\n );\n state.documents.set(params.textDocument.uri, doc);\n updateDocument(state, doc);\n\n console.error(`[thalo-lsp] Opened: ${params.textDocument.uri}`);\n });\n\n connection.onDidChangeTextDocument((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (doc) {\n const updated = TextDocument.update(doc, params.contentChanges, params.textDocument.version);\n state.documents.set(params.textDocument.uri, updated);\n updateDocument(state, updated);\n }\n });\n\n connection.onDidCloseTextDocument((params) => {\n state.documents.delete(params.textDocument.uri);\n const filePath = uriToPath(params.textDocument.uri);\n\n // Reload from disk to pick up saved changes and keep cross-file features working\n try {\n if (fs.existsSync(filePath)) {\n const source = fs.readFileSync(filePath, \"utf-8\");\n const fileType = getFileType(params.textDocument.uri);\n state.workspace.addDocument(source, { filename: filePath, fileType });\n } else {\n // File was deleted, remove from workspace\n state.workspace.removeDocument(filePath);\n }\n } catch {\n // If we can't read the file, remove it from the workspace\n state.workspace.removeDocument(filePath);\n }\n\n // Clear diagnostics for closed document (not actively editing it)\n connection.sendDiagnostics({\n uri: params.textDocument.uri,\n diagnostics: [],\n });\n\n console.error(`[thalo-lsp] Closed: ${params.textDocument.uri}`);\n });\n\n // File watcher notifications - handles external file changes\n connection.onDidChangeWatchedFiles((params) => {\n const allAffectedFiles: string[] = [];\n\n for (const change of params.changes) {\n const filePath = uriToPath(change.uri);\n\n // Only process thalo and markdown files\n if (!filePath.endsWith(\".thalo\") && !filePath.endsWith(\".md\")) {\n continue;\n }\n\n // For delete events, always process - even if file is open in editor\n // (VSCode may keep deleted file tabs open, but workspace should reflect reality)\n if (change.type === FileChangeType.Deleted) {\n // Get affected files before removing\n const affected = state.workspace.getAffectedFiles(filePath);\n allAffectedFiles.push(...affected);\n state.workspace.removeDocument(filePath);\n state.documents.delete(change.uri);\n // Clear diagnostics for the deleted file\n connection.sendDiagnostics({ uri: change.uri, diagnostics: [] });\n console.error(`[thalo-lsp] Removed deleted file: ${filePath}`);\n continue;\n }\n\n // Skip create/change if the file is currently open (handled by document lifecycle)\n if (state.documents.has(change.uri)) {\n continue;\n }\n\n switch (change.type) {\n case FileChangeType.Created:\n case FileChangeType.Changed: {\n // Load/reload the file into workspace\n try {\n if (fs.existsSync(filePath)) {\n const source = fs.readFileSync(filePath, \"utf-8\");\n const invalidation = state.workspace.updateDocument(filePath, source);\n allAffectedFiles.push(...invalidation.affectedFiles);\n console.error(`[thalo-lsp] Loaded external file: ${filePath}`);\n }\n } catch (err) {\n console.error(\n `[thalo-lsp] Error loading ${filePath}: ${err instanceof Error ? err.message : err}`,\n );\n }\n break;\n }\n }\n }\n\n // Refresh diagnostics only for affected open documents\n if (allAffectedFiles.length > 0) {\n const affectedSet = new Set(allAffectedFiles);\n for (const doc of state.documents.values()) {\n if (affectedSet.has(uriToPath(doc.uri))) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n }\n });\n\n // File operation notifications - handles user-initiated file operations in the editor\n connection.workspace.onDidCreateFiles((params) => {\n const allAffectedFiles: string[] = [];\n\n for (const file of params.files) {\n const filePath = uriToPath(file.uri);\n\n // Only process thalo and markdown files\n if (!filePath.endsWith(\".thalo\") && !filePath.endsWith(\".md\")) {\n continue;\n }\n\n // Load the new file into workspace\n try {\n if (fs.existsSync(filePath)) {\n const source = fs.readFileSync(filePath, \"utf-8\");\n const invalidation = state.workspace.updateDocument(filePath, source);\n allAffectedFiles.push(...invalidation.affectedFiles);\n console.error(`[thalo-lsp] Loaded created file: ${filePath}`);\n }\n } catch (err) {\n console.error(\n `[thalo-lsp] Error loading created file ${filePath}: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n\n // Refresh diagnostics for affected files\n if (allAffectedFiles.length > 0) {\n const affectedSet = new Set(allAffectedFiles);\n for (const doc of state.documents.values()) {\n if (affectedSet.has(uriToPath(doc.uri))) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n }\n });\n\n connection.workspace.onDidDeleteFiles((params) => {\n const allAffectedFiles: string[] = [];\n\n for (const file of params.files) {\n const filePath = uriToPath(file.uri);\n\n // Only process thalo and markdown files\n if (!filePath.endsWith(\".thalo\") && !filePath.endsWith(\".md\")) {\n continue;\n }\n\n // Get affected files before removing\n const affected = state.workspace.getAffectedFiles(filePath);\n allAffectedFiles.push(...affected);\n state.workspace.removeDocument(filePath);\n console.error(`[thalo-lsp] Removed file: ${filePath}`);\n }\n\n // Refresh diagnostics for affected files\n if (allAffectedFiles.length > 0) {\n const affectedSet = new Set(allAffectedFiles);\n for (const doc of state.documents.values()) {\n if (affectedSet.has(uriToPath(doc.uri))) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n }\n });\n\n connection.workspace.onDidRenameFiles((params) => {\n const allAffectedFiles: string[] = [];\n\n for (const file of params.files) {\n const oldPath = uriToPath(file.oldUri);\n const newPath = uriToPath(file.newUri);\n\n // Only process thalo and markdown files\n const oldIsThalo = oldPath.endsWith(\".thalo\") || oldPath.endsWith(\".md\");\n const newIsThalo = newPath.endsWith(\".thalo\") || newPath.endsWith(\".md\");\n\n if (oldIsThalo) {\n // Get affected files before removing\n const affected = state.workspace.getAffectedFiles(oldPath);\n allAffectedFiles.push(...affected);\n state.workspace.removeDocument(oldPath);\n console.error(`[thalo-lsp] Removed renamed file: ${oldPath}`);\n }\n\n if (newIsThalo) {\n // Load the file at its new location\n try {\n if (fs.existsSync(newPath)) {\n const source = fs.readFileSync(newPath, \"utf-8\");\n const invalidation = state.workspace.updateDocument(newPath, source);\n allAffectedFiles.push(...invalidation.affectedFiles);\n console.error(`[thalo-lsp] Loaded renamed file: ${newPath}`);\n }\n } catch (err) {\n console.error(\n `[thalo-lsp] Error loading renamed file ${newPath}: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n }\n\n // Refresh diagnostics for affected files\n if (allAffectedFiles.length > 0) {\n const affectedSet = new Set(allAffectedFiles);\n for (const doc of state.documents.values()) {\n if (affectedSet.has(uriToPath(doc.uri))) {\n publishDiagnosticsForDocument(state, doc);\n }\n }\n }\n });\n\n // Go to Definition\n connection.onDefinition((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return null;\n }\n\n return handleDefinition(state.workspace, doc, params.position);\n });\n\n // Find All References\n connection.onReferences((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return null;\n }\n\n return handleReferences(state.workspace, doc, params.position, params.context);\n });\n\n // Hover\n connection.onHover((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return null;\n }\n\n return handleHover(state.workspace, doc, params.position);\n });\n\n // Completion\n connection.onCompletion((params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return [];\n }\n\n return handleCompletion(state.workspace, doc, params);\n });\n\n // Completion resolve\n connection.onCompletionResolve((item) => {\n return handleCompletionResolve(item);\n });\n\n // Semantic Tokens (full)\n connection.onRequest(\"textDocument/semanticTokens/full\", (params) => {\n const doc = state.documents.get(params.textDocument.uri);\n if (!doc) {\n return { data: [] };\n }\n\n return handleSemanticTokens(doc);\n });\n\n // Start listening\n connection.listen();\n console.error(\"[thalo-lsp] Server started\");\n}\n\n// Run server when executed directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n // Initialize parser (with WASM fallback if native bindings unavailable)\n // then start the server\n initParser()\n .then(() => {\n startServer();\n })\n .catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`[thalo-lsp] Failed to initialize parser: ${message}`);\n process.exit(1);\n });\n}\n\n// Export for testing\nexport { tokenLegend };\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rejot-dev/thalo-lsp",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,7 +26,11 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"vscode-languageserver": "^9.0.1",
|
|
28
28
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
29
|
-
"
|
|
29
|
+
"web-tree-sitter": "^0.25.0",
|
|
30
|
+
"@rejot-dev/thalo": "0.2.1"
|
|
31
|
+
},
|
|
32
|
+
"optionalDependencies": {
|
|
33
|
+
"tree-sitter": "^0.25.0"
|
|
30
34
|
},
|
|
31
35
|
"devDependencies": {
|
|
32
36
|
"@types/node": "^24",
|