dsh-vscode-mode 0.1.45 → 0.1.46
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/README.md +4 -0
- package/lib/client.js +168 -2
- package/lib/client.js.map +1 -1
- package/lib/index.js +105 -5
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/monaco/lsp/providers.ts +10 -1
- package/src/client/monaco/lsp/underline.ts +101 -0
- package/src/client/styles/editor.css +2 -0
- package/src/client/ui/EditorView.ts +2 -0
- package/src/lsp/client.ts +4 -0
- package/src/lsp/derive.ts +96 -0
- package/src/lsp/server.ts +50 -4
- package/src/shared/lsp.ts +57 -0
package/lib/index.js
CHANGED
|
@@ -5760,6 +5760,7 @@ function createLspClient(transport, events = {}) {
|
|
|
5760
5760
|
const pending = /* @__PURE__ */ new Map();
|
|
5761
5761
|
let serverCapabilities = {
|
|
5762
5762
|
definition: false,
|
|
5763
|
+
declaration: false,
|
|
5763
5764
|
references: false,
|
|
5764
5765
|
documentSymbol: false,
|
|
5765
5766
|
workspaceSymbol: false,
|
|
@@ -5894,6 +5895,7 @@ function createLspClient(transport, events = {}) {
|
|
|
5894
5895
|
didSave: true
|
|
5895
5896
|
},
|
|
5896
5897
|
definition: { dynamicRegistration: false },
|
|
5898
|
+
declaration: { dynamicRegistration: false },
|
|
5897
5899
|
references: { dynamicRegistration: false },
|
|
5898
5900
|
documentSymbol: { dynamicRegistration: false },
|
|
5899
5901
|
hover: { dynamicRegistration: false },
|
|
@@ -5913,6 +5915,7 @@ function createLspClient(transport, events = {}) {
|
|
|
5913
5915
|
const legend = caps.semanticTokensProvider?.legend;
|
|
5914
5916
|
serverCapabilities = {
|
|
5915
5917
|
definition: Boolean(caps.definitionProvider),
|
|
5918
|
+
declaration: Boolean(caps.declarationProvider),
|
|
5916
5919
|
references: Boolean(caps.referencesProvider),
|
|
5917
5920
|
documentSymbol: Boolean(caps.documentSymbolProvider),
|
|
5918
5921
|
workspaceSymbol: Boolean(caps.workspaceSymbolProvider),
|
|
@@ -5966,6 +5969,73 @@ function pathToFileUri(absPath) {
|
|
|
5966
5969
|
return pathToFileURL(normalized).toString();
|
|
5967
5970
|
}
|
|
5968
5971
|
//#endregion
|
|
5972
|
+
//#region src/lsp/derive.ts
|
|
5973
|
+
/** file:// URI(或裸路径)→ 归一化绝对路径(小写、/ 分隔)。 */
|
|
5974
|
+
function normAbs(uri) {
|
|
5975
|
+
const path = String(uri ?? "").replace(/^file:\/\/\/?/, "");
|
|
5976
|
+
return decodeURIComponent(path).replace(/\\/g, "/").replace(/^\/([A-Za-z]:)/, "$1").toLowerCase();
|
|
5977
|
+
}
|
|
5978
|
+
/** 取文档 text 在 LSP range(0-based)内的切片。 */
|
|
5979
|
+
function sliceRange(text, range) {
|
|
5980
|
+
const lines = text.split(/\r\n|\r|\n/);
|
|
5981
|
+
const start = range.start;
|
|
5982
|
+
const end = range.end;
|
|
5983
|
+
const startLine = Math.max(0, start.line);
|
|
5984
|
+
const endLine = Math.max(startLine, end.line);
|
|
5985
|
+
if (startLine >= lines.length || endLine >= lines.length) return "";
|
|
5986
|
+
const startChar = Math.max(0, start.character);
|
|
5987
|
+
if (startLine === endLine) return lines[startLine].slice(startChar, Math.max(startChar, end.character));
|
|
5988
|
+
const first = lines[startLine].slice(startChar);
|
|
5989
|
+
const middle = lines.slice(startLine + 1, endLine);
|
|
5990
|
+
const last = lines[endLine].slice(0, Math.max(0, end.character));
|
|
5991
|
+
return [
|
|
5992
|
+
first,
|
|
5993
|
+
...middle,
|
|
5994
|
+
last
|
|
5995
|
+
].join("\n");
|
|
5996
|
+
}
|
|
5997
|
+
/** LSP position 是否落在 range 内(start 包含、end 排除;零宽按点匹配)。 */
|
|
5998
|
+
function posInLspRange(pos, range) {
|
|
5999
|
+
const start = range.start;
|
|
6000
|
+
const end = range.end ?? start;
|
|
6001
|
+
if (start.line === end.line && start.character === end.character) return pos.line === start.line && pos.character === start.character;
|
|
6002
|
+
if (pos.line < start.line || pos.line > end.line) return false;
|
|
6003
|
+
if (pos.line === start.line && pos.character < start.character) return false;
|
|
6004
|
+
if (pos.line === end.line && pos.character >= end.character) return false;
|
|
6005
|
+
return true;
|
|
6006
|
+
}
|
|
6007
|
+
/** 两个 range 是否完全一致。 */
|
|
6008
|
+
function sameRange(a, b) {
|
|
6009
|
+
return a.start.line === b.start.line && a.start.character === b.start.character && a.end.line === b.end.line && a.end.character === b.end.character;
|
|
6010
|
+
}
|
|
6011
|
+
/** range 长度(行/列均按 0-based 差估算,仅用于取"最小包裹"排序)。 */
|
|
6012
|
+
function rangeSize(r) {
|
|
6013
|
+
return (r.end.line - r.start.line) * 1e6 + (r.end.line === r.start.line ? r.end.character - r.start.character : r.end.character);
|
|
6014
|
+
}
|
|
6015
|
+
/**
|
|
6016
|
+
* 从引用列表推导定义位置。
|
|
6017
|
+
* @author ddj 2026年09月02号
|
|
6018
|
+
* @param queryPos 查询位置(LSP 0-based)
|
|
6019
|
+
* @param locations references(includeDeclaration) 结果
|
|
6020
|
+
* @param docText 当前文档全文(词文本一致校验)
|
|
6021
|
+
* @param docAbsPath 当前文档绝对路径(root+相对路径,与 loc.uri 归一化后比较)
|
|
6022
|
+
* @returns 推导出的定义位置;无法确定返回 null
|
|
6023
|
+
*/
|
|
6024
|
+
function deriveDefinitionFromLocations(queryPos, locations, docText, docAbsPath) {
|
|
6025
|
+
if (!locations.length) return null;
|
|
6026
|
+
const docAbs = normAbs(docAbsPath);
|
|
6027
|
+
const containing = locations.filter((loc) => posInLspRange(queryPos, loc.range)).sort((a, b) => rangeSize(a.range) - rangeSize(b.range))[0];
|
|
6028
|
+
if (!containing) return null;
|
|
6029
|
+
const queryWord = sliceRange(docText, containing.range);
|
|
6030
|
+
if (!queryWord) return null;
|
|
6031
|
+
const candidates = locations.filter((loc) => {
|
|
6032
|
+
return normAbs(loc.uri) === docAbs && sliceRange(docText, loc.range) === queryWord;
|
|
6033
|
+
});
|
|
6034
|
+
if (!candidates.length) return null;
|
|
6035
|
+
const first = candidates[0];
|
|
6036
|
+
return sameRange(first.range, containing.range) ? containing : first;
|
|
6037
|
+
}
|
|
6038
|
+
//#endregion
|
|
5969
6039
|
//#region src/lsp/server.ts
|
|
5970
6040
|
/**
|
|
5971
6041
|
* dsh-vscode-mode host — 单语言服务器会话(绑定 工作区根 + 语言)。
|
|
@@ -5990,6 +6060,7 @@ function createLspServer(spec, root, languageId, logger) {
|
|
|
5990
6060
|
let client = null;
|
|
5991
6061
|
let capabilities = {
|
|
5992
6062
|
definition: false,
|
|
6063
|
+
declaration: false,
|
|
5993
6064
|
references: false,
|
|
5994
6065
|
documentSymbol: false,
|
|
5995
6066
|
workspaceSymbol: false,
|
|
@@ -6173,13 +6244,42 @@ function createLspServer(spec, root, languageId, logger) {
|
|
|
6173
6244
|
async definition(path, line, character) {
|
|
6174
6245
|
const doc = docs.get(path);
|
|
6175
6246
|
if (!doc || !await readyWait) return [];
|
|
6176
|
-
|
|
6247
|
+
const client = ensureClient();
|
|
6248
|
+
const position = {
|
|
6249
|
+
line,
|
|
6250
|
+
character
|
|
6251
|
+
};
|
|
6252
|
+
const direct = normalizeLocations(await client.request("textDocument/definition", {
|
|
6177
6253
|
textDocument: { uri: doc.uri },
|
|
6178
|
-
position
|
|
6179
|
-
line,
|
|
6180
|
-
character
|
|
6181
|
-
}
|
|
6254
|
+
position
|
|
6182
6255
|
}));
|
|
6256
|
+
if (direct.length) return direct;
|
|
6257
|
+
if (capabilities.declaration) try {
|
|
6258
|
+
const decl = normalizeLocations(await client.request("textDocument/declaration", {
|
|
6259
|
+
textDocument: { uri: doc.uri },
|
|
6260
|
+
position
|
|
6261
|
+
}));
|
|
6262
|
+
if (decl.length) {
|
|
6263
|
+
log("definition fallback → declaration (" + path + ":" + line + ":" + character + ")");
|
|
6264
|
+
return decl;
|
|
6265
|
+
}
|
|
6266
|
+
} catch (error) {
|
|
6267
|
+
log("declaration request failed: " + String(error));
|
|
6268
|
+
}
|
|
6269
|
+
try {
|
|
6270
|
+
const derived = deriveDefinitionFromLocations(position, normalizeLocations(await client.request("textDocument/references", {
|
|
6271
|
+
textDocument: { uri: doc.uri },
|
|
6272
|
+
position,
|
|
6273
|
+
context: { includeDeclaration: true }
|
|
6274
|
+
})), doc.text, doc.uri);
|
|
6275
|
+
if (derived) {
|
|
6276
|
+
log("definition fallback → references-derived (" + path + ":" + line + ":" + character + ")");
|
|
6277
|
+
return [derived];
|
|
6278
|
+
}
|
|
6279
|
+
} catch (error) {
|
|
6280
|
+
log("references fallback failed: " + String(error));
|
|
6281
|
+
}
|
|
6282
|
+
return [];
|
|
6183
6283
|
},
|
|
6184
6284
|
async references(path, line, character, includeDeclaration) {
|
|
6185
6285
|
const doc = docs.get(path);
|