From 16f3f98e4519cd01cb87dcecf429e0d31d9ad4ef Mon Sep 17 00:00:00 2001 From: Hannah Date: Tue, 10 Mar 2026 10:01:19 -0400 Subject: [PATCH] feature(parsers): add objectscript UDL parser to neovim --- SUPPORTED_LANGUAGES.md | 1 + lua/nvim-treesitter/parsers.lua | 9 + runtime/queries/objectscript/highlights.scm | 163 +++++++++++++++++ runtime/queries/objectscript/indents.scm | 2 + runtime/queries/objectscript/injections.scm | 192 ++++++++++++++++++++ 5 files changed, 367 insertions(+) create mode 100644 runtime/queries/objectscript/highlights.scm create mode 100644 runtime/queries/objectscript/indents.scm create mode 100644 runtime/queries/objectscript/injections.scm diff --git a/SUPPORTED_LANGUAGES.md b/SUPPORTED_LANGUAGES.md index 547b48d04..b2d2007c9 100644 --- a/SUPPORTED_LANGUAGES.md +++ b/SUPPORTED_LANGUAGES.md @@ -195,6 +195,7 @@ jsx (queries only)[^jsx] | unstable | `HFIJ ` | @steelsojka [nu](https://github.com/nushell/tree-sitter-nu) | unstable | `HFIJ ` | @abhisheksingh0x558 [objc](https://github.com/tree-sitter-grammars/tree-sitter-objc) | unstable | `HFIJL` | @amaanq [objdump](https://github.com/ColinKennedy/tree-sitter-objdump) | unstable | `H  J ` | @ColinKennedy +[objectscript](https://github.com/intersystems/tree-sitter-objectscript) | unstable | `H IJ ` | @davem-intersys, @hkimura-intersys [ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) | unstable | `HFIJL` | @undu [ocaml_interface](https://github.com/tree-sitter/tree-sitter-ocaml) | unstable | `HFIJL` | @undu [ocamllex](https://github.com/atom-ocaml/tree-sitter-ocamllex) | unstable | `H  J ` | @undu diff --git a/lua/nvim-treesitter/parsers.lua b/lua/nvim-treesitter/parsers.lua index 5f1f12e90..d31609919 100644 --- a/lua/nvim-treesitter/parsers.lua +++ b/lua/nvim-treesitter/parsers.lua @@ -1498,6 +1498,15 @@ return { maintainers = { '@ColinKennedy' }, tier = 2, }, + objectscript = { + install_info = { + location = 'udl', + revision = 'e03cd14c61bda43a135b23352f7fb695c2e9567f', + url = 'https://github.com/intersystems/tree-sitter-objectscript' + }, + maintainers = { '@davem-intersys', '@hkimura-intersys' }, + tier = 2, + } ocaml = { install_info = { location = 'grammars/ocaml', diff --git a/runtime/queries/objectscript/highlights.scm b/runtime/queries/objectscript/highlights.scm new file mode 100644 index 000000000..79dbe08c0 --- /dev/null +++ b/runtime/queries/objectscript/highlights.scm @@ -0,0 +1,163 @@ +(pattern_expression) @string.regex +(numeric_literal) @number +(string_literal) @string + +(keyword_pound_pound_class) @keyword +(keyword_pound_pound_super) @keyword +(system_defined_variable) @variable.special +(system_defined_function) @variable.special +(sql_field_modifier) @variable.special +(property_name) @property +(method_name) @function +(parameter_name) @property +(class_name) @type +(macro) @constant + +(routine_ref) @variable +(sql_field_identifier) @variable +(lvn) @variable +(gvn) @variable +(ssvn) @variable +(instance_variable) @variable +(objectscript_identifier) @variable + +(method_arg) @variable.parameter +; I didn't include '(' or ')' in this, because they are often grouped +; as part of a sequence that gets turned into a single token, so they +; don't get matched, and one ends up getting colored differently than the other. +[ + "_" + "," + ":" + "." + ".." + "..." + "'[" + "']" + "']]" + "\"" + "\"\"" + "[" + "]" + "]]" + "{" + "}" + "/" + "\\" + "#" + "|" + "||" + "/" + "/" + "$$" + "--" + ";" + "//" + "#;" + "##;" + "$" +] @punctuation + +[ + "'&" + "&" + "&&" + "'<" + "'=" + "'>" + "^" + "-" + "^$" + "+" + "<" + "<=" + "=" + ">" + ">=" + "@" + "*" + "**" + "'" + "'!" + "'?" + "!" + "?" +] @operator + +(json_string_literal) @string +(json_boolean_literal) @boolean +(json_number_literal) @number +(json_null_literal) @string +(bracket) @punctuation.bracket +(locktype) @variable + +(macro_arg) @variable +(macro_value) @constant.builtin +keyword: (_) @keyword + +(embedded_js_special_case_complete) @punctuation.special +(embedded_sql_marker) @punctuation.special +(embedded_sql_reverse_marker) @punctuation.special +(html_marker) @punctuation.special +(html_marker_reversed) @punctuation.special + +(attribute) @attribute + +(open_keywords) @attribute +(use_keywords) @attribute +(close_parameter_option_value) @attribute + +; Cannot combine all of these into a supertype as for some reason, it messes up the scanner and doesn't match correctly. +[ + (line_comment_1) + (line_comment_2) + (line_comment_3) + (line_comment_4) + (block_comment) +] @comment @spell + +(tag) @tag + +; ------------------ UDL ------------------- + +[ + (method_keyword_codemode_expression) + (call_method_keyword) + (method_keyword) + (class_keywords) + (query_keywords) + (trigger_keyword) + (method_keyword_language) + (relationship_keyword) + (foreignkey_keyword) + (parameter_keyword) + (projection_keyword) + (index_keyword) + (index_keyword_extent) + (xdata_keyword) + (xdata_keyword_mimetype) + (property_keyword) + +] @attribute + +(documatic_line) @comment.doc + +(query_name) @property +(property_name) @property +(relationship_name) @property +(foreignkey_name) @property +(parameter_name) @property +(projection_name) @property +(index_name) @property +(xdata_name) @property +(storage_name) @property + +(return_type) @type.builtin +(typename) @type +(parameter_type) @type.builtin +(index_type) @type.builtin +(projection_type) @type.builtin +(property_type) @type.builtin +(index_property_type) @type.builtin + +(identifier) @variable diff --git a/runtime/queries/objectscript/indents.scm b/runtime/queries/objectscript/indents.scm new file mode 100644 index 000000000..dc176fe94 --- /dev/null +++ b/runtime/queries/objectscript/indents.scm @@ -0,0 +1,2 @@ +("{" @indents.begin) +("}" @indents.end) \ No newline at end of file diff --git a/runtime/queries/objectscript/injections.scm b/runtime/queries/objectscript/injections.scm new file mode 100644 index 000000000..9aef5a1a8 --- /dev/null +++ b/runtime/queries/objectscript/injections.scm @@ -0,0 +1,192 @@ +; Core grammar injections +(embedded_html + (angled_bracket_fenced_text) @injection.content + (#set! injection.language "html") +) + +(embedded_sql + (_ + (paren_fenced_text) @injection.content + ) + (#set! injection.language "sql") +) + + (embedded_js + [ + (angled_bracket_fenced_text) + (embedded_js_special_case) + ] @injection.content + (#set! injection.language "javascript")) + + +(embedded_xml + (angled_bracket_fenced_text) @injection.content + (#set! injection.language "xml") +) + +([ + (line_comment_1) + (line_comment_2) + (line_comment_3) + (block_comment) +] @injection.content + (#set! injection.language "comment")) + + + +; UDL grammar injections +;; Keywords, one of type language = "python", none of type codemode +; External method body injection based on [ Language = ... ] +(method_definition + (external_method_keywords + (method_keyword_language + (rhs) @lang)) + (external_method_body_content) @injection.content + (#set! injection.include-children) + (#match? @lang "^[Pp][Yy][Tt][Hh][Oo][Nn]$") + (#set! injection.language "python")) + +(method_definition + (external_method_keywords + (method_keyword_language + (rhs) @lang)) + (external_method_body_content) @injection.content + (#set! injection.include-children) + (#match? @lang "^[Tt][Ss][Qq][Ll]$") + (#set! injection.language "tsql")) + +(method_definition + (external_method_keywords + (method_keyword_language + (rhs) @lang)) + (external_method_body_content) @injection.content + (#set! injection.include-children) + (#match? @lang "^[Ii][Ss][Pp][Ll]$") + (#set! injection.language "ispl")) + + + +;; External trigger with python body +( + (trigger + (external_trigger + (trigger_keywords + (method_keyword_language + (rhs) @lang)) + (external_method_body_content) @injection.content)) + (#set! injection.include-children) + (#match? @lang "^[Pp][Yy][Tt][Hh][Oo][Nn]$") + (#set! injection.language "python") +) + +;; External trigger with TSQL body +( + (trigger + (external_trigger + (trigger_keywords + (method_keyword_language + (rhs) @lang)) + (external_method_body_content) @injection.content)) + (#set! injection.include-children) + (#match? @lang "^[Tt][Ss][Qq][Ll]$") + (#set! injection.language) +) + +; A query must be of type %SQLQuery to have an SQL body, otherwise the body +; is empty +(query + (return_type + (typename + (identifier) @_querytype + (#match? @_querytype "^%[Ss][Qq][Ll][Qq][Uu][Ee][Rr][Yy]$"))) + (query_body + (query_body_content) @injection.content) + (#set! injection.language "sql") + (#set! injection.include-children) +) + +; XDATA blocks: +; - xdata_any requires a keyword list that includes MimeType +; - xdata_xml allows an optional keyword list and defaults to XML + +; ---------------------------- +; XDATA injections (MimeType) +; ---------------------------- + +; text/markdown +(xdata + (xdata_any + (xdata_keywords + (xdata_keyword_mimetype (rhs) @mt)) + (external_method_body_content) @injection.content) + (#set! injection.include-children) + (#match? @mt "^\"?text/markdown\"?$") + (#set! injection.language "markdown")) + +; XML MimeTypes +(xdata + (xdata_any + (xdata_keywords + (xdata_keyword_mimetype (rhs) @mt)) + (external_method_body_content) @injection.content) + (#set! injection.include-children) + (#match? @mt "^\"?([Tt][Ee][Xx][Tt]|[Aa][Pp][Pp][Ll][Ii][Cc][Aa][Tt][Ii][Oo][Nn])/[Xx][Mm][Ll]\"?$") + (#set! injection.language "xml")) + +; text/html +(xdata + (xdata_any + (xdata_keywords + (xdata_keyword_mimetype (rhs) @mt)) + (external_method_body_content) @injection.content) + (#set! injection.include-children) + (#match? @mt "^\"?text/html\"?$") + (#set! injection.language "html")) + +; application/json +(xdata + (xdata_any + (xdata_keywords + (xdata_keyword_mimetype (rhs) @mt)) + (external_method_body_content) @injection.content) + (#set! injection.include-children) + (#match? @mt "^\"?application/json\"?$") + (#set! injection.language "json")) + +; text/yaml or application/yaml +(xdata + (xdata_any + (xdata_keywords + (xdata_keyword_mimetype (rhs) @mt)) + (external_method_body_content) @injection.content) + (#set! injection.include-children) + (#match? @mt "^\"?([Tt][Ee][Xx][Tt]|[Aa][Pp][Pp][Ll][Ii][Cc][Aa][Tt][Ii][Oo][Nn])/[Yy][Aa][Mm][Ll]\"?$") + (#set! injection.language "yaml")) + +; text/css +(xdata + (xdata_any + (xdata_keywords + (xdata_keyword_mimetype (rhs) @mt)) + (external_method_body_content) @injection.content) + (#set! injection.include-children) + (#match? @mt "^\"?text/css\"?$") + (#set! injection.language "css")) + +; ----------------------------------------- +; XDATA default (no MimeType): XML fallback +; ----------------------------------------- +(xdata + (xdata_xml + (xdata_keywords)? + (external_method_body_content) @injection.content) + (#set! injection.include-children) + (#set! injection.language "xml")) + + +; Storage definition is XML +(storage + (storage_body + (external_method_body_content) @injection.content) + (#set! injection.language "xml") + (#set! injection.include-children))