From 2a4a19388f30220fd81586bd70b7e3aa8a1495e5 Mon Sep 17 00:00:00 2001 From: Michael Huynh Date: Sat, 27 Oct 2018 16:54:12 +0800 Subject: [PATCH] Fix label suggestions for multi-line aggregation queries No label suggestions were being returned for multi-line aggregation contexts because the parsed selector string does not see the full context before a `by` or `without` clause. This solution stitches together all text nodes that comprise the query editor to ensure the selector has sufficient context to generate suggestions. Also, an additional workaround has been included to ensure range vector syntax does not disrupt label suggestions in aggregation contexts. Related: #12890 --- .../prometheus/language_provider.ts | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/language_provider.ts b/public/app/plugins/datasource/prometheus/language_provider.ts index 3e406a71264..3dd15eb713e 100644 --- a/public/app/plugins/datasource/prometheus/language_provider.ts +++ b/public/app/plugins/datasource/prometheus/language_provider.ts @@ -162,16 +162,29 @@ export default class PromQlLanguageProvider extends LanguageProvider { let refresher: Promise = null; const suggestions: CompletionItemGroup[] = []; - // sum(foo{bar="1"}) by (|) - const line = value.anchorBlock.getText(); - const cursorOffset: number = value.anchorOffset; - // sum(foo{bar="1"}) by ( - const leftSide = line.slice(0, cursorOffset); + // Stitch all query lines together to support multi-line queries + let queryOffset; + const queryText = value.document.getBlocks().reduce((text, block) => { + const blockText = block.getText(); + if (value.anchorBlock.key === block.key) { + // Newline characters are not accounted for but this is irrelevant + // for the purpose of extracting the selector string + queryOffset = value.anchorOffset + text.length; + } + text += blockText; + return text; + }, ''); + + const leftSide = queryText.slice(0, queryOffset); const openParensAggregationIndex = leftSide.lastIndexOf('('); const openParensSelectorIndex = leftSide.slice(0, openParensAggregationIndex).lastIndexOf('('); const closeParensSelectorIndex = leftSide.slice(openParensSelectorIndex).indexOf(')') + openParensSelectorIndex; - // foo{bar="1"} - const selectorString = leftSide.slice(openParensSelectorIndex + 1, closeParensSelectorIndex); + + let selectorString = leftSide.slice(openParensSelectorIndex + 1, closeParensSelectorIndex); + + // Range vector syntax not accounted for by subsequent parse so discard it if present + selectorString = selectorString.replace(/\[[^\]]+\]$/, ''); + const selector = parseSelector(selectorString, selectorString.length - 2).selector; const labelKeys = this.labelKeys[selector];