Skip to content

Commit

Permalink
fix: try to resolve failed mapping edit range
Browse files Browse the repository at this point in the history
close #2155
  • Loading branch information
johnsoncodehk committed Jan 4, 2023
1 parent 47dcaae commit 710a6a3
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 102 deletions.
2 changes: 2 additions & 0 deletions packages/language-service/src/languageFeatures/complete.ts
Expand Up @@ -63,6 +63,7 @@ export function register(context: LanguageServiceRuntimeContext) {
cacheData.list = transformCompletionList(
embeddedCompletionList,
range => map.toSourceRange(range),
map.virtualFileDocument,
(newItem, oldItem) => newItem.data = {
uri,
originalItem: oldItem,
Expand Down Expand Up @@ -164,6 +165,7 @@ export function register(context: LanguageServiceRuntimeContext) {
const completionList = transformCompletionList(
embeddedCompletionList,
range => map.toSourceRange(range),
map.virtualFileDocument,
(newItem, oldItem) => newItem.data = {
uri,
originalItem: oldItem,
Expand Down
Expand Up @@ -48,6 +48,7 @@ export function register(context: LanguageServiceRuntimeContext) {
if (range) return range;
return map.toSourceRange(embeddedRange);
},
map.virtualFileDocument,
);
}
}
Expand Down
Expand Up @@ -66,7 +66,7 @@ export function register(context: LanguageServiceRuntimeContext) {

const position = map.toSourcePosition(_inlayHint.position);
const edits = _inlayHint.textEdits
?.map(textEdit => transformTextEdit(textEdit, range => map!.toSourceRange(range)))
?.map(textEdit => transformTextEdit(textEdit, range => map!.toSourceRange(range), map.virtualFileDocument))
.filter(shared.notEmpty);

if (position) {
Expand Down
16 changes: 10 additions & 6 deletions packages/transforms/src/completionItem.ts
@@ -1,15 +1,19 @@
import type * as vscode from 'vscode-languageserver-types';
import { transform as transformLocations } from './locationsLike';
import * as vscode from 'vscode-languageserver-types';
import { transform as transformTextEdit } from './textEdit';
import * as shared from '@volar/shared';

export function transform<T extends vscode.CompletionItem>(item: T, getOtherRange: (range: vscode.Range) => vscode.Range | undefined): T {
export function transform<T extends vscode.CompletionItem>(
item: T,
getOtherRange: (range: vscode.Range) => vscode.Range | undefined,
document: vscode.TextDocument,
): T {
return {
...item,
additionalTextEdits: item.additionalTextEdits
? transformLocations(item.additionalTextEdits, getOtherRange)
: undefined,
?.map(edit => transformTextEdit(edit, getOtherRange, document))
.filter(shared.notEmpty),
textEdit: item.textEdit
? transformTextEdit(item.textEdit, getOtherRange)
? transformTextEdit(item.textEdit, getOtherRange, document)
: undefined,
};
}
3 changes: 2 additions & 1 deletion packages/transforms/src/completionList.ts
Expand Up @@ -4,6 +4,7 @@ import { transform as transformCompletionItem } from './completionItem';
export function transform<T extends vscode.CompletionList>(
completionList: T,
getOtherRange: (range: vscode.Range) => vscode.Range | undefined,
document: vscode.TextDocument,
onItem?: (newItem: vscode.CompletionItem, oldItem: vscode.CompletionItem) => void,
): T {
return {
Expand All @@ -20,7 +21,7 @@ export function transform<T extends vscode.CompletionList>(
: undefined,
} : undefined,
items: completionList.items.map(item => {
const newItem = transformCompletionItem(item, getOtherRange);
const newItem = transformCompletionItem(item, getOtherRange, document);
onItem?.(newItem, item);
return newItem;
}),
Expand Down
86 changes: 71 additions & 15 deletions packages/transforms/src/textEdit.ts
@@ -1,28 +1,84 @@
import * as vscode from 'vscode-languageserver-types';

export function transform<T extends vscode.TextEdit | vscode.InsertReplaceEdit>(textEdit: T, getOtherRange: (range: vscode.Range) => vscode.Range | undefined): T | undefined {
export function transform<T extends vscode.TextEdit | vscode.InsertReplaceEdit>(
textEdit: T,
getOtherRange: (range: vscode.Range) => vscode.Range | undefined,
document: vscode.TextDocument,
): T | undefined {
if (vscode.TextEdit.is(textEdit)) {

const range = getOtherRange(textEdit.range);
if (!range) return;

return {
...textEdit,
range,
let range = getOtherRange(textEdit.range);
if (range) {
return {
...textEdit,
range,
};
};

const cover = tryRecover(getOtherRange, textEdit.range, textEdit.newText, document);
if (cover) {
return {
...textEdit,
range: cover.range,
newText: cover.newText,
};
}
}
else if (vscode.InsertReplaceEdit.is(textEdit)) {

const insert = getOtherRange(textEdit.insert);
if (!insert) return;
const replace = insert ? getOtherRange(textEdit.replace) : undefined;
if (insert && replace) {
return {
...textEdit,
insert,
replace,
};
}

const replace = getOtherRange(textEdit.replace);
if (!replace) return;
const recoverInsert = tryRecover(getOtherRange, textEdit.insert, textEdit.newText, document);
const recoverReplace = recoverInsert ? tryRecover(getOtherRange, textEdit.replace, textEdit.newText, document) : undefined;
if (recoverInsert && recoverReplace && recoverInsert.newText === recoverReplace.newText) {
return {
...textEdit,
insert: recoverInsert.range,
replace: recoverReplace.range,
newText: recoverInsert.newText,
};
}
}
}

return {
...textEdit,
insert,
replace,
};
/**
* update edit text from ". foo" to " foo"
* fix https://github.com/johnsoncodehk/volar/issues/2155
*/
function tryRecover(
getOtherRange: (range: vscode.Range) => vscode.Range | undefined,
replaceRange: vscode.Range,
newText: string,
document: vscode.TextDocument,
): vscode.TextEdit | undefined {
if (replaceRange.start.line === replaceRange.end.line && replaceRange.end.character > replaceRange.start.character) {

let character = replaceRange.start.character;

while (newText.length && replaceRange.end.character > character) {
const newStart = { line: replaceRange.start.line, character: replaceRange.start.character + 1 };
if (document.getText({ start: replaceRange.start, end: newStart }) === newText[0]) {
newText = newText.slice(1);
character++;
const otherRange = getOtherRange({ start: newStart, end: replaceRange.end });
if (otherRange) {
return {
newText,
range: otherRange,
};
}
}
else {
break;
}
}
}
}
2 changes: 1 addition & 1 deletion plugins/typescript/src/services/completions/basic.ts
Expand Up @@ -103,7 +103,7 @@ export function register(
item.insertTextFormat = isSnippet ? vscode.InsertTextFormat.Snippet : vscode.InsertTextFormat.PlainText;
item.filterText = getFilterText(tsEntry, wordRange, line, tsEntry.insertText);

if (completionContext!.isMemberCompletion && dotAccessorContext && !isSnippet) {
if (completionContext?.isMemberCompletion && dotAccessorContext && !isSnippet) {
item.filterText = dotAccessorContext.text + (item.insertText || item.label);
if (!range) {
const replacementRange = wordRange;
Expand Down

0 comments on commit 710a6a3

Please sign in to comment.