CompletionItemProvider.ts 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import type { Monaco, monacoTypes } from '@grafana/ui';
  2. import { linkedTokenBuilder } from '../monarch/linkedTokenBuilder';
  3. import { LanguageDefinition } from '../monarch/register';
  4. import { Completeable, CompletionItemPriority, TokenTypes } from '../monarch/types';
  5. import { DYNAMIC_LABEL_PATTERNS } from './language';
  6. type CompletionItem = monacoTypes.languages.CompletionItem;
  7. export class DynamicLabelsCompletionItemProvider implements Completeable {
  8. tokenTypes: TokenTypes;
  9. constructor() {
  10. this.tokenTypes = {
  11. Parenthesis: 'delimiter.parenthesis.cloudwatch-dynamicLabels',
  12. Whitespace: 'white.cloudwatch-dynamicLabels',
  13. Keyword: 'keyword.cloudwatch-dynamicLabels',
  14. Delimiter: 'delimiter.cloudwatch-dynamicLabels',
  15. Operator: 'operator.cloudwatch-dynamicLabels',
  16. Identifier: 'identifier.cloudwatch-dynamicLabels',
  17. Type: 'type.cloudwatch-dynamicLabels',
  18. Function: 'predefined.cloudwatch-dynamicLabels',
  19. Number: 'number.cloudwatch-dynamicLabels',
  20. String: 'string.cloudwatch-dynamicLabels',
  21. Variable: 'variable.cloudwatch-dynamicLabels',
  22. };
  23. }
  24. // called by registerLanguage and passed to monaco with registerCompletionItemProvider
  25. // returns an object that implements https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.CompletionItemProvider.html
  26. getCompletionProvider(monaco: Monaco, languageDefinition: LanguageDefinition) {
  27. return {
  28. triggerCharacters: [' ', '$', ',', '(', "'"], // one of these characters indicates that it is time to look for a suggestion
  29. provideCompletionItems: async (model: monacoTypes.editor.ITextModel, position: monacoTypes.IPosition) => {
  30. const currentToken = linkedTokenBuilder(monaco, languageDefinition, model, position, this.tokenTypes);
  31. const invalidRangeToken = currentToken?.isWhiteSpace() || currentToken?.isParenthesis();
  32. const range =
  33. invalidRangeToken || !currentToken?.range ? monaco.Range.fromPositions(position) : currentToken?.range;
  34. const toCompletionItem = (value: string, rest: Partial<CompletionItem> = {}) => {
  35. const item: CompletionItem = {
  36. label: value,
  37. insertText: value,
  38. kind: monaco.languages.CompletionItemKind.Field,
  39. range,
  40. sortText: CompletionItemPriority.Medium,
  41. ...rest,
  42. };
  43. return item;
  44. };
  45. let suggestions: CompletionItem[] = [];
  46. const next = currentToken?.next;
  47. if (!currentToken?.isFunction() && (!next || next.isWhiteSpace())) {
  48. suggestions = DYNAMIC_LABEL_PATTERNS.map((val) => toCompletionItem(val));
  49. // always insert suggestion for dimension value and allow user to complete pattern by providing the dimension name
  50. suggestions.push(
  51. toCompletionItem("${PROP('Dim.')}", {
  52. sortText: CompletionItemPriority.High,
  53. insertText: `\${PROP('Dim.$0')} `,
  54. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  55. })
  56. );
  57. }
  58. return {
  59. suggestions,
  60. };
  61. },
  62. };
  63. }
  64. }