umple-lsp-server 0.4.2 → 1.0.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/CHANGELOG.md +10 -0
- package/README.md +35 -0
- package/completions.scm +9 -3
- package/definitions.scm +5 -0
- package/highlights.scm +487 -0
- package/out/codeActions.d.ts +31 -0
- package/out/codeActions.js +361 -0
- package/out/codeActions.js.map +1 -0
- package/out/completionAnalysis.d.ts +9 -1
- package/out/completionAnalysis.js +1211 -64
- package/out/completionAnalysis.js.map +1 -1
- package/out/completionBuilder.d.ts +1 -1
- package/out/completionBuilder.js +463 -319
- package/out/completionBuilder.js.map +1 -1
- package/out/completionTriggers.d.ts +20 -0
- package/out/completionTriggers.js +69 -0
- package/out/completionTriggers.js.map +1 -0
- package/out/diagnosticSources.d.ts +3 -0
- package/out/diagnosticSources.js +11 -0
- package/out/diagnosticSources.js.map +1 -0
- package/out/diagramNavigation.js +3 -3
- package/out/diagramNavigation.js.map +1 -1
- package/out/documentSymbolBuilder.js +2 -37
- package/out/documentSymbolBuilder.js.map +1 -1
- package/out/formatter.d.ts +13 -1
- package/out/formatter.js +303 -10
- package/out/formatter.js.map +1 -1
- package/out/hoverBuilder.js +90 -23
- package/out/hoverBuilder.js.map +1 -1
- package/out/inlayHints.d.ts +21 -0
- package/out/inlayHints.js +98 -0
- package/out/inlayHints.js.map +1 -0
- package/out/referenceSearch.d.ts +1 -1
- package/out/referenceSearch.js +134 -7
- package/out/referenceSearch.js.map +1 -1
- package/out/resolver.js +82 -3
- package/out/resolver.js.map +1 -1
- package/out/semanticTokens.d.ts +32 -0
- package/out/semanticTokens.js +228 -0
- package/out/semanticTokens.js.map +1 -0
- package/out/server.js +216 -36
- package/out/server.js.map +1 -1
- package/out/snippets.d.ts +39 -0
- package/out/snippets.js +328 -0
- package/out/snippets.js.map +1 -0
- package/out/symbolIndex.d.ts +50 -0
- package/out/symbolIndex.js +170 -7
- package/out/symbolIndex.js.map +1 -1
- package/out/symbolPresentation.d.ts +3 -0
- package/out/symbolPresentation.js +45 -0
- package/out/symbolPresentation.js.map +1 -0
- package/out/symbolTypes.d.ts +1 -0
- package/out/tokenAnalysis.js +77 -4
- package/out/tokenAnalysis.js.map +1 -1
- package/out/tokenTypes.d.ts +8 -1
- package/out/tokenTypes.js +2 -0
- package/out/tokenTypes.js.map +1 -1
- package/out/treeUtils.js +17 -4
- package/out/treeUtils.js.map +1 -1
- package/out/workspaceSymbolBuilder.d.ts +3 -0
- package/out/workspaceSymbolBuilder.js +117 -0
- package/out/workspaceSymbolBuilder.js.map +1 -0
- package/package.json +5 -2
- package/references.scm +31 -3
- package/tree-sitter-umple.wasm +0 -0
- package/out/bin.d.ts +0 -2
- package/out/bin.js +0 -5
- package/out/bin.js.map +0 -1
- package/out/log.d.ts +0 -7
- package/out/log.js +0 -22
- package/out/log.js.map +0 -1
- package/out/tsconfig.tsbuildinfo +0 -1
package/out/server.js
CHANGED
|
@@ -8,6 +8,7 @@ const zlib = require("zlib");
|
|
|
8
8
|
const url_1 = require("url");
|
|
9
9
|
const node_1 = require("vscode-languageserver/node");
|
|
10
10
|
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
|
|
11
|
+
const codeActions_1 = require("./codeActions");
|
|
11
12
|
const symbolIndex_1 = require("./symbolIndex");
|
|
12
13
|
const tokenTypes_1 = require("./tokenTypes");
|
|
13
14
|
const resolver_1 = require("./resolver");
|
|
@@ -16,7 +17,12 @@ const hoverBuilder_1 = require("./hoverBuilder");
|
|
|
16
17
|
const renameValidation_1 = require("./renameValidation");
|
|
17
18
|
const traitSmEventResolver_1 = require("./traitSmEventResolver");
|
|
18
19
|
const documentSymbolBuilder_1 = require("./documentSymbolBuilder");
|
|
20
|
+
const workspaceSymbolBuilder_1 = require("./workspaceSymbolBuilder");
|
|
19
21
|
const formatter_1 = require("./formatter");
|
|
22
|
+
const completionTriggers_1 = require("./completionTriggers");
|
|
23
|
+
const diagnosticSources_1 = require("./diagnosticSources");
|
|
24
|
+
const semanticTokens_1 = require("./semanticTokens");
|
|
25
|
+
const inlayHints_1 = require("./inlayHints");
|
|
20
26
|
// Handle CLI flags before opening the LSP connection. Editor integrations
|
|
21
27
|
// always spawn the server with `--stdio` and never pass these flags, so the
|
|
22
28
|
// only callers that hit this branch are humans running the binary directly
|
|
@@ -47,6 +53,13 @@ const documents = new Map();
|
|
|
47
53
|
const pendingValidations = new Map();
|
|
48
54
|
let workspaceRoots = [];
|
|
49
55
|
const rootScanStates = new Map();
|
|
56
|
+
function isPathInsideRoot(filePath, root) {
|
|
57
|
+
const relative = path.relative(path.normalize(root), path.normalize(filePath));
|
|
58
|
+
return relative === "" || (!!relative && !relative.startsWith("..") && !path.isAbsolute(relative));
|
|
59
|
+
}
|
|
60
|
+
function isInWorkspaceRoot(filePath) {
|
|
61
|
+
return workspaceRoots.some((root) => isPathInsideRoot(filePath, root));
|
|
62
|
+
}
|
|
50
63
|
/**
|
|
51
64
|
* Check if the workspace use-graph is ready for the root containing a file.
|
|
52
65
|
* Returns true if the root's scan is complete, false if scanning or idle.
|
|
@@ -55,12 +68,16 @@ const rootScanStates = new Map();
|
|
|
55
68
|
function isUseGraphReadyForFile(filePath) {
|
|
56
69
|
const normalized = path.normalize(filePath);
|
|
57
70
|
for (const [root, state] of rootScanStates) {
|
|
58
|
-
if (normalized
|
|
71
|
+
if (isPathInsideRoot(normalized, root))
|
|
59
72
|
return state === "ready";
|
|
60
73
|
}
|
|
61
74
|
// File outside all workspace roots — no graph needed, local scope is fine
|
|
62
75
|
return true;
|
|
63
76
|
}
|
|
77
|
+
function getOpenDocumentContent(filePath) {
|
|
78
|
+
const uri = (0, url_1.pathToFileURL)(filePath).toString();
|
|
79
|
+
return getDocument(uri)?.getText();
|
|
80
|
+
}
|
|
64
81
|
/**
|
|
65
82
|
* Async cooperative directory scanner. Discovers .ump files without blocking
|
|
66
83
|
* the event loop. Uses fs.promises.readdir with yielding every 100 directories.
|
|
@@ -265,7 +282,15 @@ let supportsFileWatcherDynamicRegistration = false;
|
|
|
265
282
|
const DEFAULT_UMPLESYNC_TIMEOUT_MS = 30000;
|
|
266
283
|
// Track in-flight validations so we can abort stale ones
|
|
267
284
|
const inFlightValidations = new Map();
|
|
285
|
+
// Topic 054 — captured during initialize from
|
|
286
|
+
// `params.capabilities.textDocument.completion.completionItem.snippetSupport`.
|
|
287
|
+
// Snippet items are emitted only when this is true. Clients without snippet
|
|
288
|
+
// support keep the pre-topic-054 keyword/symbol completion shape.
|
|
289
|
+
let clientSnippetSupport = false;
|
|
268
290
|
connection.onInitialize((params) => {
|
|
291
|
+
clientSnippetSupport =
|
|
292
|
+
params.capabilities.textDocument?.completion?.completionItem?.snippetSupport ===
|
|
293
|
+
true;
|
|
269
294
|
const initOptions = params.initializationOptions;
|
|
270
295
|
umpleSyncJarPath =
|
|
271
296
|
initOptions?.umpleSyncJarPath || process.env.UMPLESYNC_JAR_PATH;
|
|
@@ -302,16 +327,49 @@ connection.onInitialize((params) => {
|
|
|
302
327
|
textDocumentSync: node_1.TextDocumentSyncKind.Incremental,
|
|
303
328
|
completionProvider: {
|
|
304
329
|
resolveProvider: false,
|
|
305
|
-
|
|
330
|
+
// Stage-1 trigger expansion (topic 051 item 1).
|
|
331
|
+
// "/" use-path completion inside `use "..."`
|
|
332
|
+
// "." qualified names, dotted state paths
|
|
333
|
+
// "-" association arrow start (`1 -|`); trait-SM op marker
|
|
334
|
+
// "," isA / implementsReq / param continuation
|
|
335
|
+
// Stage-2 (topic 053):
|
|
336
|
+
// "<" association arrow `1 <|`; trait-SM op recovery `isA T<-|`
|
|
337
|
+
// "@" Java annotation (suppressed); aggregation `1 <@|`
|
|
338
|
+
// "(" parameter-type slot at method (param-type completion)
|
|
339
|
+
// Topic 063:
|
|
340
|
+
// " " retrigger after structural whitespace slots (`1 |`,
|
|
341
|
+
// `1 -> |`, `1 -> * |`, `implementsReq |`). We intentionally
|
|
342
|
+
// do not trigger on token finishers (`>`, `*`) themselves; the
|
|
343
|
+
// next slot starts after the separating space.
|
|
344
|
+
triggerCharacters: [...completionTriggers_1.COMPLETION_TRIGGER_CHARACTERS],
|
|
306
345
|
},
|
|
307
346
|
definitionProvider: true,
|
|
308
347
|
referencesProvider: true,
|
|
348
|
+
// Topic 059 — `Go to Implementations` for traits. Returns
|
|
349
|
+
// class/trait declarations that implement the trait via `isA`,
|
|
350
|
+
// both directly and transitively (interfaces excluded).
|
|
351
|
+
implementationProvider: true,
|
|
309
352
|
renameProvider: {
|
|
310
353
|
prepareProvider: true,
|
|
311
354
|
},
|
|
312
355
|
hoverProvider: true,
|
|
313
356
|
documentSymbolProvider: true,
|
|
357
|
+
workspaceSymbolProvider: true,
|
|
358
|
+
semanticTokensProvider: {
|
|
359
|
+
legend: semanticTokens_1.UMPLE_SEMANTIC_TOKENS_LEGEND,
|
|
360
|
+
full: true,
|
|
361
|
+
range: false,
|
|
362
|
+
},
|
|
363
|
+
inlayHintProvider: {
|
|
364
|
+
resolveProvider: false,
|
|
365
|
+
},
|
|
314
366
|
documentFormattingProvider: true,
|
|
367
|
+
// Quick-fix code actions. Pure classifiers live in codeActions.ts and
|
|
368
|
+
// are gated on compiler diagnostic codes plus shape whitelists.
|
|
369
|
+
codeActionProvider: {
|
|
370
|
+
codeActionKinds: [node_1.CodeActionKind.QuickFix],
|
|
371
|
+
resolveProvider: false,
|
|
372
|
+
},
|
|
315
373
|
},
|
|
316
374
|
};
|
|
317
375
|
});
|
|
@@ -483,11 +541,17 @@ connection.onDidChangeWatchedFiles((params) => {
|
|
|
483
541
|
symbolIndex_1.symbolIndex.removeFile(filePath);
|
|
484
542
|
}
|
|
485
543
|
else {
|
|
486
|
-
// Created or
|
|
544
|
+
// Created or changed. If workspace/symbol has already indexed this file,
|
|
545
|
+
// keep symbols fresh; otherwise only maintain the lightweight use graph.
|
|
487
546
|
const content = readFileSafe(filePath);
|
|
488
547
|
if (content) {
|
|
489
|
-
|
|
490
|
-
|
|
548
|
+
if (symbolIndex_1.symbolIndex.isFileIndexed(filePath)) {
|
|
549
|
+
symbolIndex_1.symbolIndex.indexFile(filePath, content);
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
const uses = symbolIndex_1.symbolIndex.extractUseStatements(filePath, content);
|
|
553
|
+
symbolIndex_1.symbolIndex.updateUseGraphEdges(filePath, uses);
|
|
554
|
+
}
|
|
491
555
|
}
|
|
492
556
|
}
|
|
493
557
|
}
|
|
@@ -512,6 +576,10 @@ connection.onCompletion(async (params) => {
|
|
|
512
576
|
if (info.symbolKinds === "suppress") {
|
|
513
577
|
return [];
|
|
514
578
|
}
|
|
579
|
+
if (params.context?.triggerCharacter === " " &&
|
|
580
|
+
!(0, completionTriggers_1.shouldServeWhitespaceTriggeredCompletion)(info.symbolKinds)) {
|
|
581
|
+
return [];
|
|
582
|
+
}
|
|
515
583
|
// 3. Ensure imported files are indexed
|
|
516
584
|
const reachableFiles = ensureImportsIndexed(docPath, text);
|
|
517
585
|
const items = [];
|
|
@@ -549,7 +617,7 @@ connection.onCompletion(async (params) => {
|
|
|
549
617
|
}));
|
|
550
618
|
}
|
|
551
619
|
// 5. Build semantic completion items (keywords, operators, types, symbols)
|
|
552
|
-
const semanticItems = (0, completionBuilder_1.buildSemanticCompletionItems)(info, symbolKinds, symbolIndex_1.symbolIndex, reachableFiles);
|
|
620
|
+
const semanticItems = (0, completionBuilder_1.buildSemanticCompletionItems)(info, symbolKinds, symbolIndex_1.symbolIndex, reachableFiles, clientSnippetSupport);
|
|
553
621
|
// Merge use_path items (if any) with semantic items, deduplicating
|
|
554
622
|
for (const item of semanticItems) {
|
|
555
623
|
if (!seen.has(item.label)) {
|
|
@@ -686,6 +754,67 @@ function isUnambiguousRename(symbols) {
|
|
|
686
754
|
const name = symbols[0].name;
|
|
687
755
|
return symbols.every((s) => s.name === name);
|
|
688
756
|
}
|
|
757
|
+
function shouldUseWorkspaceWideRename(docPath, symbols) {
|
|
758
|
+
return workspaceRoots.length > 0 &&
|
|
759
|
+
(isInWorkspaceRoot(docPath) || symbols.some((s) => isInWorkspaceRoot(s.file)));
|
|
760
|
+
}
|
|
761
|
+
function indexWorkspaceForRename() {
|
|
762
|
+
symbolIndex_1.symbolIndex.indexWorkspace(workspaceRoots, getOpenDocumentContent);
|
|
763
|
+
return symbolIndex_1.symbolIndex.getIndexedFilePaths();
|
|
764
|
+
}
|
|
765
|
+
function expandRenameDeclarations(resolvedSymbols, filesToSearch) {
|
|
766
|
+
if (resolvedSymbols.length === 0)
|
|
767
|
+
return [];
|
|
768
|
+
const target = resolvedSymbols[0];
|
|
769
|
+
const candidates = symbolIndex_1.symbolIndex.getSymbols({
|
|
770
|
+
name: target.name,
|
|
771
|
+
kind: target.kind,
|
|
772
|
+
});
|
|
773
|
+
return candidates.filter((candidate) => filesToSearch.has(path.normalize(candidate.file)) &&
|
|
774
|
+
candidate.name === target.name &&
|
|
775
|
+
candidate.kind === target.kind &&
|
|
776
|
+
isUnambiguousRename([...resolvedSymbols, candidate]));
|
|
777
|
+
}
|
|
778
|
+
// ── Find Implementations ─────────────────────────────────────────────────────
|
|
779
|
+
// For class/interface/trait targets, return declarations below the target in
|
|
780
|
+
// the `isA` graph. Trait behavior preserves topic 059 semantics: interfaces
|
|
781
|
+
// are excluded and are not traversed for trait targets.
|
|
782
|
+
connection.onImplementation(async (params) => {
|
|
783
|
+
const document = getDocument(params.textDocument.uri);
|
|
784
|
+
if (!document || !symbolIndexReady)
|
|
785
|
+
return [];
|
|
786
|
+
const docPath = getDocumentFilePath(document);
|
|
787
|
+
if (!docPath)
|
|
788
|
+
return [];
|
|
789
|
+
const resolved = resolveSymbolAtPosition(docPath, document.getText(), params.position.line, params.position.character);
|
|
790
|
+
if (!resolved)
|
|
791
|
+
return [];
|
|
792
|
+
const targetSymbols = resolved.symbols.filter((s) => s.kind === "class" || s.kind === "interface" || s.kind === "trait");
|
|
793
|
+
if (targetSymbols.length !== 1)
|
|
794
|
+
return [];
|
|
795
|
+
const target = targetSymbols[0];
|
|
796
|
+
// Same scope model as find-references: declaration files + forward
|
|
797
|
+
// import closure + reverse importers, lazily indexed.
|
|
798
|
+
const reachable = ensureImportsIndexed(docPath, document.getText());
|
|
799
|
+
const targetFiles = new Set([path.normalize(target.file)]);
|
|
800
|
+
for (const f of targetFiles)
|
|
801
|
+
reachable.add(f);
|
|
802
|
+
const reverseImporters = symbolIndex_1.symbolIndex.getReverseImporters(targetFiles);
|
|
803
|
+
for (const f of reverseImporters) {
|
|
804
|
+
if (!symbolIndex_1.symbolIndex.isFileIndexed(f)) {
|
|
805
|
+
try {
|
|
806
|
+
const content = fs.readFileSync(f, "utf8");
|
|
807
|
+
symbolIndex_1.symbolIndex.indexFile(f, content);
|
|
808
|
+
}
|
|
809
|
+
catch {
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
reachable.add(f);
|
|
814
|
+
}
|
|
815
|
+
const implementers = symbolIndex_1.symbolIndex.findIsAImplementers(target.name, target.kind, reachable);
|
|
816
|
+
return implementers.map((sym) => node_1.Location.create((0, url_1.pathToFileURL)(sym.file).toString(), node_1.Range.create(node_1.Position.create(sym.line, sym.column), node_1.Position.create(sym.endLine, sym.endColumn))));
|
|
817
|
+
});
|
|
689
818
|
connection.onPrepareRename(async (params) => {
|
|
690
819
|
const document = getDocument(params.textDocument.uri);
|
|
691
820
|
if (!document || !symbolIndexReady)
|
|
@@ -743,33 +872,39 @@ connection.onRenameRequest(async (params) => {
|
|
|
743
872
|
// Validate new name against the kind-specific rule.
|
|
744
873
|
if (!(0, renameValidation_1.isValidNewName)(resolved.symbols[0].kind, params.newName))
|
|
745
874
|
return null;
|
|
746
|
-
|
|
747
|
-
//
|
|
748
|
-
//
|
|
749
|
-
//
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
875
|
+
const useWorkspaceWideRename = shouldUseWorkspaceWideRename(docPath, resolved.symbols);
|
|
876
|
+
// Check workspace use-graph readiness only for the old import-chain fallback.
|
|
877
|
+
// Workspace-wide rename indexes the workspace synchronously below, so it does
|
|
878
|
+
// not depend on the background use-graph scan having finished.
|
|
879
|
+
if (!useWorkspaceWideRename) {
|
|
880
|
+
for (const sym of resolved.symbols) {
|
|
881
|
+
if (!isUseGraphReadyForFile(sym.file)) {
|
|
882
|
+
// Use window/showMessage notification instead of showWarningMessage
|
|
883
|
+
// (window/showMessageRequest) — some clients like CodeMirror don't
|
|
884
|
+
// implement the request and the rejection crashes the server.
|
|
885
|
+
connection.sendNotification(node_1.ShowMessageNotification.type, {
|
|
886
|
+
type: node_1.MessageType.Warning,
|
|
887
|
+
message: "Workspace scan in progress. Please try rename again in a moment.",
|
|
888
|
+
});
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
760
891
|
}
|
|
761
892
|
}
|
|
762
|
-
// 2. Index forward-reachable files
|
|
763
|
-
//
|
|
764
|
-
//
|
|
893
|
+
// 2. Index forward-reachable files. If the rename target belongs to a
|
|
894
|
+
// workspace root, also synchronously index the workspace before searching.
|
|
895
|
+
// Rename is explicit and must prefer complete edits over request latency.
|
|
765
896
|
const reachableFiles = ensureImportsIndexed(docPath, document.getText());
|
|
766
897
|
// 3. Compute search scope: declaration files + forward-reachable + known reverse importers
|
|
767
898
|
const declFiles = new Set(resolved.symbols.map((s) => path.normalize(s.file)));
|
|
899
|
+
const workspaceFiles = useWorkspaceWideRename
|
|
900
|
+
? indexWorkspaceForRename()
|
|
901
|
+
: new Set();
|
|
768
902
|
const reverseImporters = symbolIndex_1.symbolIndex.getReverseImporters(declFiles);
|
|
769
903
|
const filesToSearch = new Set([
|
|
770
904
|
...declFiles,
|
|
771
905
|
...reachableFiles,
|
|
772
906
|
...reverseImporters,
|
|
907
|
+
...workspaceFiles,
|
|
773
908
|
]);
|
|
774
909
|
// Ensure reverse importers are fully indexed
|
|
775
910
|
for (const file of reverseImporters) {
|
|
@@ -784,11 +919,15 @@ connection.onRenameRequest(async (params) => {
|
|
|
784
919
|
}
|
|
785
920
|
}
|
|
786
921
|
}
|
|
787
|
-
// 4. Expand
|
|
788
|
-
|
|
789
|
-
//
|
|
922
|
+
// 4. Expand declarations after the full search scope is known. This picks up
|
|
923
|
+
// same-identity declarations discovered by workspace indexing, such as
|
|
924
|
+
// partial top-level declarations in files outside the import graph.
|
|
925
|
+
const renameDeclarations = expandRenameDeclarations(resolved.symbols, filesToSearch);
|
|
926
|
+
// 5. Expand shared state declarations (reused SM alias/base equivalence)
|
|
927
|
+
const sharedDecls = symbolIndex_1.symbolIndex.getSharedStateDeclarations(renameDeclarations, filesToSearch);
|
|
928
|
+
// 6. Find ALL references including declarations
|
|
790
929
|
const refs = symbolIndex_1.symbolIndex.findReferences(sharedDecls, filesToSearch, true);
|
|
791
|
-
//
|
|
930
|
+
// 7. Build WorkspaceEdit
|
|
792
931
|
const changes = {};
|
|
793
932
|
for (const r of refs) {
|
|
794
933
|
const uri = (0, url_1.pathToFileURL)(r.file).toString();
|
|
@@ -841,6 +980,37 @@ connection.onDocumentSymbol(async (params) => {
|
|
|
841
980
|
symbolIndex_1.symbolIndex.updateFile(docPath, document.getText());
|
|
842
981
|
return (0, documentSymbolBuilder_1.buildDocumentSymbolTree)(symbolIndex_1.symbolIndex.getFileSymbols(docPath));
|
|
843
982
|
});
|
|
983
|
+
connection.onWorkspaceSymbol(async (params) => {
|
|
984
|
+
if (!symbolIndexReady)
|
|
985
|
+
return [];
|
|
986
|
+
if (workspaceRoots.length > 0) {
|
|
987
|
+
symbolIndex_1.symbolIndex.indexWorkspace(workspaceRoots, (filePath) => {
|
|
988
|
+
const uri = (0, url_1.pathToFileURL)(filePath).toString();
|
|
989
|
+
return getDocument(uri)?.getText();
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
return (0, workspaceSymbolBuilder_1.buildWorkspaceSymbols)(symbolIndex_1.symbolIndex.getAllSymbols(), params.query);
|
|
993
|
+
});
|
|
994
|
+
connection.languages.semanticTokens.on(async (params) => {
|
|
995
|
+
const document = getDocument(params.textDocument.uri);
|
|
996
|
+
if (!document || !symbolIndexReady)
|
|
997
|
+
return { data: [] };
|
|
998
|
+
const docPath = getDocumentFilePath(document);
|
|
999
|
+
if (!docPath)
|
|
1000
|
+
return { data: [] };
|
|
1001
|
+
symbolIndex_1.symbolIndex.updateFile(docPath, document.getText());
|
|
1002
|
+
return (0, semanticTokens_1.buildSemanticTokens)(symbolIndex_1.symbolIndex.getHighlightCaptures(docPath));
|
|
1003
|
+
});
|
|
1004
|
+
connection.languages.inlayHint.on(async (params) => {
|
|
1005
|
+
const document = getDocument(params.textDocument.uri);
|
|
1006
|
+
if (!document || !symbolIndexReady)
|
|
1007
|
+
return [];
|
|
1008
|
+
const docPath = getDocumentFilePath(document);
|
|
1009
|
+
if (!docPath)
|
|
1010
|
+
return [];
|
|
1011
|
+
symbolIndex_1.symbolIndex.updateFile(docPath, document.getText());
|
|
1012
|
+
return (0, inlayHints_1.buildInlayHints)(symbolIndex_1.symbolIndex.getTree(docPath), params.range);
|
|
1013
|
+
});
|
|
844
1014
|
// ── Formatting ──────────────────────────────────────────────────────────────
|
|
845
1015
|
connection.onDocumentFormatting(async (params) => {
|
|
846
1016
|
const document = getDocument(params.textDocument.uri);
|
|
@@ -874,6 +1044,8 @@ connection.onDocumentFormatting(async (params) => {
|
|
|
874
1044
|
...(0, formatter_1.computeIndentEdits)(text, params.options, formatTree),
|
|
875
1045
|
...(0, formatter_1.fixTransitionSpacing)(text, formatTree),
|
|
876
1046
|
...(0, formatter_1.fixAssociationSpacing)(text, formatTree),
|
|
1047
|
+
...(0, formatter_1.fixDeclarationAssignmentSpacing)(text, formatTree),
|
|
1048
|
+
...(0, formatter_1.fixStructuralCommaSpacing)(text, formatTree),
|
|
877
1049
|
...(0, formatter_1.normalizeTopLevelBlankLines)(text, formatTree),
|
|
878
1050
|
...(0, formatter_1.reindentEmbeddedCode)(text, params.options, formatTree),
|
|
879
1051
|
];
|
|
@@ -925,6 +1097,14 @@ connection.onDocumentFormatting(async (params) => {
|
|
|
925
1097
|
node_1.TextEdit.replace(node_1.Range.create(node_1.Position.create(0, 0), node_1.Position.create(lastLine, lastChar)), finalText),
|
|
926
1098
|
];
|
|
927
1099
|
});
|
|
1100
|
+
// Quick-fix code actions. Pure logic lives in `codeActions.ts`; this handler
|
|
1101
|
+
// just routes the diagnostics the client already received.
|
|
1102
|
+
connection.onCodeAction(async (params) => {
|
|
1103
|
+
const document = getDocument(params.textDocument.uri);
|
|
1104
|
+
if (!document)
|
|
1105
|
+
return [];
|
|
1106
|
+
return (0, codeActions_1.buildQuickFixActions)(document, params.context.diagnostics);
|
|
1107
|
+
});
|
|
928
1108
|
function scheduleValidation(document) {
|
|
929
1109
|
const uriKey = normalizeUri(document.uri);
|
|
930
1110
|
const existing = pendingValidations.get(uriKey);
|
|
@@ -1392,7 +1572,8 @@ function parseUmpleJsonDiagnostics(stderr, document, tempFilename, documentDir)
|
|
|
1392
1572
|
severity,
|
|
1393
1573
|
range: node_1.Range.create(node_1.Position.create(useLine, 0), node_1.Position.create(useLine, useLineText.length)),
|
|
1394
1574
|
message,
|
|
1395
|
-
source:
|
|
1575
|
+
source: diagnosticSources_1.UMPLE_DIAGNOSTIC_SOURCE,
|
|
1576
|
+
...(errorCode ? { code: errorCode } : {}),
|
|
1396
1577
|
});
|
|
1397
1578
|
}
|
|
1398
1579
|
continue;
|
|
@@ -1402,18 +1583,17 @@ function parseUmpleJsonDiagnostics(stderr, document, tempFilename, documentDir)
|
|
|
1402
1583
|
const lineText = lines[lineNumber] ?? "";
|
|
1403
1584
|
const firstNonSpace = lineText.search(/\S/);
|
|
1404
1585
|
const startChar = firstNonSpace === -1 ? 0 : firstNonSpace;
|
|
1405
|
-
const
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
result.message,
|
|
1411
|
-
].filter(Boolean);
|
|
1586
|
+
const errorCode = result.errorCode
|
|
1587
|
+
? (severity === node_1.DiagnosticSeverity.Warning ? "W" : "E") +
|
|
1588
|
+
result.errorCode
|
|
1589
|
+
: undefined;
|
|
1590
|
+
const details = [errorCode, result.message].filter(Boolean);
|
|
1412
1591
|
diagnostics.push({
|
|
1413
1592
|
severity,
|
|
1414
1593
|
range: node_1.Range.create(node_1.Position.create(lineNumber, startChar), node_1.Position.create(lineNumber, lineText.length)),
|
|
1415
1594
|
message: details.join(": "),
|
|
1416
|
-
source:
|
|
1595
|
+
source: diagnosticSources_1.UMPLE_DIAGNOSTIC_SOURCE,
|
|
1596
|
+
...(errorCode ? { code: errorCode } : {}),
|
|
1417
1597
|
});
|
|
1418
1598
|
}
|
|
1419
1599
|
return diagnostics;
|