diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a79662c5..6b76fa69d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ Swift. File detection is now stricter for UTF-8, and recognises more compression file types as binary (e.g. zstd or bzip2). +Added support for Verilog and SystemVerilog. + ### Build CI on GitHub now uses Ubuntu 22.04 for Linux builds (previously Ubuntu diff --git a/Cargo.lock b/Cargo.lock index 598dc49e0..ba5ae41a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -303,6 +303,7 @@ dependencies = [ "tree-sitter-swift", "tree-sitter-toml-ng", "tree-sitter-typescript", + "tree-sitter-verilog", "tree-sitter-xml", "tree-sitter-yaml", "tree_magic_mini", @@ -1291,6 +1292,16 @@ dependencies = [ "tree-sitter-language", ] +[[package]] +name = "tree-sitter-verilog" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e7e0360395852f1f6ff5b7b82c72dc6557d181073188df1d60ec469ea69c66" +dependencies = [ + "cc", + "tree-sitter-language", +] + [[package]] name = "tree-sitter-xml" version = "0.7.0" diff --git a/Cargo.toml b/Cargo.toml index 868953da9..71cdcfc75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ tree-sitter-scala = "0.23.3" tree-sitter-swift = "0.7.0" tree-sitter-toml-ng = "0.7.0" tree-sitter-typescript = "0.23.2" +tree-sitter-verilog = "1.0.3" tree-sitter-xml = "0.7.0" tree-sitter-yaml = "0.7.0" diff --git a/manual/src/languages_supported.md b/manual/src/languages_supported.md index 9030965bf..559e5f8cb 100644 --- a/manual/src/languages_supported.md +++ b/manual/src/languages_supported.md @@ -56,6 +56,7 @@ with `difft --list-languages`. | SQL | [m-novikov/tree-sitter-sql](https://github.com/m-novikov/tree-sitter-sql) | | Swift | [alex-pinkus/tree-sitter-swift](https://github.com/alex-pinkus/tree-sitter-swift) | | TypeScript, TSX | [tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript) | +| Verilog | [tree-sitter/tree-sitter-verilog](https://github.com/tree-sitter/tree-sitter-verilog) | | VHDL | [JLeemaster/tree-sitter-vhdl](https://github.com/JLeemaster/tree-sitter-vhdl) | | Zig | [maxxnino/tree-sitter-zig](https://github.com/maxxnino/tree-sitter-zig) | diff --git a/sample_files/compare.expected b/sample_files/compare.expected index b74b86638..cd4c401e6 100644 --- a/sample_files/compare.expected +++ b/sample_files/compare.expected @@ -295,6 +295,9 @@ sample_files/typing_1.ml sample_files/typing_2.ml sample_files/utf16_1.py sample_files/utf16_2.py 3bcee785d4cebc38a42eafe49a198b52 - +sample_files/verilog_1.sv sample_files/verilog_2.sv +2f59632b5a4e5addfa7b4d5274da72cc - + sample_files/vhdl_1.vhd sample_files/vhdl_2.vhd ca98b4d14fc21e0f04cf24aeb3d2526c - diff --git a/sample_files/verilog_1.sv b/sample_files/verilog_1.sv new file mode 100644 index 000000000..69392bc2e --- /dev/null +++ b/sample_files/verilog_1.sv @@ -0,0 +1,11 @@ +module blinky( + input clk, + output led +); + reg[7:0] counter; + always_ff @(posedge clk) begin + counter <= counter + 1; + end + + assign led = counter > 'h80; +endmodule diff --git a/sample_files/verilog_2.sv b/sample_files/verilog_2.sv new file mode 100644 index 000000000..17a7f4d16 --- /dev/null +++ b/sample_files/verilog_2.sv @@ -0,0 +1,11 @@ +module blinky( + input clk, input rst, + output led +); + reg[7:0] counter; + always_ff @(posedge clk) + if (rst) counter <= 0; + else counter <= counter + 1; + + assign led = counter < 'h80; +endmodule diff --git a/src/parse/guess_language.rs b/src/parse/guess_language.rs index 5638b5458..d7a14af48 100644 --- a/src/parse/guess_language.rs +++ b/src/parse/guess_language.rs @@ -77,6 +77,7 @@ pub(crate) enum Language { Toml, TypeScript, TypeScriptTsx, + Verilog, Vhdl, Xml, Yaml, @@ -170,6 +171,7 @@ pub(crate) fn language_name(language: Language) -> &'static str { Toml => "TOML", TypeScript => "TypeScript", TypeScriptTsx => "TypeScript TSX", + Verilog => "Verilog", Vhdl => "VHDL", Xml => "XML", Yaml => "YAML", @@ -377,6 +379,7 @@ pub(crate) fn language_globs(language: Language) -> Vec { ], TypeScript => &["*.ts"], TypeScriptTsx => &["*.tsx"], + Verilog => &["*.v", "*.sv", "*.vh"], Vhdl => &["*.vhdl", "*.vhd"], Xml => &[ "*.ant", @@ -552,6 +555,7 @@ fn from_emacs_mode_header(src: &str) -> Option { "toml" => Some(Toml), "tuareg" => Some(OCaml), "typescript" => Some(TypeScript), + "verilog" => Some(Verilog), "vhdl" => Some(Vhdl), "yaml" => Some(Yaml), "zig" => Some(Zig), diff --git a/src/parse/tree_sitter_parser.rs b/src/parse/tree_sitter_parser.rs index 2d028bcf3..c1b944d17 100644 --- a/src/parse/tree_sitter_parser.rs +++ b/src/parse/tree_sitter_parser.rs @@ -1094,6 +1094,21 @@ pub(crate) fn from_language(language: guess::Language) -> TreeSitterConfig { sub_languages: vec![], } } + Verilog => { + let language_fn = tree_sitter_verilog::LANGUAGE; + let language = tree_sitter::Language::new(language_fn); + TreeSitterConfig { + language: language.clone(), + atom_nodes: [].into_iter().collect(), + delimiter_tokens: vec![("(", ")"), ("[", "]"), ("begin", "end")], + highlight_query: ts::Query::new( + &language, + include_str!("../../vendored_parsers/highlights/verilog.scm"), + ) + .unwrap(), + sub_languages: vec![], + } + } Vhdl => { let language = unsafe { tree_sitter_vhdl() }; TreeSitterConfig { diff --git a/vendored_parsers/highlights/verilog.scm b/vendored_parsers/highlights/verilog.scm new file mode 100644 index 000000000..fb97092fc --- /dev/null +++ b/vendored_parsers/highlights/verilog.scm @@ -0,0 +1,322 @@ +;; https://github.com/helix-editor/helix/blob/f6878f62f74430cff188e7978d06c5ed143179e9/runtime/queries/verilog/highlights.scm + +; Keywords + +[ + ; block delimiters + (module_keyword) + "endmodule" + "program" + "endprogram" + "class" + "endclass" + "interface" + "endinterface" + "package" + "endpackage" + "checker" + "endchecker" + + ; these work in helix, but panic on 1.0.3. Unsure why. + ; "config" + ; "endconfig" + + "pure" + "virtual" + "extends" + "implements" + "super" + (class_item_qualifier) + + "parameter" + "localparam" + "defparam" + "assign" + "typedef" + "modport" + "fork" + "join" + "join_none" + "join_any" + "default" + "break" + "assert" + (unique_priority) + "tagged" + "extern" +] @keyword + +[ + "function" + "endfunction" + + "task" + "endtask" +] @keyword.function + +"return" @keyword.control.return + +[ + "begin" + "end" +] @label + +[ + (always_keyword) + "generate" + "for" + "foreach" + "repeat" + "forever" + "initial" + "while" +] @keyword.control + +[ + "if" + "else" + (case_keyword) + "endcase" +] @keyword.control.conditional + +(comment) @comment + +(include_compiler_directive) @keyword.directive +(package_import_declaration + "import" @keyword.control.import) + +(package_import_declaration + (package_import_item + (package_identifier + (simple_identifier) @constant))) + +(text_macro_identifier + (simple_identifier) @keyword.directive) + +(package_scope + (package_identifier + (simple_identifier) @constant)) + +(package_declaration + (package_identifier + (simple_identifier) @constant)) + +(parameter_port_list + "#" @constructor) + +[ + "=" + "-" + "+" + "/" + "*" + "**" + "^" + "&" + "|" + "&&" + "||" + ":" + (unary_operator) + "{" + "}" + "'{" + "<=" + "@" + "==" + "!=" + "===" + "!==" + "-:" + "<" + ">" + ">=" + "%" + ">>" + "<<" + ">>>" + "<<<" + "|=" + (inc_or_dec_operator) + "?" +] @operator +[ + "or" + "and" +] @keyword.operator + +(cast + ["'" "(" ")"] @keyword.operator) + +(edge_identifier) @constant + +(port_direction) @label +(port_identifier + (simple_identifier) @variable) + +(variable_port_header ("var") @type.builtin) +(data_declaration ("var") @type.builtin) +(tf_port_item1 ("var") @type.builtin) +[ + (net_type) + (integer_vector_type) + (integer_atom_type) +] @type.builtin + +[ + "signed" + "unsigned" +] @label + +(data_type + (simple_identifier) @type) + +(method_call_body + (method_identifier) @variable.other.member) + +(interface_identifier + (simple_identifier) @type) + +(modport_identifier + (modport_identifier + (simple_identifier) @variable.other.member)) + +(net_port_type1 + (simple_identifier) @type) + +[ + (double_quoted_string) + (string_literal) +] @string + +[ + (include_compiler_directive) + (default_nettype_compiler_directive) + (timescale_compiler_directive) +] @keyword.directive + +; begin/end label +(seq_block + (simple_identifier) @comment) + +[ + ";" + "::" + "," + "." +] @punctuation.delimiter + + +(default_nettype_compiler_directive + (default_nettype_value) @string) + +(text_macro_identifier + (simple_identifier) @function.macro) + +(module_declaration + (module_header + (simple_identifier) @constructor)) + +(class_constructor_declaration + "new" @constructor) + +(parameter_identifier + (simple_identifier) @variable.parameter) + +[ + (integral_number) + (unsigned_number) + (unbased_unsized_literal) +] @constant.numeric + +(time_unit) @constant + +(checker_instantiation + (checker_identifier + (simple_identifier) @constructor)) + +(module_instantiation + (simple_identifier) @constructor) + +(name_of_instance + (instance_identifier + (simple_identifier) @variable)) + +(interface_port_declaration + (interface_identifier + (simple_identifier) @type)) + +(net_declaration + (simple_identifier) @type) + +(lifetime) @label + +(function_identifier + (function_identifier + (simple_identifier) @function)) + +(function_subroutine_call + (subroutine_call + (tf_call + (simple_identifier) @function))) + +(function_subroutine_call + (subroutine_call + (system_tf_call + (system_tf_identifier) @function.builtin))) + +(task_identifier + (task_identifier + (simple_identifier) @function.method)) + +;;TODO: fixme +;(assignment_pattern_expression + ;(assignment_pattern + ;(parameter_identifier) @variable.other.member)) + +(type_declaration + (data_type ["packed"] @label)) + +(struct_union) @type + +[ + "enum" +] @type + +(enum_name_declaration + (enum_identifier + (simple_identifier) @constant)) + +(type_declaration + (simple_identifier) @type) + +[ + (integer_atom_type) + (non_integer_type) + "genvar" +] @type.builtin + +(struct_union_member + (list_of_variable_decl_assignments + (variable_decl_assignment + (simple_identifier) @variable.other.member))) + +(member_identifier + (simple_identifier) @variable.other.member) + +(struct_union_member + (data_type_or_void + (data_type + (simple_identifier) @type))) + +(type_declaration + (simple_identifier) @type) + +(generate_block_identifier) @comment + +[ + "[" + "]" + "(" + ")" +] @punctuation.bracket