Implement code actions

This allows the user to remove unused anchors using quick actions.
This commit is contained in:
Remco Haszing 2022-03-07 17:57:05 +01:00
parent 4ab8e671e6
commit 5d84ccbcda
No known key found for this signature in database
GPG key ID: 40D9F5FE9155FD3C
4 changed files with 493 additions and 450 deletions

857
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
import {
editor,
IDisposable,
IRange,
languages,
MarkerSeverity,
MarkerTag,
@ -152,6 +153,22 @@ function toRange(range: ls.Range): Range {
);
}
function fromRange(range: IRange): ls.Range {
return {
start: { line: range.startLineNumber - 1, character: range.startColumn - 1 },
end: { line: range.endLineNumber - 1, character: range.endColumn - 1 },
};
}
function fromMarkerData(marker: editor.IMarkerData): ls.Diagnostic {
return {
message: marker.message,
range: fromRange(marker),
code: typeof marker.code === 'object' ? marker.code.value : marker.code,
source: marker.source,
};
}
function toCompletionItemKind(kind: ls.CompletionItemKind): languages.CompletionItemKind {
const mItemKind = languages.CompletionItemKind;
@ -429,3 +446,55 @@ export function createLinkProvider(getWorker: WorkerAccessor): languages.LinkPro
},
};
}
function toWorkspaceEdit(edit: ls.WorkspaceEdit): languages.WorkspaceEdit {
const edits: languages.WorkspaceTextEdit[] = [];
for (const [uri, textEdits] of Object.entries(edit.changes)) {
for (const textEdit of textEdits) {
edits.push({
resource: Uri.parse(uri),
edit: {
text: textEdit.newText,
range: toRange(textEdit.range),
},
});
}
}
return {
edits,
};
}
function toCodeAction(codeAction: ls.CodeAction): languages.CodeAction {
return {
title: codeAction.title,
diagnostics: codeAction.diagnostics.map(toDiagnostics),
disabled: codeAction.disabled?.reason,
edit: toWorkspaceEdit(codeAction.edit),
kind: codeAction.kind,
isPreferred: codeAction.isPreferred,
};
}
export function createCodeActionProvider(getWorker: WorkerAccessor): languages.CodeActionProvider {
return {
async provideCodeActions(model, range, context) {
const resource = model.uri;
const worker = await getWorker(resource);
const codeActions = await worker.getCodeAction(
String(resource),
fromRange(range),
context.markers.map(fromMarkerData),
);
return {
actions: codeActions.map(toCodeAction),
dispose() {
// This is required by the TypeScript interface, but its not implemented.
},
};
},
};
}

View file

@ -2,6 +2,7 @@ import { languages } from 'monaco-editor/esm/vs/editor/editor.api.js';
import { languageId } from './constants';
import {
createCodeActionProvider,
createCompletionItemProvider,
createDefinitionProvider,
createDiagnosticsAdapter,
@ -56,6 +57,7 @@ export function setupMode(defaults: languages.yaml.LanguageServiceDefaults): voi
createDocumentFormattingEditProvider(worker),
);
languages.registerLinkProvider(languageId, createLinkProvider(worker));
languages.registerCodeActionProvider(languageId, createCodeActionProvider(worker));
createDiagnosticsAdapter(worker, defaults);
languages.setLanguageConfiguration(languageId, richEditConfiguration);
}

View file

@ -34,6 +34,12 @@ export interface YAMLWorker {
findDocumentSymbols: (uri: string) => Promisable<ls.DocumentSymbol[]>;
findLinks: (uri: string) => Promisable<ls.DocumentLink[]>;
getCodeAction: (
uri: string,
range: ls.Range,
diagnostics: ls.Diagnostic[],
) => Promisable<ls.CodeAction[]>;
}
export function createYAMLWorker(
@ -101,6 +107,15 @@ export function createYAMLWorker(
const document = getTextDocument(uri);
return languageService.findLinks(document);
},
getCodeAction(uri, range, diagnostics) {
const document = getTextDocument(uri);
return languageService.getCodeAction(document, {
range,
textDocument: { uri },
context: { diagnostics },
});
},
};
}