如何在实施 Go To Definition 时获取当前 text/symbol
How to get current text/symbol when implementing Go To Definition
我正在使用语言服务器协议开发我的第一个 vscode 扩展,我需要在 Right click -> Go to definition
被触发时获取文本
我当前的 onDefinition
方法仅接收 textPosition
export default class DefinitionFinder extends Handler {
constructor(
protected connection: Connection,
private refManager: ReferenceManager)
{
super();
this.connection.onDefinition(async (textPosition) => {
return this.handleErrors(
this.getDefinition(textPosition), undefined) as Promise<Definition>;
});
}
private async getDefinition(textPosition: TextDocumentPositionParams): Promise<Location[]> {
const text = "funABC";
// instead of hardcoded value I need to get the text/symbol
// that is going to be use to go to definition
return this.refManager.getDefinitionLocations(text);
}
TextDocumentPositionParams
只包含documentUri
、line(number)
和character(number)
这是否意味着每次调用 onDefinition
我都需要打开文档,转到行和字符并获取当前单词?
export interface TextDocumentPositionParams {
/**
* The text document.
*/
textDocument: TextDocumentIdentifier;
/**
* The position inside the text document.
*/
position: Position;
}
export interface TextDocumentIdentifier {
/**
* The text document's uri. (string)
*/
uri: DocumentUri;
}
export declare namespace Position {
/**
* Creates a new Position literal from the given line and character.
* @param line The position's line.
* @param character The position's character.
*/
语言服务器通常会根据收到的文档更改事件维护一个文本文档缓存。如果您使用 TypeScript 编写语言服务器,则可以简单地使用 vscode-languageserver
和 vscode-languageserver-textdocument
包中的实现。相关摘录自official sample:
import { TextDocuments } from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
// Create a simple text document manager.
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
...
// Make the text document manager listen on the connection
// for open, change and close text document events
documents.listen(connection);
那么你可以这样做:
documents.get(uri).getText(range)
在我的例子中,我实现了这个:
let word = document.getText(document.getWordRangeAtPosition(position));
这适用于扩展 API
当在语言服务器上请求“转到定义”
时,这就是我最终实现逻辑以获取 word/symbol 的方式
我决定 return 一个 LocationLink,它也显示为 word/symbol
上的超链接
this.connection.onDefinition(async (textPosition) => {
return this.handleErrors(
this.getDefinitionLink(textPosition), undefined) as Promise<LocationLink[]>;
});
此方法从文档中获取符号,然后在 refManager 中查看其定义
private async getDefinitionLink(textPosition: TextDocumentPositionParams): Promise<LocationLink[]> {
const symbol = this.getSymbolAtPosition(textPosition.position, textPosition.textDocument.uri);
return this.refManager.getDefinitionLink(symbol);
}
这是提取当前单词的实际逻辑,无论它是否在中间单击。
let TokenSeparatorsXML = /[\t= <>"]/;
public getSymbolAtPosition(position: Position, documentUri: string): string {
const range = {
start: { line: position.line, character: 0},
end: { line: position.line, character: Number.MAX_VALUE }
};
//get the whole line
const txtDoc = this.refManager.getDocument(documentUri)!;
const context = txtDoc.getText(range);
const offset = position.character ;
let start = offset-1;
while ((start > 0) && !context[start].match(this.TokenSeparatorsXML))
{
start--;
}
let end = offset;
while ((end < context.length) && !context[end].match(this.TokenSeparatorsXML))
{
end++;
}
const symbol = context.substr(start + 1, end - start - 1);
console.log(`${start}->${end}- symbol: ${symbol}`);
return symbol;
}
在我的例子中,令牌分隔符非常窄,但您应该考虑使用单词模式 https://code.visualstudio.com/api/language-extensions/language-configuration-guide#word-pattern
可以在此处找到扩展的完整代码 - https://github.com/mauriciogracia/petrel-xml
我正在使用语言服务器协议开发我的第一个 vscode 扩展,我需要在 Right click -> Go to definition
被触发时获取文本
我当前的 onDefinition
方法仅接收 textPosition
export default class DefinitionFinder extends Handler {
constructor(
protected connection: Connection,
private refManager: ReferenceManager)
{
super();
this.connection.onDefinition(async (textPosition) => {
return this.handleErrors(
this.getDefinition(textPosition), undefined) as Promise<Definition>;
});
}
private async getDefinition(textPosition: TextDocumentPositionParams): Promise<Location[]> {
const text = "funABC";
// instead of hardcoded value I need to get the text/symbol
// that is going to be use to go to definition
return this.refManager.getDefinitionLocations(text);
}
TextDocumentPositionParams
只包含documentUri
、line(number)
和character(number)
这是否意味着每次调用 onDefinition
我都需要打开文档,转到行和字符并获取当前单词?
export interface TextDocumentPositionParams {
/**
* The text document.
*/
textDocument: TextDocumentIdentifier;
/**
* The position inside the text document.
*/
position: Position;
}
export interface TextDocumentIdentifier {
/**
* The text document's uri. (string)
*/
uri: DocumentUri;
}
export declare namespace Position {
/**
* Creates a new Position literal from the given line and character.
* @param line The position's line.
* @param character The position's character.
*/
语言服务器通常会根据收到的文档更改事件维护一个文本文档缓存。如果您使用 TypeScript 编写语言服务器,则可以简单地使用 vscode-languageserver
和 vscode-languageserver-textdocument
包中的实现。相关摘录自official sample:
import { TextDocuments } from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
// Create a simple text document manager.
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
...
// Make the text document manager listen on the connection
// for open, change and close text document events
documents.listen(connection);
那么你可以这样做:
documents.get(uri).getText(range)
在我的例子中,我实现了这个:
let word = document.getText(document.getWordRangeAtPosition(position));
这适用于扩展 API
当在语言服务器上请求“转到定义”
时,这就是我最终实现逻辑以获取 word/symbol 的方式我决定 return 一个 LocationLink,它也显示为 word/symbol
上的超链接this.connection.onDefinition(async (textPosition) => {
return this.handleErrors(
this.getDefinitionLink(textPosition), undefined) as Promise<LocationLink[]>;
});
此方法从文档中获取符号,然后在 refManager 中查看其定义
private async getDefinitionLink(textPosition: TextDocumentPositionParams): Promise<LocationLink[]> {
const symbol = this.getSymbolAtPosition(textPosition.position, textPosition.textDocument.uri);
return this.refManager.getDefinitionLink(symbol);
}
这是提取当前单词的实际逻辑,无论它是否在中间单击。
let TokenSeparatorsXML = /[\t= <>"]/;
public getSymbolAtPosition(position: Position, documentUri: string): string {
const range = {
start: { line: position.line, character: 0},
end: { line: position.line, character: Number.MAX_VALUE }
};
//get the whole line
const txtDoc = this.refManager.getDocument(documentUri)!;
const context = txtDoc.getText(range);
const offset = position.character ;
let start = offset-1;
while ((start > 0) && !context[start].match(this.TokenSeparatorsXML))
{
start--;
}
let end = offset;
while ((end < context.length) && !context[end].match(this.TokenSeparatorsXML))
{
end++;
}
const symbol = context.substr(start + 1, end - start - 1);
console.log(`${start}->${end}- symbol: ${symbol}`);
return symbol;
}
在我的例子中,令牌分隔符非常窄,但您应该考虑使用单词模式 https://code.visualstudio.com/api/language-extensions/language-configuration-guide#word-pattern
可以在此处找到扩展的完整代码 - https://github.com/mauriciogracia/petrel-xml