Repository: pabluk/pygments-promql (language: python)

Issue:
Multiple comma-separated function arguments
Found another small issue with the following query:
```
histogram_quantile(0.9999,sum(irate(metric_histogram{a=~'(1|2|3)',b=~'(1|2|3)',c=~'(1|2|3)',d=~'(1|2|3)'}[1m])) by(a,b,c))
```
<img width="1037" alt="Screenshot 2021-04-26 at 10 37 52" src="https://user-images.githubusercontent.com/9629314/116053959-7e97d500-a67b-11eb-9bed-92b770018f6b.png">

seems that multiple labels from by aggregator are not parsed properly.


Discussion / hints:
Hey @ocervell! thanks for the full query, I'm testing it now and I'll try to find what is happening with those labels. 

Fix patch:
diff --git a/pygments_promql/__init__.py b/pygments_promql/__init__.py
index f220920..d5ddc17 100644
--- a/pygments_promql/__init__.py
+++ b/pygments_promql/__init__.py
@@ -136,6 +136,7 @@ class PromQLLexer(RegexLexer):
             (r"\s+", Whitespace),
             (r"//.*?\n", Comment.Single),
             (r",", Punctuation),
+            (r"(by|without)(\s*?)(\()", bygroups(Keyword, Whitespace, Operator), "aggregator_modifier"),
             # Keywords
             base_keywords,
             aggregator_keywords,
@@ -161,6 +162,13 @@ class PromQLLexer(RegexLexer):
             (r"{", Punctuation, "labels"),
             (r"\[", Punctuation, "range"),
         ],
+        "aggregator_modifier": [
+            (r"\)", Operator, "#pop"),
+            (r"\n", Whitespace),
+            (r"\s+", Whitespace),
+            (r",", Punctuation),
+            (r"[_a-zA-Z]+", Name.Label),
+        ],
         "labels": [
             (r"}", Punctuation, "#pop"),
             (r"\n", Whitespace),


Test patch:
diff --git a/tests/test_promql.py b/tests/test_promql.py
index 94f39b9..9d46f30 100644
--- a/tests/test_promql.py
+++ b/tests/test_promql.py
@@ -138,10 +138,10 @@ def test_function_sum_with_args(lexer):
         (Token.Keyword, "by"),
         (Token.Text.Whitespace, " "),
         (Token.Operator, "("),
-        (Token.Name.Variable, "app"),
+        (Token.Name.Label, "app"),
         (Token.Punctuation, ","),
         (Token.Text.Whitespace, " "),
-        (Token.Name.Variable, "proc"),
+        (Token.Name.Label, "proc"),
         (Token.Operator, ")"),
         (Token.Text.Whitespace, " "),
         (Token.Operator, "("),
@@ -173,7 +173,7 @@ def test_function_multi_line(lexer):
         (Token.Keyword, "by"),
         (Token.Text.Whitespace, " "),
         (Token.Operator, "("),
-        (Token.Name.Variable, "instance"),
+        (Token.Name.Label, "instance"),
         (Token.Operator, ")"),
         (Token.Text.Whitespace, " "),
         (Token.Operator, "("),
@@ -247,7 +247,7 @@ def test_function_multi_line2(lexer):
         (Token.Text.Whitespace, " "),
         (Token.Keyword, "by"),
         (Token.Operator, "("),
-        (Token.Name.Variable, "instance"),
+        (Token.Name.Label, "instance"),
         (Token.Operator, ")"),
         (Token.Text.Whitespace, "\n"),
         (Token.Text.Whitespace, "        "),
@@ -340,7 +340,7 @@ def test_complex_exp_double_quotes(lexer):
         (Token.Text.Whitespace, " "),
         (Token.Keyword, "by"),
         (Token.Operator, "("),
-        (Token.Name.Variable, "node"),
+        (Token.Name.Label, "node"),
         (Token.Operator, ")"),
         (Token.Operator, ")"),
         (Token.Text.Whitespace, "\n"),
@@ -378,7 +378,7 @@ def test_complex_exp_single_quotes(lexer):
         (Token.Text.Whitespace, " "),
         (Token.Keyword, "by"),
         (Token.Operator, "("),
-        (Token.Name.Variable, "node"),
+        (Token.Name.Label, "node"),
         (Token.Operator, ")"),
         (Token.Operator, ")"),
         (Token.Text.Whitespace, "\n"),
@@ -403,3 +403,74 @@ def test_matching_operator_no_regexmatch(lexer):
         (Token.Text.Whitespace, "\n"),
     ]
     assert list(lexer.get_tokens(fragment)) == tokens
+
+def test_by_clause_label_list(lexer):
+    fragment = u"sum(irate(metric_histogram{a=~'(1|2|3)',b=~'(1|2|3)',c=~'(1|2|3)',d=~'(1|2|3)'}[1m])) by(a,b,c)"
+    tokens = [
+        (Token.Keyword, "sum"),
+        (Token.Operator, "("),
+        (Token.Keyword.Reserved, "irate"),
+        (Token.Operator, "("),
+        (Token.Name.Variable, "metric_histogram"),
+        (Token.Punctuation, "{"),
+        (Token.Name.Label, "a"),
+        (Token.Operator, "=~"),
+        (Token.Punctuation, "'"),
+        (Token.Literal.String, "(1|2|3)"),
+        (Token.Punctuation, "'"),
+        (Token.Punctuation, ","),
+        (Token.Name.Label, "b"),
+        (Token.Operator, "=~"),
+        (Token.Punctuation, "'"),
+        (Token.Literal.String, "(1|2|3)"),
+        (Token.Punctuation, "'"),
+        (Token.Punctuation, ","),
+        (Token.Name.Label, "c"),
+        (Token.Operator, "=~"),
+        (Token.Punctuation, "'"),
+        (Token.Literal.String, "(1|2|3)"),
+        (Token.Punctuation, "'"),
+        (Token.Punctuation, ","),
+        (Token.Name.Label, "d"),
+        (Token.Operator, "=~"),
+        (Token.Punctuation, "'"),
+        (Token.Literal.String, "(1|2|3)"),
+        (Token.Punctuation, "'"),
+        (Token.Punctuation, "}"),
+        (Token.Punctuation, "["),
+        (Token.Literal.String, "1m"),
+        (Token.Punctuation, "]"),
+        (Token.Operator, ")"),
+        (Token.Operator, ")"),
+        (Token.Text.Whitespace, " "),
+        (Token.Keyword, "by"),
+        (Token.Operator, "("),
+        (Token.Name.Label, "a"),
+        (Token.Punctuation, ","),
+        (Token.Name.Label, "b"),
+        (Token.Punctuation, ","),
+        (Token.Name.Label, "c"),
+        (Token.Operator, ")"),
+        (Token.Text.Whitespace, "\n"),
+    ]
+    assert list(lexer.get_tokens(fragment)) == tokens
+
+
+def test_without_clause_label_list(lexer):
+    fragment = u"sum without (instance,) (http_requests_total)"
+    tokens = [
+        (Token.Keyword, "sum"),
+	(Token.Text.Whitespace, ' '),
+	(Token.Keyword, 'without'),
+	(Token.Text.Whitespace, ' '),
+	(Token.Operator, '('),
+	(Token.Name.Label, 'instance'),
+        (Token.Punctuation, ","),
+	(Token.Operator, ')'),
+	(Token.Text.Whitespace, ' '),
+	(Token.Operator, '('),
+	(Token.Name.Variable, 'http_requests_total'),
+	(Token.Operator, ')'),
+        (Token.Text.Whitespace, "\n"),
+    ]
+    assert list(lexer.get_tokens(fragment)) == tokens