Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Commit

Permalink
Merge pull request #32 from prometheus-community/feature/bump
Browse files Browse the repository at this point in the history
Bump lezer-promql and autocomplete module
  • Loading branch information
juliusv authored Aug 18, 2020
2 parents ee2b36c + 348de0d commit 562ae73
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 64 deletions.
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
},
"homepage": "https://github.com/prometheus-community/codemirror-promql/blob/master/README.md",
"dependencies": {
"@nexucis/codemirror-next-autocomplete": "^0.1.8",
"@nexucis/codemirror-next-autocomplete": "^0.1.9",
"axios": "^0.19.2",
"lezer-promql": "0.6.0",
"lezer-promql": "0.7.0",
"vscode-languageserver-types": "^3.15.1"
},
"devDependencies": {
Expand Down
110 changes: 61 additions & 49 deletions src/lang-promql/complete/hybrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,46 +24,38 @@ import { AutocompleteContext, Completion, CompletionResult, snippet, SnippetSpec
import { CompleteStrategy } from './index';
import { Subtree } from 'lezer-tree';
import { EditorState } from '@codemirror/next/basic-setup';
import { promQLSyntax } from 'lezer-promql';
import { PrometheusClient } from '../client';
import {
AggregateOp,
aggregateOpTerms,
BinaryExpr,
binOpTerms,
FunctionIdentifier,
functionIdentifierTerms,
GroupingLabel,
GroupingLabels,
Identifier,
LabelMatcher,
LabelMatchers,
LabelName,
matchOpTerms,
MetricIdentifier,
StringLiteral,
VectorSelector,
} from 'lezer-promql';

const matchOp = 9999;

interface AutoCompleteNode {
labels: string[];
type: string;
}

const MatchOp = 'MatchOp',
BinOp = 'BinOp',
BinaryExpr = 'BinaryExpr',
FunctionIdentifier = 'FunctionIdentifier',
AggregateOp = 'AggregateOp',
MetricIdentifier = 'MetricIdentifier',
Identifier = 'Identifier',
GroupingLabels = 'GroupingLabels',
GroupingLabel = 'GroupingLabel',
LabelMatchers = 'LabelMatchers',
LabelMatcher = 'LabelMatcher',
LabelName = 'LabelName',
VectorSelector = 'VectorSelector',
StringLiteral = 'StringLiteral';

const autocompleteNode = {
MatchOp: {
labels: promQLSyntax[MatchOp],
type: '',
},
BinaryExpr: {
labels: promQLSyntax[BinOp],
type: '',
},
FunctionIdentifier: {
labels: promQLSyntax[FunctionIdentifier],
type: 'function',
},
AggregateOp: {
labels: promQLSyntax[AggregateOp],
type: 'keyword',
},
const autocompleteNode: { [key: number]: AutoCompleteNode } = {
[matchOp]: { labels: matchOpTerms, type: '' },
[BinaryExpr]: { labels: binOpTerms, type: '' },
[FunctionIdentifier]: { labels: functionIdentifierTerms, type: 'function' },
[AggregateOp]: { labels: aggregateOpTerms, type: 'keyword' },
};

const snippets: readonly SnippetSpec[] = [
Expand Down Expand Up @@ -100,7 +92,7 @@ export class HybridComplete implements CompleteStrategy {
promQL(context: AutocompleteContext): Promise<CompletionResult> | CompletionResult | null {
const { state, pos } = context;
const tree = state.tree.resolve(pos, -1);
if (tree.parent?.name === MetricIdentifier && tree.name === Identifier) {
if (tree.parent?.type.id === MetricIdentifier && tree.type.id === Identifier) {
// Here we cannot know if we have to autocomplete the metric_name, or the function or the aggregation.
// So we will just autocomplete everything
if (this.prometheusClient) {
Expand All @@ -125,33 +117,33 @@ export class HybridComplete implements CompleteStrategy {
true
);
}
if (tree.name === GroupingLabels || (tree.parent?.name === GroupingLabel && tree.name === LabelName)) {
if (tree.type.id === GroupingLabels || (tree.parent?.type.id === GroupingLabel && tree.type.id === LabelName)) {
// In this case we are in the given situation:
// sum by ()
// So we have to autocomplete any labelName
return this.labelNames(tree, pos, context, state);
}
if (tree.name === LabelMatchers || (tree.parent?.name === LabelMatcher && tree.name === LabelName)) {
if (tree.type.id === LabelMatchers || (tree.parent?.type.id === LabelMatcher && tree.type.id === LabelName)) {
// In that case we are in the given situation:
// metric_name{} or {}
return this.autocompleteLabelNamesByMetric(tree, pos, context, state);
}
if (tree.parent?.name === LabelMatcher && tree.name === StringLiteral) {
if (tree.parent?.type.id === LabelMatcher && tree.type.id === StringLiteral) {
// In this case we are in the given situation:
// metric_name{labelName=""}
// So we can autocomplete the labelValue
return this.autocompleteLabelValue(tree.parent, tree, pos, context, state);
}
if (tree.name === MatchOp) {
return this.arrayToCompletionResult([autocompleteNode[MatchOp]], tree.start, pos, context, state);
if (tree.name === 'MatchOp') {
return this.arrayToCompletionResult([autocompleteNode[matchOp]], tree.start, pos, context, state);
}
if (tree.parent?.name === BinaryExpr) {
if (tree.parent?.type.id === BinaryExpr) {
return this.arrayToCompletionResult([autocompleteNode[BinaryExpr]], tree.start, pos, context, state);
}
if (tree.parent?.name === FunctionIdentifier) {
if (tree.parent?.type.id === FunctionIdentifier) {
return this.arrayToCompletionResult([autocompleteNode[FunctionIdentifier]], tree.start, pos, context, state);
}
if (tree.parent?.name === AggregateOp) {
if (tree.parent?.type.id === AggregateOp) {
return this.arrayToCompletionResult([autocompleteNode[AggregateOp]], tree.start, pos, context, state);
}
return null;
Expand All @@ -170,14 +162,25 @@ export class HybridComplete implements CompleteStrategy {
// First get the labelName.
// By definition it's the firstChild: https://github.com/promlabs/lezer-promql/blob/0ef65e196a8db6a989ff3877d57fd0447d70e971/src/promql.grammar#L250
let labelName = '';
if (this.prometheusClient && parent.firstChild && parent.firstChild.name === LabelName) {
if (this.prometheusClient && parent.firstChild && parent.firstChild.type.id === LabelName) {
labelName = state.sliceDoc(parent.firstChild.start, parent.firstChild.end);
}
// then find the metricName if it exists
const metricName = this.getMetricNameInVectorSelector(current, state);
return this.prometheusClient.labelValues(labelName, metricName).then((labelValues: string[]) => {
// +1 to avoid to remove the first quote.
return this.arrayToCompletionResult([{ labels: labelValues, type: 'text' }], current.start + 1, pos, context, state);
return this.arrayToCompletionResult(
[
{
labels: labelValues,
type: 'text',
},
],
current.start + 1,
pos,
context,
state
);
});
}

Expand All @@ -194,23 +197,23 @@ export class HybridComplete implements CompleteStrategy {
// Find if there is a defined metric name. Should be used to autocomplete a labelValue or a labelName
// First find the parent "VectorSelector" to be able to find then the subChild "MetricIdentifier" if it exists.
let currentNode: Subtree | null = tree;
while (currentNode && currentNode.name !== VectorSelector) {
while (currentNode && currentNode.type.id !== VectorSelector) {
currentNode = currentNode.parent;
}
if (!currentNode) {
// Weird case that shouldn't happen, because "VectorSelector" is by definition the parent of the LabelMatchers.
return '';
}
// By definition "MetricIdentifier" is necessary the first child if it exists
if (!currentNode.firstChild || currentNode.firstChild.name !== MetricIdentifier) {
if (!currentNode.firstChild || currentNode.firstChild.type.id !== MetricIdentifier) {
// If it doesn't exist then we are in the given situation
// {}
return '';
}
// Let's move forward to the next child.
currentNode = currentNode.firstChild;
// By definition the next child should be an "Identifier" which contains the metricName
if (!currentNode.firstChild || currentNode.firstChild.name !== Identifier) {
if (!currentNode.firstChild || currentNode.firstChild.type.id !== Identifier) {
return '';
}
currentNode = currentNode.firstChild;
Expand All @@ -235,7 +238,7 @@ export class HybridComplete implements CompleteStrategy {
type: 'constant',
},
],
tree.name === GroupingLabels || tree.name === LabelMatchers ? tree.start + 1 : tree.start,
tree.type.id === GroupingLabels || tree.type.id === LabelMatchers ? tree.start + 1 : tree.start,
pos,
context,
state
Expand All @@ -256,7 +259,16 @@ export class HybridComplete implements CompleteStrategy {

for (const completionList of data) {
for (const label of completionList.labels) {
const completionResult = context.filter({ label: label, original: label, apply: label, type: completionList.type, score: 0 }, text);
const completionResult = context.filter(
{
label: label,
original: label,
apply: label,
type: completionList.type,
score: 0,
},
text
);
if (completionResult !== null) {
options.push(completionResult);
}
Expand Down
6 changes: 3 additions & 3 deletions src/lang-promql/promql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export const promQLSyntax = LezerSyntax.define(
Duration: 'number',
'abs absent absent_over_time avg_over_time ceil changes clamp_max clamp_min count_over_time days_in_month day_of_month day_of_week delta deriv exp floor histogram_quantile holt_winters hour idelta increase irate label_replace label_join ln log10 log2 max_over_time min_over_time minute month predict_linear quantile_over_time rate resets round scalar sort sort_desc sqrt stddev_over_time stdvar_over_time sum_over_time time timestamp vector year':
'functionName',
'avg bottomk count count_values group max min quantile stddev stdvar sum topk': 'operatorKeyword',
'by without bool on ignoring group_left group_right offset': 'modifier',
'and unless or': 'logicOperator',
'Avg Bottomk Count Count_values Group Max Min Quantile Stddev Stdvar Sum Topk': 'operatorKeyword',
'By Without Bool On Ignoring GroupLeft GroupRight Offset': 'modifier',
'And Unless Or': 'logicOperator',
BinOp: 'operator',
MatchOp: 'compareOperator',
UnaryOp: 'arithmeticOperator',
Expand Down

0 comments on commit 562ae73

Please sign in to comment.