diff --git a/web/ui/module/codemirror-promql/src/complete/hybrid.test.ts b/web/ui/module/codemirror-promql/src/complete/hybrid.test.ts index 8250319681..5906a692de 100644 --- a/web/ui/module/codemirror-promql/src/complete/hybrid.test.ts +++ b/web/ui/module/codemirror-promql/src/complete/hybrid.test.ts @@ -922,6 +922,30 @@ describe('computeEndCompletePosition test', () => { pos: 12, // cursor after '{' expectedEnd: 12, }, + { + title: 'cursor in middle of label name in grouping clause - should extend to end', + expr: 'sum by (instance_name)', + pos: 12, // cursor after 'inst' (before 'ance') + expectedEnd: 21, // should extend to end of 'instance_name' + }, + { + title: 'cursor in middle of label name in label matcher - should extend to end', + expr: 'metric{instance_name="value"}', + pos: 11, // cursor after 'inst' (before 'ance') + expectedEnd: 20, // should extend to end of 'instance_name' + }, + { + title: 'cursor in middle of label name in on() modifier - should extend to end', + expr: 'a / on(instance_name) b', + pos: 11, // cursor after 'inst' (before 'ance') + expectedEnd: 20, // should extend to end of 'instance_name' + }, + { + title: 'cursor in middle of label name in ignoring() modifier - should extend to end', + expr: 'a / ignoring(instance_name) b', + pos: 17, // cursor after 'inst' (before 'ance') + expectedEnd: 26, // should extend to end of 'instance_name' + }, ]; testCases.forEach((value) => { it(value.title, () => { diff --git a/web/ui/module/codemirror-promql/src/complete/hybrid.ts b/web/ui/module/codemirror-promql/src/complete/hybrid.ts index d89907699a..23e47ce649 100644 --- a/web/ui/module/codemirror-promql/src/complete/hybrid.ts +++ b/web/ui/module/codemirror-promql/src/complete/hybrid.ts @@ -167,13 +167,14 @@ function arrayToCompletionResult(data: Completion[], from: number, to: number, i } // computeEndCompletePosition calculates the end position for autocompletion replacement. -// When the cursor is in the middle of an identifier (e.g., metric name), this ensures the entire -// identifier is replaced, not just the portion before the cursor. This fixes issue #15839. +// When the cursor is in the middle of an identifier (e.g., metric name) or label name, this ensures +// the entire token is replaced, not just the portion before the cursor. This fixes issue #15839. // Note: this method is exported only for testing purpose. export function computeEndCompletePosition(state: EditorState, node: SyntaxNode, pos: number): number { - // For Identifier nodes (metric names), extend the end position to include - // the entire identifier, even if the cursor is in the middle. - if (node.type.id === Identifier) { + // For Identifier nodes (metric names) and LabelName nodes (label names in matchers, + // grouping clauses, etc.), extend the end position to include the entire token, + // even if the cursor is in the middle. + if (node.type.id === Identifier || node.type.id === LabelName) { return node.to; } // Default: use the cursor position as the end position