diff --git a/vscode/grammars/ruby.cson.json b/vscode/grammars/ruby.cson.json index 7be523fa8..2c7b83a0c 100644 --- a/vscode/grammars/ruby.cson.json +++ b/vscode/grammars/ruby.cson.json @@ -109,20 +109,23 @@ "name": "keyword.operator.assignment.augmented.ruby" } }, - "match": "^\\s*([a-z]([A-Za-z0-9_])*)\\s*(&&=)", - "comment": "A local variable and assignment" + "match": "^\\s*([a-z]([A-Za-z0-9_])*)\\s*((&&|\\|\\|)=)", + "comment": "A local variable and/or assignment" }, { "captures": { "1": { - "name": "variable.ruby" + "name": "keyword.control.ruby" }, "3": { + "name": "variable.ruby" + }, + "5": { "name": "keyword.operator.assignment.augmented.ruby" } }, - "match": "^\\s*([a-z]([A-Za-z0-9_])*)\\s*(\\|\\|=)", - "comment": "A local variable or assignment" + "match": "(?>)=)", "comment": "A local variable operation assignment (+=, -=, *=, /=)" }, + { + "captures": { + "1": { + "name": "keyword.control.ruby" + }, + "3": { + "name": "variable.ruby" + }, + "5": { + "name": "keyword.operator.assignment.augmented.ruby" + } + }, + "match": "(?>)=)", + "comment": "A local variable operation assignment in a condition" + }, { "captures": { "1": { @@ -145,6 +163,18 @@ "match": "^\\s*([a-z]([A-Za-z0-9_])*)\\s*=[^=>]", "comment": "A local variable assignment" }, + { + "captures": { + "1": { + "name": "keyword.control.ruby" + }, + "3": { + "name": "variable.ruby" + } + }, + "match": "(?]", + "comment": "A local variable assignment in a condition" + }, { "captures": { "1": { diff --git a/vscode/src/test/suite/grammars.test.ts b/vscode/src/test/suite/grammars.test.ts index 127f1e963..6cc2065f4 100644 --- a/vscode/src/test/suite/grammars.test.ts +++ b/vscode/src/test/suite/grammars.test.ts @@ -337,6 +337,66 @@ suite("Grammars", () => { const actualTokens = tokenizeRuby(ruby); assert.deepStrictEqual(actualTokens, expectedTokens); }); + test("or assignment", () => { + const ruby = "local ||= 1"; + const expectedTokens = [ + ["local", ["source.ruby", "variable.ruby"]], + [" ", ["source.ruby"]], + [ + "||=", + ["source.ruby", "keyword.operator.assignment.augmented.ruby"], + ], + [" ", ["source.ruby"]], + ["1", ["source.ruby", "constant.numeric.ruby"]], + ]; + const actualTokens = tokenizeRuby(ruby); + assert.deepStrictEqual(actualTokens, expectedTokens); + }); + test("and assignment in a condition", () => { + const ruby = "if local &&= 1"; + const expectedTokens = [ + ["if", ["source.ruby", "keyword.control.ruby"]], + [" ", ["source.ruby"]], + ["local", ["source.ruby", "variable.ruby"]], + [" ", ["source.ruby"]], + [ + "&&=", + ["source.ruby", "keyword.operator.assignment.augmented.ruby"], + ], + [" ", ["source.ruby"]], + ["1", ["source.ruby", "constant.numeric.ruby"]], + ]; + const actualTokens = tokenizeRuby(ruby); + assert.deepStrictEqual(actualTokens, expectedTokens); + }); + test("assignment in a condition", () => { + const ruby = "if (local = 1)"; + const expectedTokens = [ + ["if", ["source.ruby", "keyword.control.ruby"]], + [" (", ["source.ruby"]], + ["local", ["source.ruby", "variable.ruby"]], + [" = ", ["source.ruby"]], + ["1", ["source.ruby", "constant.numeric.ruby"]], + [")", ["source.ruby", "punctuation.section.function.ruby"]], + ]; + const actualTokens = tokenizeRuby(ruby); + assert.deepStrictEqual(actualTokens, expectedTokens); + }); + test("operation assignment in a condition", () => { + const ruby = "if (local += 1)"; + const expectedTokens = [ + ["if", ["source.ruby", "keyword.control.ruby"]], + [" (", ["source.ruby"]], + ["local", ["source.ruby", "variable.ruby"]], + [" ", ["source.ruby"]], + ["+=", ["source.ruby", "keyword.operator.assignment.augmented.ruby"]], + [" ", ["source.ruby"]], + ["1", ["source.ruby", "constant.numeric.ruby"]], + [")", ["source.ruby", "punctuation.section.function.ruby"]], + ]; + const actualTokens = tokenizeRuby(ruby); + assert.deepStrictEqual(actualTokens, expectedTokens); + }); }); function tokenizeRuby(ruby: string): [string, string[]][] {