From 8c1bb283a135df8e63f964c21f5a7a2f3eabdf91 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 5 Mar 2024 03:29:07 +0800 Subject: [PATCH] syntax-highlighter: Add snapshot test for Groovy (#60819) Updates the docs to mention how to run one test specifically. --- docker-images/syntax-highlighter/README.md | 12 + ...ng__syntect_scip__test__groovy.groovy.snap | 250 ++++++++++++++++++ .../snapshots/syntect_files/groovy.groovy | 71 +++++ .../src/highlighting/syntect_scip.rs | 15 +- 4 files changed, 341 insertions(+), 7 deletions(-) create mode 100644 docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/snapshots/syntax_analysis__highlighting__syntect_scip__test__groovy.groovy.snap create mode 100644 docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/snapshots/syntect_files/groovy.groovy diff --git a/docker-images/syntax-highlighter/README.md b/docker-images/syntax-highlighter/README.md index fdd019a3da6..0de4df488c7 100644 --- a/docker-images/syntax-highlighter/README.md +++ b/docker-images/syntax-highlighter/README.md @@ -47,6 +47,18 @@ By default on startup, `syntect_server` will list all file types it supports. Th 2. Use `cargo run --bin syntect_server` to run the server locally. 3. You can change the `SRC_SYNTECT_SERVER` option in your `sg.config.yaml` to point to whatever port you're running on (usually 8000) and test against that without building the docker image. +### Testing syntect -> SCIP grammar mappings + + + +You can run a subset of tests for `syntect_scip` using the `ONLY` environment variable. +Example: + +```bash +cd crates/syntax-analysis +ONLY=.java cargo test test_all_files -- --nocapture +``` + ## Building docker image `./build.sh` will build your current repository checkout into a final Docker image. You **DO NOT** need to do this when you push to get it publish. But, you should do this to make sure that it is possible to build the image :smile:. diff --git a/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/snapshots/syntax_analysis__highlighting__syntect_scip__test__groovy.groovy.snap b/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/snapshots/syntax_analysis__highlighting__syntect_scip__test__groovy.groovy.snap new file mode 100644 index 00000000000..b7a254450e2 --- /dev/null +++ b/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/snapshots/syntax_analysis__highlighting__syntect_scip__test__groovy.groovy.snap @@ -0,0 +1,250 @@ +--- +source: crates/syntax-analysis/src/highlighting/syntect_scip.rs +expression: "snapshot_sciptect_documents(&document, &contents)" +--- + def name = "John" +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^^^^^^ StringLiteral string.quoted.double.groovy + String greeting = "Hello" +//^^^^^^ IdentifierType storage.type.class.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^^^^^^^ StringLiteral string.quoted.double.groovy + int age = 30 +//^^^ IdentifierType storage.type.primitive.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^^ NumericLiteral constant.numeric.groovy + + def list = [1, 2, 3] +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^ PunctuationBracket punctuation.definition.structure.begin.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.separator.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.separator.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.structure.end.groovy + def map = [name: "John", age: 30] +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^ PunctuationBracket punctuation.definition.structure.begin.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^^^^^ StringLiteral string.quoted.double.groovy +// ^ PunctuationBracket punctuation.definition.separator.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.structure.end.groovy + + def code = { "Inside closure" } +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^ PunctuationBracket punctuation.section.block.begin.groovy +// ^^^^^^^^^^^^^^^^ StringLiteral string.quoted.double.groovy +// ^ PunctuationBracket punctuation.section.block.end.groovy + + def message = name ?: "Default" +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^^ IdentifierOperator keyword.operator.elvis.groovy +// ^^^^^^^^^ StringLiteral string.quoted.double.groovy + + def str = "hello 123 world" +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^^^^^^^^^^^^^^^^^ StringLiteral string.quoted.double.groovy + def regex = /\d+/ +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^ PunctuationBracket punctuation.definition.string.regexp.begin.groovy +// ^^^ StringLiteral punctuation.definition.string.regexp.end.groovy +// ^ PunctuationBracket punctuation.definition.string.regexp.end.groovy + + def transformed = [1, 2, 3, 4, 5].collect{ it * 2 } +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^ PunctuationBracket punctuation.definition.structure.begin.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.separator.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.separator.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.separator.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.separator.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.structure.end.groovy +// ^ PunctuationBracket punctuation.accessor.dot.groovy +// ^ PunctuationBracket punctuation.section.block.begin.groovy +// ^ IdentifierOperator keyword.operator.arithmetic.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.section.block.end.groovy + + assert name instanceof String +//^^^^^^ Keyword keyword.control.assert.groovy +// ^^^^^^^^^^ IdentifierOperator keyword.operator.instanceof.groovy +// ^^^^^^ IdentifierType storage.type.class.groovy + + new File("data.txt") +//^^^ Keyword keyword.other.new.groovy +// ^^^^ IdentifierType storage.type.class.groovy +// ^^^^^^^^^^ StringLiteral string.quoted.double.groovy + + name.reverse() +// ^ PunctuationBracket punctuation.accessor.dot.groovy +// ^ PunctuationBracket punctuation.definition.method-parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.method-parameters.end.groovy + + for(i in 1..5) { +//^^^ Keyword keyword.control.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^^ IdentifierOperator keyword.operator.range.groovy +// ^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.section.block.begin.groovy + println i +// ^^^^^^^ IdentifierFunction support.function.print.groovy + } +//^ PunctuationBracket punctuation.section.block.end.groovy + + class Person { +//^^^^^ IdentifierType storage.type.class.groovy +// ^^^^^^ IdentifierType entity.name.type.class.groovy + String name +// ^^^^^^ IdentifierType storage.type.class.groovy + int age +// ^^^ IdentifierType storage.type.primitive.groovy + + String greeting() { +// ^^^^^^ IdentifierType storage.type.return-type.class.groovy +// ^^^^^^^^ IdentifierFunction entity.name.function.groovy +// ^ PunctuationBracket punctuation.definition.parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.parameters.end.groovy + "Hello, $name!" +// ^^^^^^^^ StringLiteral variable.other.interpolated.groovy +// ^^^^^ Identifier variable.other.interpolated.groovy +// ^^ StringLiteral string.quoted.double.groovy + } + } + + def person = new Person(name: "John", age: 30) +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^^^ Keyword keyword.other.new.groovy +// ^^^^^^ IdentifierType storage.type.class.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^^^^^ StringLiteral string.quoted.double.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^ NumericLiteral constant.numeric.groovy + + class Employee extends Person { +//^^^^^ IdentifierType storage.type.class.groovy +// ^^^^^^^^ IdentifierType entity.name.type.class.groovy +// ^^^^^^^ Keyword storage.modifier.extends.groovy +// ^^^^^^ Identifier entity.other.inherited-class.groovy + double salary +// ^^^^^^ IdentifierType storage.type.primitive.groovy + + String greeting() { +// ^^^^^^ IdentifierType storage.type.return-type.class.groovy +// ^^^^^^^^ IdentifierFunction entity.name.function.groovy +// ^ PunctuationBracket punctuation.definition.parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.parameters.end.groovy + "${super.greeting()} My salary is $salary." +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ StringLiteral variable.other.interpolated.groovy +// ^^ PunctuationBracket punctuation.section.embedded.groovy +// ^^^^^ Identifier variable.language.groovy +// ^ PunctuationBracket punctuation.accessor.dot.groovy +// ^ PunctuationBracket punctuation.definition.method-parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.method-parameters.end.groovy +// ^ PunctuationBracket punctuation.section.embedded.groovy +// ^^^^^^^ Identifier variable.other.interpolated.groovy +// ^^ StringLiteral string.quoted.double.groovy + } + } + + def employee = new Employee(name: "Jane", age: 28, salary: 60000) +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^^^ Keyword keyword.other.new.groovy +// ^^^^^^^^ IdentifierType storage.type.class.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^^^^^ StringLiteral string.quoted.double.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^^^^ NumericLiteral constant.numeric.groovy + + interface Singer { +// ^^^^^^ IdentifierType storage.type.class.groovy +// ^ PunctuationBracket punctuation.section.block.begin.groovy + void sing() +// ^ PunctuationBracket punctuation.definition.method-parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.method-parameters.end.groovy + } +//^ PunctuationBracket punctuation.section.block.end.groovy + + class LeadSinger implements Singer { +//^^^^^ IdentifierType storage.type.class.groovy +// ^^^^^^^^^^ IdentifierType entity.name.type.class.groovy +// ^^^^^^^^^^ Keyword storage.modifier.implements.groovy +// ^^^^^^ Identifier entity.other.inherited-class.interface.groovy + @Override +// ^^^^^^^^^ IdentifierType storage.type.annotation.groovy + void sing() { +// ^^^^ IdentifierType storage.type.return-type.void.groovy +// ^^^^ IdentifierFunction entity.name.function.groovy +// ^ PunctuationBracket punctuation.definition.parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.parameters.end.groovy + println "Singing a song!" +// ^^^^^^^ IdentifierFunction support.function.print.groovy +// ^^^^^^^^^^^^^^^^^ StringLiteral string.quoted.double.groovy + } + + } + + trait Guitarist { +// ^^^^^^^^^ IdentifierType storage.type.class.groovy +// ^ PunctuationBracket punctuation.section.block.begin.groovy + void playGuitar() { +// ^ PunctuationBracket punctuation.definition.method-parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.method-parameters.end.groovy +// ^ PunctuationBracket punctuation.section.block.begin.groovy + println "Playing guitar riff" +// ^^^^^^^ IdentifierFunction support.function.print.groovy +// ^^^^^^^^^^^^^^^^^^^^^ StringLiteral string.quoted.double.groovy + } +// ^ PunctuationBracket punctuation.section.block.end.groovy + } +//^ PunctuationBracket punctuation.section.block.end.groovy + + class RockSinger extends Person implements Singer, Guitarist { } +//^^^^^ IdentifierType storage.type.class.groovy +// ^^^^^^^^^^ IdentifierType entity.name.type.class.groovy +// ^^^^^^^ Keyword storage.modifier.extends.groovy +// ^^^^^^ Identifier entity.other.inherited-class.groovy +// ^^^^^^^^^^ Keyword storage.modifier.implements.groovy +// ^^^^^^ Identifier entity.other.inherited-class.interface.groovy +// ^ PunctuationBracket punctuation.definition.implemented.interfaces.separator.groovy +// ^^^^^^^^^ Identifier entity.other.inherited-class.interface.groovy + + def singer = new RockSinger(name: "Ross", age: 25).with { +//^^^ IdentifierType storage.type.def.groovy +// ^ IdentifierOperator keyword.operator.assignment.groovy +// ^^^ Keyword keyword.other.new.groovy +// ^^^^^^^^^^ IdentifierType storage.type.class.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^^^^^ StringLiteral string.quoted.double.groovy +// ^ PunctuationBracket punctuation.definition.separator.key-value.groovy +// ^^ NumericLiteral constant.numeric.groovy +// ^ PunctuationBracket punctuation.accessor.dot.groovy +// ^^^^ IdentifierFunction support.function.other.groovy +// ^ PunctuationBracket punctuation.section.block.begin.groovy + sing() +// ^ PunctuationBracket punctuation.definition.method-parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.method-parameters.end.groovy + playGuitar() +// ^ PunctuationBracket punctuation.definition.method-parameters.begin.groovy +// ^ PunctuationBracket punctuation.definition.method-parameters.end.groovy + } +//^ PunctuationBracket punctuation.section.block.end.groovy + diff --git a/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/snapshots/syntect_files/groovy.groovy b/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/snapshots/syntect_files/groovy.groovy new file mode 100644 index 00000000000..f1a442b1f49 --- /dev/null +++ b/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/snapshots/syntect_files/groovy.groovy @@ -0,0 +1,71 @@ +def name = "John" +String greeting = "Hello" +int age = 30 + +def list = [1, 2, 3] +def map = [name: "John", age: 30] + +def code = { "Inside closure" } + +def message = name ?: "Default" + +def str = "hello 123 world" +def regex = /\d+/ + +def transformed = [1, 2, 3, 4, 5].collect{ it * 2 } + +assert name instanceof String + +new File("data.txt") + +name.reverse() + +for(i in 1..5) { + println i +} + +class Person { + String name + int age + + String greeting() { + "Hello, $name!" + } +} + +def person = new Person(name: "John", age: 30) + +class Employee extends Person { + double salary + + String greeting() { + "${super.greeting()} My salary is $salary." + } +} + +def employee = new Employee(name: "Jane", age: 28, salary: 60000) + +interface Singer { + void sing() +} + +class LeadSinger implements Singer { + @Override + void sing() { + println "Singing a song!" + } + +} + +trait Guitarist { + void playGuitar() { + println "Playing guitar riff" + } +} + +class RockSinger extends Person implements Singer, Guitarist { } + +def singer = new RockSinger(name: "Ross", age: 25).with { + sing() + playGuitar() +} \ No newline at end of file diff --git a/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/syntect_scip.rs b/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/syntect_scip.rs index 922daf764f8..0c5b41da423 100644 --- a/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/syntect_scip.rs +++ b/docker-images/syntax-highlighter/crates/syntax-analysis/src/highlighting/syntect_scip.rs @@ -388,8 +388,9 @@ impl<'a> DocumentGenerator<'a> { match match_scope_to_kind(&scope) { Some(kind) => { - // Uncomment to debug what scopes are picked up - // println!("SCOPE {row:>3}:{character:<3} {:50} {kind:?}", format!("{}", scope)); + // See also NOTE(id: only-flag) + // DEBUG: Print matched scopes here + // eprintln!("SCOPE {row:>3}:{character:<3} {:50} {kind:?}", format!("{}", scope)); let partial_hl = HighlightStart::some(row, character, kind, scope); if let Some(partial_hl) = highlight_manager.push_hl(partial_hl) @@ -404,7 +405,9 @@ impl<'a> DocumentGenerator<'a> { }; } None => { - // println!("SCOPE {row:>3}:{character:<3} {:50}", format!("{}", scope)); + // See also NOTE(id: only-flag) + // DEBUG: Print unknown/unhighlighted scope here + // eprintln!("SCOPE {row:>3}:{character:<3} {:50}", format!("{}", scope)); unhandled_scopes.insert(scope); highlight_manager.push_empty(); } @@ -584,10 +587,8 @@ mod test { let dir = read_dir(&input_dir)?; - let filter = env::args() - .last() - .and_then(|x| x.strip_prefix("only=").map(|x| x.to_owned())) - .unwrap_or("".to_owned()); // run everything + // See NOTE(id: only-flag) for exact syntax on how to pass this. + let filter = env::var("ONLY").unwrap_or("".to_owned()); let mut count = 0; for entry in dir {