From d1054de3ced44903c7bdcf5886d8481eb40a948f Mon Sep 17 00:00:00 2001 From: Novus Nota <68142933+novusnota@users.noreply.github.com> Date: Sun, 4 Feb 2024 02:09:11 +0100 Subject: [PATCH] feat: Add `Tact` language support (#9512) Re-submitting --- book/src/generated/lang-support.md | 1 + languages.toml | 19 ++ runtime/queries/tact/highlights.scm | 298 +++++++++++++++++++++++++++ runtime/queries/tact/indents.scm | 38 ++++ runtime/queries/tact/injections.scm | 5 + runtime/queries/tact/locals.scm | 35 ++++ runtime/queries/tact/textobjects.scm | 58 ++++++ 7 files changed, 454 insertions(+) create mode 100644 runtime/queries/tact/highlights.scm create mode 100644 runtime/queries/tact/indents.scm create mode 100644 runtime/queries/tact/injections.scm create mode 100644 runtime/queries/tact/locals.scm create mode 100644 runtime/queries/tact/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index a78dd7935bc3..e7d29cc7340c 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -162,6 +162,7 @@ | swift | ✓ | | | `sourcekit-lsp` | | t32 | ✓ | | | | | tablegen | ✓ | ✓ | ✓ | | +| tact | ✓ | ✓ | ✓ | | | task | ✓ | | | | | templ | ✓ | | | `templ` | | tfvars | ✓ | | ✓ | `terraform-ls` | diff --git a/languages.toml b/languages.toml index 1f26f1680b60..e601c20d95e3 100644 --- a/languages.toml +++ b/languages.toml @@ -3042,3 +3042,22 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "hocon" source = { git = "https://github.com/antosha417/tree-sitter-hocon", rev = "c390f10519ae69fdb03b3e5764f5592fb6924bcc" } + +[[language]] +name = "tact" +scope = "source.tact" +injection-regex = "tact" +file-types = ["tact"] +comment-token = "//" +indent = { tab-width = 4, unit = " " } + +[language.auto-pairs] +'"' = '"' +'{' = '}' +'(' = ')' +'<' = '>' + +[[grammar]] +name = "tact" +source = { git = "https://github.com/tact-lang/tree-sitter-tact", rev = "ec57ab29c86d632639726631fb2bb178d23e1c91" } + diff --git a/runtime/queries/tact/highlights.scm b/runtime/queries/tact/highlights.scm new file mode 100644 index 000000000000..53bf985b54b8 --- /dev/null +++ b/runtime/queries/tact/highlights.scm @@ -0,0 +1,298 @@ +; See: https://docs.helix-editor.com/master/themes.html#syntax-highlighting +; ------------------------------------------------------------------------- + +; attribute +; --------- + +[ + "@name" + "@interface" +] @attribute + +; comment.line +; ------------ + +((comment) @comment.line + (#match? @comment.line "^//")) + +; comment.block +; ------------- + +(comment) @comment.block + +; function.builtin +; ---------------- + +((identifier) @function.builtin + (#any-of? @function.builtin + "send" "sender" "require" "now" + "myBalance" "myAddress" "newAddress" + "contractAddress" "contractAddressExt" + "emit" "cell" "ton" + "beginString" "beginComment" "beginTailString" "beginStringFromBuilder" "beginCell" "emptyCell" + "randomInt" "random" + "checkSignature" "checkDataSignature" "sha256" + "min" "max" "abs" "pow" + "throw" "dump" "getConfigParam" + "nativeThrowWhen" "nativeThrowUnless" "nativeReserve" + "nativeRandomize" "nativeRandomizeLt" "nativePrepareRandom" "nativeRandom" "nativeRandomInterval") + (#is-not? local)) + +; function.method +; --------------- + +(method_call_expression + name: (identifier) @function.method) + +; function +; -------- + +(func_identifier) @function + +(native_function + name: (identifier) @function) + +(static_function + name: (identifier) @function) + +(static_call_expression + name: (identifier) @function) + +(init_function + "init" @function.method) + +(receive_function + "receive" @function.method) + +(bounced_function + "bounced" @function.method) + +(external_function + "external" @function.method) + +(function + name: (identifier) @function.method) + +; keyword.control.conditional +; --------------------------- + +[ + "if" "else" +] @keyword.control.conditional + +; keyword.control.repeat +; ---------------------- + +[ + "while" "repeat" "do" "until" +] @keyword.control.repeat + +; keyword.control.import +; ---------------------- + +"import" @keyword.control.import + +; keyword.control.return +; ---------------------- + +"return" @keyword.control.return + +; keyword.operator +; ---------------- + +"initOf" @keyword.operator + +; keyword.directive +; ----------------- + +"primitive" @keyword.directive + +; keyword.function +; ---------------- + +[ + "fun" + "native" +] @keyword.function + +; keyword.storage.type +; -------------------- + +[ + "contract" "trait" "struct" "message" "with" + "const" "let" +] @keyword.storage.type + +; keyword.storage.modifier +; ------------------------ + +[ + "get" "mutates" "extends" "virtual" "override" "inline" "abstract" +] @keyword.storage.modifier + +; keyword +; ------- + +[ + "with" + ; "public" ; -- not used, but declared in grammar.ohm + ; "extend" ; -- not used, but declared in grammar.ohm +] @keyword + +; constant.builtin.boolean +; ------------------------ + +(boolean) @constant.builtin.boolean + +; constant.builtin +; ---------------- + +((identifier) @constant.builtin + (#any-of? @constant.builtin + "SendPayGasSeparately" + "SendIgnoreErrors" + "SendDestroyIfZero" + "SendRemainingValue" + "SendRemainingBalance") + (#is-not? local)) + +(null) @constant.builtin + +; constant.numeric.integer +; ------------------------ + +(integer) @constant.numeric.integer + +; constant +; -------- + +(constant + name: (identifier) @constant) + +; string.special.path +; ------------------- + +(import_statement + library: (string) @string.special.path) + +; string +; ------ + +(string) @string + +; type.builtin +; ------------ + +(tlb_serialization + "as" @keyword + type: (identifier) @type.builtin + (#any-of? @type.builtin + "int8" "int16" "int32" "int64" "int128" "int256" "int257" + "uint8" "uint16" "uint32" "uint64" "uint128" "uint256" + "coins" "remaining" "bytes32" "bytes64")) + +((type_identifier) @type.builtin + (#any-of? @type.builtin + "Address" "Bool" "Builder" "Cell" "Int" "Slice" "String" "StringBuilder")) + +(map_type + "map" @type.builtin + "<" @punctuation.bracket + ">" @punctuation.bracket) + +(bounced_type + "bounced" @type.builtin + "<" @punctuation.bracket + ">" @punctuation.bracket) + +((identifier) @type.builtin + (#eq? @type.builtin "SendParameters") + (#is-not? local)) + +; type +; ---- + +(type_identifier) @type + +; constructor +; ----------- + +(instance_expression + name: (identifier) @constructor) + +(initOf + name: (identifier) @constructor) + +; operator +; -------- + +[ + "-" "-=" + "+" "+=" + "*" "*=" + "/" "/=" + "%" "%=" + "=" "==" + "!" "!=" "!!" + "<" "<=" "<<" + ">" ">=" ">>" + "&" "|" + "&&" "||" +] @operator + +; punctuation.bracket +; ------------------- + +[ + "(" ")" + "{" "}" +] @punctuation.bracket + +; punctuation.delimiter +; --------------------- + +[ + ";" + "," + "." + ":" + "?" +] @punctuation.delimiter + +; variable.other.member +; --------------------- + +(field + name: (identifier) @variable.other.member) + +(contract_body + (constant + name: (identifier) @variable.other.member)) + +(trait_body + (constant + name: (identifier) @variable.other.member)) + +(field_access_expression + name: (identifier) @variable.other.member) + +(lvalue (_) (_) @variable.other.member) + +(instance_argument + name: (identifier) @variable.other.member) + +; variable.parameter +; ------------------ + +(parameter + name: (identifier) @variable.parameter) + +; variable.builtin +; ---------------- + +(self) @variable.builtin + +; variable +; -------- + +(identifier) @variable diff --git a/runtime/queries/tact/indents.scm b/runtime/queries/tact/indents.scm new file mode 100644 index 000000000000..62c532b22304 --- /dev/null +++ b/runtime/queries/tact/indents.scm @@ -0,0 +1,38 @@ +; indent +; ------ + +[ + ; (..., ...) + (parameter_list) + (argument_list) + + ; {..., ...} + (instance_argument_list) + + ; {...; ...} + (message_body) + (struct_body) + (contract_body) + (trait_body) + (function_body) + (block_statement) + + ; misc. + (binary_expression) + (return_statement) +] @indent + +; outdent +; ------- + +[ + "}" + ")" + ">" +] @outdent + +; indent.always +; outdent.always +; align +; extend +; extend.prevent-once \ No newline at end of file diff --git a/runtime/queries/tact/injections.scm b/runtime/queries/tact/injections.scm new file mode 100644 index 000000000000..e61db3a56a4d --- /dev/null +++ b/runtime/queries/tact/injections.scm @@ -0,0 +1,5 @@ +; See: https://docs.helix-editor.com/guides/injection.html + +((comment) @injection.content + (#set! injection.language "comment") + (#match? @injection.content "^//")) \ No newline at end of file diff --git a/runtime/queries/tact/locals.scm b/runtime/queries/tact/locals.scm new file mode 100644 index 000000000000..f1b3e8de5fd0 --- /dev/null +++ b/runtime/queries/tact/locals.scm @@ -0,0 +1,35 @@ +; See: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#local-variables + +; Scopes @local.scope +; ------------------------- + +[ + (static_function) + (init_function) + (bounced_function) + (receive_function) + (external_function) + (function) + (block_statement) +] @local.scope + +; Definitions @local.definition +; ------------------------------ + +(let_statement + name: (identifier) @local.definition) + +(parameter + name: (identifier) @local.definition) + +(constant + name: (identifier) @local.definition) + +; References @local.reference +; ----------------------------- + +(self) @local.reference + +(value_expression (identifier) @local.reference) + +(lvalue (identifier) @local.reference) diff --git a/runtime/queries/tact/textobjects.scm b/runtime/queries/tact/textobjects.scm new file mode 100644 index 000000000000..54d07014e06e --- /dev/null +++ b/runtime/queries/tact/textobjects.scm @@ -0,0 +1,58 @@ +; function.inside & around +; ------------------------ + +(static_function + body: (_) @function.inside) @function.around + +(init_function + body: (_) @function.inside) @function.around + +(bounced_function + body: (_) @function.inside) @function.around + +(receive_function + body: (_) @function.inside) @function.around + +(external_function + body: (_) @function.inside) @function.around + +(function + body: (_) @function.inside) @function.around + +; class.inside & around +; --------------------- + +(struct + body: (_) @class.inside) @class.around + +(message + body: (_) @class.inside) @class.around + +(contract + body: (_) @class.inside) @class.around + +; NOTE: Marked as @definition.interface in tags, as it's semantically correct +(trait + body: (_) @class.inside) @class.around + +; parameter.inside & around +; ------------------------- + +(parameter_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(argument_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(instance_argument_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +; comment.inside +; -------------- + +(comment) @comment.inside + +; comment.around +; -------------- + +(comment)+ @comment.around \ No newline at end of file