Skip to content

Commit

Permalink
feat(language-service): auto insert feature does not abstract selecti…
Browse files Browse the repository at this point in the history
…on (#156)
  • Loading branch information
johnsoncodehk authored Apr 2, 2024
1 parent 9f3432f commit 8afff8e
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export function registerLanguageFeatures(
});
connection.onRequest(AutoInsertRequest.type, async (params, token) => {
return worker(params.textDocument.uri, token, service => {
return service.doAutoInsert(params.textDocument.uri, params.position, params.lastChange, token);
return service.doAutoInsert(params.textDocument.uri, params.selection, params.change, token);
});
});

Expand Down
11 changes: 7 additions & 4 deletions packages/language-server/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,16 @@ export namespace GetMatchTsConfigRequest {
}

export namespace AutoInsertRequest {
export type ParamsType = vscode.TextDocumentPositionParams & {
lastChange: {
range: vscode.Range;
export type ParamsType = {
textDocument: vscode.TextDocumentIdentifier;
selection: vscode.Position;
change: {
rangeOffset: number;
rangeLength: number;
text: string;
};
};
export type ResponseType = string | vscode.TextEdit | null | undefined;
export type ResponseType = string | null | undefined;
export type ErrorType = never;
export const type = new vscode.RequestType<ParamsType, ResponseType, ErrorType>('volar/client/autoInsert');
}
Expand Down
21 changes: 11 additions & 10 deletions packages/language-service/lib/features/provideAutoInsertionEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@ import { isAutoInsertEnabled } from '@volar/language-core';

export function register(context: ServiceContext) {

return (uri: string, position: vscode.Position, lastChange: { range: vscode.Range; text: string; }, token = NoneCancellationToken) => {
return (uri: string, selection: vscode.Position, change: { rangeOffset: number; rangeLength: number; text: string; }, token = NoneCancellationToken) => {

return languageFeatureWorker(
context,
uri,
() => ({ position, lastChange }),
() => ({ selection, change }),
function* (map) {
for (const mappedPosition of map.getGeneratedPositions(position, isAutoInsertEnabled)) {
const range = map.getGeneratedRange(lastChange.range);
if (range) {
for (const mappedPosition of map.getGeneratedPositions(selection, isAutoInsertEnabled)) {
const mapped = map.map.getGeneratedOffset(change.rangeOffset);
if (mapped) {
yield {
position: mappedPosition,
lastChange: {
text: lastChange.text,
range,
selection: mappedPosition,
change: {
text: change.text,
rangeOffset: mapped[0],
rangeLength: change.rangeLength,
},
};
}
Expand All @@ -30,7 +31,7 @@ export function register(context: ServiceContext) {
if (token.isCancellationRequested) {
return;
}
return service[1].provideAutoInsertionEdit?.(document, args.position, args.lastChange, token);
return service[1].provideAutoInsertionEdit?.(document, args.selection, args.change, token);
},
(item, map) => {
if (!map || typeof item === 'string') {
Expand Down
2 changes: 1 addition & 1 deletion packages/language-service/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export interface LanguageServicePluginInstance<P = any> {
provideSemanticDiagnostics?(document: TextDocument, token: vscode.CancellationToken): NullableProviderResult<vscode.Diagnostic[]>;
provideFileReferences?(document: TextDocument, token: vscode.CancellationToken): NullableProviderResult<vscode.Location[]>; // volar specific
provideReferencesCodeLensRanges?(document: TextDocument, token: vscode.CancellationToken): NullableProviderResult<vscode.Range[]>; // volar specific
provideAutoInsertionEdit?(document: TextDocument, position: vscode.Position, lastChange: { range: vscode.Range; text: string; }, token: vscode.CancellationToken): NullableProviderResult<string | vscode.TextEdit>; // volar specific
provideAutoInsertionEdit?(document: TextDocument, position: vscode.Position, lastChange: { rangeOffset: number; rangeLength: number; text: string; }, token: vscode.CancellationToken): NullableProviderResult<string | vscode.TextEdit>; // volar specific
provideFileRenameEdits?(oldUri: string, newUri: string, token: vscode.CancellationToken): NullableProviderResult<vscode.WorkspaceEdit>; // volar specific
provideDocumentDropEdits?(document: TextDocument, position: vscode.Position, dataTransfer: Map<string, DataTransferItem>, token: vscode.CancellationToken): NullableProviderResult<DocumentDropEdit>; // volar specific
resolveCodeLens?(codeLens: vscode.CodeLens, token: vscode.CancellationToken): ProviderResult<vscode.CodeLens>;
Expand Down
5 changes: 3 additions & 2 deletions packages/monaco/lib/editor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { LanguageService } from '@volar/language-service';
import type { editor, IDisposable, MonacoEditor, Uri } from 'monaco-types';
import { fromPosition, fromRange, toMarkerData, toTextEdit } from 'monaco-languageserver-types';
import { fromPosition, toMarkerData, toTextEdit } from 'monaco-languageserver-types';
import { markers } from './markers.js';

interface IInternalEditorModel extends editor.IModel {
Expand Down Expand Up @@ -189,8 +189,9 @@ export function activateAutoInsertion(
column: lastChange.range.startColumn + lastChange.text.length,
}),
{
range: fromRange(lastChange.range),
text: lastChange.text,
rangeOffset: lastChange.rangeOffset,
rangeLength: lastChange.rangeLength,
},
);
if (model.getVersionId() !== version) {
Expand Down
62 changes: 26 additions & 36 deletions packages/vscode/lib/features/autoInsertion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ export function activate(selector: vscode.DocumentSelector, client: BaseLanguage
if (document !== activeDocument) {
return;
}
if (timeout) {
clearTimeout(timeout);
}

const lastChange = contentChanges[contentChanges.length - 1];
doAutoInsert(document, lastChange);
}
Expand All @@ -51,47 +47,41 @@ export function activate(selector: vscode.DocumentSelector, client: BaseLanguage
timeout = undefined;
}
const version = document.version;
const isCancel = () => document !== vscode.window.activeTextEditor?.document
|| vscode.window.activeTextEditor?.document.version !== version;

timeout = setTimeout(async () => {
timeout = undefined;

const isCancel = () => document !== vscode.window.activeTextEditor?.document
|| vscode.window.activeTextEditor?.document.version !== version;
if (isCancel()) {
return;
}

const rangeStart = lastChange.range.start;
const position = new vscode.Position(rangeStart.line, rangeStart.character + lastChange.text.length);
const params = {
...client.code2ProtocolConverter.asTextDocumentPositionParams(document, position),
lastChange: {
const activeEditor = vscode.window.activeTextEditor;
if (!activeEditor) {
return;
}
const newTextRange = new vscode.Range(
lastChange.range.start,
document.positionAt(
document.offsetAt(lastChange.range.start)
+ lastChange.text.length
)
);
const selection = activeEditor.selections.find(selection => newTextRange.contains(selection.active))?.active;
if (!selection) {
return;
}
const params: AutoInsertRequest.ParamsType = {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
selection: client.code2ProtocolConverter.asPosition(selection),
change: {
rangeLength: lastChange.rangeLength,
rangeOffset: lastChange.rangeOffset,
text: lastChange.text,
range: client.code2ProtocolConverter.asRange(lastChange.range),
},
};
const insertion = await client.sendRequest(AutoInsertRequest.type, params);
const activeEditor = vscode.window.activeTextEditor;

if (
insertion !== undefined
&& insertion !== null
&& isEnabled
&& !isCancel()
&& activeEditor
) {
if (typeof insertion === 'string') {
const selections = activeEditor.selections;
if (selections.length && selections.some(s => s.active.isEqual(position))) {
activeEditor.insertSnippet(new vscode.SnippetString(insertion), selections.map(s => s.active));
}
else {
activeEditor.insertSnippet(new vscode.SnippetString(insertion), position);
}
}
else {
const edit = client.protocol2CodeConverter.asTextEdit(insertion);
activeEditor.insertSnippet(new vscode.SnippetString(edit.newText), edit.range);
}
if (insertion && isEnabled && !isCancel()) {
activeEditor.insertSnippet(new vscode.SnippetString(insertion));
}
}, 100);
}
Expand Down

0 comments on commit 8afff8e

Please sign in to comment.