mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
81 lines
3.0 KiB
TypeScript
81 lines
3.0 KiB
TypeScript
import type { Monaco, monacoTypes } from '@grafana/ui';
|
|
|
|
import { getIntent } from './intent';
|
|
import { getCompletions, DataProvider, CompletionType } from './completions';
|
|
import { NeverCaseError } from './util';
|
|
|
|
function getMonacoCompletionItemKind(type: CompletionType, monaco: Monaco): monacoTypes.languages.CompletionItemKind {
|
|
switch (type) {
|
|
case 'DURATION':
|
|
return monaco.languages.CompletionItemKind.Unit;
|
|
case 'FUNCTION':
|
|
return monaco.languages.CompletionItemKind.Variable;
|
|
case 'HISTORY':
|
|
return monaco.languages.CompletionItemKind.Snippet;
|
|
case 'LABEL_NAME':
|
|
return monaco.languages.CompletionItemKind.Enum;
|
|
case 'LABEL_VALUE':
|
|
return monaco.languages.CompletionItemKind.EnumMember;
|
|
case 'METRIC_NAME':
|
|
return monaco.languages.CompletionItemKind.Constructor;
|
|
default:
|
|
throw new NeverCaseError(type);
|
|
}
|
|
}
|
|
export function getCompletionProvider(
|
|
monaco: Monaco,
|
|
dataProvider: DataProvider
|
|
): monacoTypes.languages.CompletionItemProvider {
|
|
const provideCompletionItems = (
|
|
model: monacoTypes.editor.ITextModel,
|
|
position: monacoTypes.Position
|
|
): monacoTypes.languages.ProviderResult<monacoTypes.languages.CompletionList> => {
|
|
const word = model.getWordAtPosition(position);
|
|
const range =
|
|
word != null
|
|
? monaco.Range.lift({
|
|
startLineNumber: position.lineNumber,
|
|
endLineNumber: position.lineNumber,
|
|
startColumn: word.startColumn,
|
|
endColumn: word.endColumn,
|
|
})
|
|
: monaco.Range.fromPositions(position);
|
|
// documentation says `position` will be "adjusted" in `getOffsetAt`
|
|
// i don't know what that means, to be sure i clone it
|
|
const positionClone = {
|
|
column: position.column,
|
|
lineNumber: position.lineNumber,
|
|
};
|
|
const offset = model.getOffsetAt(positionClone);
|
|
const intent = getIntent(model.getValue(), offset);
|
|
const completionsPromise = intent != null ? getCompletions(intent, dataProvider) : Promise.resolve([]);
|
|
return completionsPromise.then((items) => {
|
|
// monaco by-default alphabetically orders the items.
|
|
// to stop it, we use a number-as-string sortkey,
|
|
// so that monaco keeps the order we use
|
|
const maxIndexDigits = items.length.toString().length;
|
|
const suggestions: monacoTypes.languages.CompletionItem[] = items.map((item, index) => ({
|
|
kind: getMonacoCompletionItemKind(item.type, monaco),
|
|
label: item.label,
|
|
insertText: item.insertText,
|
|
detail: item.detail,
|
|
documentation: item.documentation,
|
|
sortText: index.toString().padStart(maxIndexDigits, '0'), // to force the order we have
|
|
range,
|
|
command: item.triggerOnInsert
|
|
? {
|
|
id: 'editor.action.triggerSuggest',
|
|
title: '',
|
|
}
|
|
: undefined,
|
|
}));
|
|
return { suggestions };
|
|
});
|
|
};
|
|
|
|
return {
|
|
triggerCharacters: ['{', ',', '[', '(', '=', '~'],
|
|
provideCompletionItems,
|
|
};
|
|
}
|