diff --git a/lua/nvim-treesitter/parsers.lua b/lua/nvim-treesitter/parsers.lua index dd7d3c75e..7d0ec1e4f 100644 --- a/lua/nvim-treesitter/parsers.lua +++ b/lua/nvim-treesitter/parsers.lua @@ -75,6 +75,13 @@ return { }, tier = 2, }, + b = { + install_info = { + revision = '353237b4e3325f73c4eb1f745048c6bcac763953', + url = 'https://github.com/VoxelPrismatic/tree-sitter-b', + }, + tier = 2, + }, bash = { install_info = { revision = '0c46d792d54c536be5ff7eb18eb95c70fccdb232', diff --git a/plugin/filetypes.lua b/plugin/filetypes.lua index feb1194a6..e95994b82 100644 --- a/plugin/filetypes.lua +++ b/plugin/filetypes.lua @@ -59,6 +59,7 @@ local filetypes = { vhs = { 'tape' }, xml = { 'xsd', 'xslt', 'svg' }, xresources = { 'xdefaults' }, + b = { 'b' }, } for lang, ft in pairs(filetypes) do diff --git a/runtime/queries/b/folds.scm b/runtime/queries/b/folds.scm new file mode 100644 index 000000000..bb26a62eb --- /dev/null +++ b/runtime/queries/b/folds.scm @@ -0,0 +1,23 @@ +[ + (for_statement) + (if_statement) + (while_statement) + (do_statement) + (switch_statement) + (case_statement) + (function_definition) + (struct_specifier) + (enum_specifier) + (comment) + (preproc_if) + (preproc_elif) + (preproc_else) + (preproc_ifdef) + (preproc_function_def) + (initializer_list) + (gnu_asm_expression) + (preproc_include)+ +] @fold + +(compound_statement + (compound_statement) @fold) diff --git a/runtime/queries/b/highlights.scm b/runtime/queries/b/highlights.scm new file mode 100644 index 000000000..533c662bc --- /dev/null +++ b/runtime/queries/b/highlights.scm @@ -0,0 +1,242 @@ +; Lower priority to prefer @variable.parameter when identifier appears in parameter_declaration. +((identifier) @variable + (#set! priority 95)) + +[ + "default" + "goto" + "asm" + "__asm__" +] @keyword + +"auto" @keyword.type + +"extrn" @keyword.type + +(alignof_expression + . + _ @keyword.operator) + +"return" @keyword.return + +"while" @keyword.repeat + +[ + "if" + "else" + "case" + "switch" +] @keyword.conditional + +"extrn" @keyword.import + +[ + ";" + ":" + "," + "." + "::" +] @punctuation.delimiter + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ + "=" + "-" + "*" + "/" + "+" + "%" + "~" + "|" + "&" + "^" + "<<" + ">>" + "->" + "<" + "<=" + ">=" + ">" + "==" + "!=" + "!" + "&&" + "||" + "--" + "++" +] @operator + +[ + "=-" + "=+" + "=*" + "=/" + "=%" + "=|" + "=&" + "=^" + "=>>" + "=<<" + "=>=" + "=<=" +] @operator + +; Make sure the comma operator is given a highlight group after the comma +; punctuator so the operator is highlighted properly. +(comma_expression + "," @operator) + +[ + (true) + (false) +] @boolean + +(conditional_expression + [ + "?" + ":" + ] @keyword.conditional.ternary) + +(string_literal) @string + +(system_lib_string) @string + +(escape_sequence) @string.escape + +(null) @constant.builtin + +(number_literal) @number + +(char_literal) @character + +((field_expression + (field_identifier) @property) @_parent + (#not-has-parent? @_parent template_method function_declarator call_expression)) + +(field_designator) @property + +((field_identifier) @property + (#has-ancestor? @property field_declaration) + (#not-has-ancestor? @property function_declarator)) + +(statement_identifier) @label + +(declaration + type: (type_identifier) @_type + declarator: (identifier) @label + (#eq? @_type "__label__")) + +[ + (type_identifier) + (type_descriptor) +] @type + +(storage_class_specifier) @keyword.modifier + +[ + (type_qualifier) + (gnu_asm_qualifier) + "__extension__" +] @keyword.modifier + +(type_definition + declarator: (type_identifier) @type.definition) + +(primitive_type) @type.builtin + +(sized_type_specifier + _ @type.builtin + type: _?) + +((identifier) @constant + (#lua-match? @constant "^[A-Z][A-Z0-9_]+$")) + +(enumerator + name: (identifier) @constant) + +(case_statement + value: (identifier) @constant) + +((identifier) @constant.builtin + ; format-ignore + (#any-of? @constant.builtin + "args" + )) + +(attribute_specifier + (argument_list + (identifier) @variable.builtin)) + +(attribute_specifier + (argument_list + (call_expression + function: (identifier) @variable.builtin))) + +((call_expression + function: (identifier) @function.builtin) + (#lua-match? @function.builtin "^__builtin_")) + +((call_expression + function: (identifier) @function.builtin) + (#has-ancestor? @function.builtin attribute_specifier)) + +(call_expression + function: (identifier) @function.call) + +(call_expression + function: (field_expression + field: (field_identifier) @function.call)) + +(function_declarator + declarator: (identifier) @function) + +(function_declarator + declarator: (parenthesized_declarator + (pointer_declarator + declarator: (field_identifier) @function))) + +(comment) @comment @spell + +((comment) @comment.documentation + (#lua-match? @comment.documentation "^/[*][*][^*].*[*]/$")) + +; Parameters +(parameter_declaration + declarator: (identifier) @variable.parameter) + +(parameter_declaration + declarator: (array_declarator) @variable.parameter) + +(parameter_declaration + declarator: (pointer_declarator) @variable.parameter) + +; K&R functions +; To enable support for K&R functions, +; add the following lines to your own query config and uncomment them. +; They are commented out as they'll conflict with C++ +; Note that you'll need to have `; extends` at the top of your query file. +; +; (parameter_list (identifier) @variable.parameter) +; +; (function_definition +; declarator: _ +; (declaration +; declarator: (identifier) @variable.parameter)) +; +; (function_definition +; declarator: _ +; (declaration +; declarator: (array_declarator) @variable.parameter)) +; +; (function_definition +; declarator: _ +; (declaration +; declarator: (pointer_declarator) @variable.parameter)) diff --git a/runtime/queries/b/indents.scm b/runtime/queries/b/indents.scm new file mode 100644 index 000000000..1932ce8d6 --- /dev/null +++ b/runtime/queries/b/indents.scm @@ -0,0 +1,99 @@ +[ + (compound_statement) + (field_declaration_list) + (case_statement) + (enumerator_list) + (compound_literal_expression) + (initializer_list) + (init_declarator) +] @indent.begin + +; With current indent logic, if we capture expression_statement with @indent.begin +; It will be affected by _parent_ node with error subnodes deep down the tree +; So narrow indent capture to check for error inside expression statement only, +(expression_statement + (_) @indent.begin + ";" @indent.end) + +(ERROR + "for" + "(" @indent.begin + ";" + ";" + ")" @indent.end) + +((for_statement + body: (_) @_body) @indent.begin + (#not-kind-eq? @_body "compound_statement")) + +(while_statement + condition: (_) @indent.begin) + +((while_statement + body: (_) @_body) @indent.begin + (#not-kind-eq? @_body "compound_statement")) + +((if_statement) + . + (ERROR + "else" @indent.begin)) + +(if_statement + condition: (_) @indent.begin) + +; Supports if without braces (but not both if-else without braces) +(if_statement + consequence: (_ + ";" @indent.end) @_consequence + (#not-kind-eq? @_consequence "compound_statement") + alternative: (else_clause + "else" @indent.branch + [ + (if_statement + (compound_statement) @indent.dedent)? @indent.dedent + (compound_statement)? @indent.dedent + (_)? @indent.dedent + ])?) @indent.begin + +(else_clause + (_ + . + "{" @indent.branch)) + +(compound_statement + "}" @indent.end) + +[ + ")" + "}" + (statement_identifier) +] @indent.branch + +[ + "#define" + "#ifdef" + "#ifndef" + "#elif" + "#if" + "#else" + "#endif" +] @indent.zero + +[ + (preproc_arg) + (string_literal) +] @indent.ignore + +((ERROR + (parameter_declaration)) @indent.align + (#set! indent.open_delimiter "(") + (#set! indent.close_delimiter ")")) + +([ + (argument_list) + (parameter_list) +] @indent.align + (#set! indent.open_delimiter "(") + (#set! indent.close_delimiter ")")) + +(comment) @indent.auto diff --git a/runtime/queries/b/injections.scm b/runtime/queries/b/injections.scm new file mode 100644 index 000000000..ebedc1ec3 --- /dev/null +++ b/runtime/queries/b/injections.scm @@ -0,0 +1,128 @@ +((preproc_arg) @injection.content + (#set! injection.self)) + +((comment) @injection.content + (#set! injection.language "comment")) + +((comment) @injection.content + (#match? @injection.content "/\\*!([a-zA-Z]+:)?re2c") + (#set! injection.language "re2c")) + +((comment) @injection.content + (#lua-match? @injection.content "/[*/][!*/]