diff --git a/packages/grafana-ui/src/components/Monaco/suggestions.test.ts b/packages/grafana-ui/src/components/Monaco/suggestions.test.ts new file mode 100644 index 00000000000..61be3eb69d5 --- /dev/null +++ b/packages/grafana-ui/src/components/Monaco/suggestions.test.ts @@ -0,0 +1,38 @@ +import { findInsertIndex } from './suggestions'; + +describe('Check suggestion index', () => { + it('find last $ sign', () => { + const line = ' hello $123'; + const { index, prefix } = findInsertIndex(line); + expect(index).toEqual(line.indexOf('$')); + expect(prefix).toEqual('$123'); + }); + + it('insert into empty line', () => { + const line = ''; + const { index, prefix } = findInsertIndex(line); + expect(index).toEqual(0); + expect(prefix).toEqual(''); + }); + + it('insert new word', () => { + const line = 'this is a new '; + const { index, prefix } = findInsertIndex(line); + expect(index).toEqual(line.length); + expect(prefix).toEqual(''); + }); + + it('complte a simple word', () => { + const line = 'SELECT * FROM tab'; + const { index, prefix } = findInsertIndex(line); + expect(index).toEqual(line.lastIndexOf(' ') + 1); + expect(prefix).toEqual('tab'); + }); + + it('complete a quoted word', () => { + const line = 'SELECT "hello", "wo'; + const { index, prefix } = findInsertIndex(line); + expect(index).toEqual(line.lastIndexOf('"') + 1); + expect(prefix).toEqual('wo'); + }); +}); diff --git a/packages/grafana-ui/src/components/Monaco/suggestions.ts b/packages/grafana-ui/src/components/Monaco/suggestions.ts index 1070789943b..dc79f467557 100644 --- a/packages/grafana-ui/src/components/Monaco/suggestions.ts +++ b/packages/grafana-ui/src/components/Monaco/suggestions.ts @@ -2,6 +2,33 @@ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; import { CodeEditorSuggestionItem, CodeEditorSuggestionItemKind, CodeEditorSuggestionProvider } from './types'; +/** + * @internal -- only exported for tests + */ +export function findInsertIndex(line: string): { index: number; prefix: string } { + for (let i = line.length - 1; i > 0; i--) { + const ch = line.charAt(i); + if (ch === '$') { + return { + index: i, + prefix: line.substring(i), + }; + } + + // Keep these seperators + if (ch === ' ' || ch === '\t' || ch === '"' || ch === "'") { + return { + index: i + 1, + prefix: line.substring(i + 1), + }; + } + } + return { + index: 0, + prefix: line, + }; +} + function getCompletionItems( prefix: string, suggestions: CodeEditorSuggestionItem[], @@ -53,51 +80,39 @@ export function registerSuggestions( triggerCharacters: ['$'], provideCompletionItems: (model, position, context) => { + const range = { + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + startColumn: position.column, + endColumn: position.column, + }; + + // Simple check if this was triggered by pressing `$` if (context.triggerCharacter === '$') { - const range = { - startLineNumber: position.lineNumber, - endLineNumber: position.lineNumber, - startColumn: position.column - 1, - endColumn: position.column, - }; + range.startColumn = position.column - 1; return { suggestions: getCompletionItems('$', getSuggestions(), range), }; } - // find out if we are completing a property in the 'dependencies' object. - const lineText = model.getValueInRange({ + // Find the replacement region + const currentLine = model.getValueInRange({ startLineNumber: position.lineNumber, startColumn: 1, endLineNumber: position.lineNumber, endColumn: position.column, }); - const idx = lineText.lastIndexOf('$'); - if (idx >= 0) { - const range = { - startLineNumber: position.lineNumber, - endLineNumber: position.lineNumber, - startColumn: idx, // the last $ we found - endColumn: position.column, - }; - return { - suggestions: getCompletionItems(lineText.substr(idx), getSuggestions(), range), - }; + const { index, prefix } = findInsertIndex(currentLine); + range.startColumn = index + 1; + + const suggestions = getCompletionItems(prefix, getSuggestions(), range); + if (suggestions.length) { + // NOTE, this will replace any language provided suggestions + return { suggestions }; } - // Empty line that asked for suggestion - if (lineText.trim().length < 1) { - return { - suggestions: getCompletionItems('', getSuggestions(), { - startLineNumber: position.lineNumber, - endLineNumber: position.lineNumber, - startColumn: position.column, - endColumn: position.column, - }), - }; - } - // console.log('complete?', lineText, context); + // Default language suggestions return undefined; }, });