From 3eaf7ee7086231ccd66ec9123cac258bc2b736c5 Mon Sep 17 00:00:00 2001 From: Michael Daffin Date: Mon, 21 Feb 2022 13:58:24 +0000 Subject: [PATCH 1/7] Add kotlin language Queries taken from https://github.com/nvim-treesitter/nvim-treesitter/blob/master/queries/kotlin seem to work well enough for my needs though I don't use kotlin heavily. --- .gitmodules | 3 + helix-syntax/languages/tree-sitter-kotlin | 1 + languages.toml | 10 + runtime/queries/kotlin/folds.scm | 17 + runtime/queries/kotlin/highlights.scm | 409 ++++++++++++++++++++++ runtime/queries/kotlin/injections.scm | 32 ++ runtime/queries/kotlin/locals.scm | 83 +++++ 7 files changed, 555 insertions(+) create mode 160000 helix-syntax/languages/tree-sitter-kotlin create mode 100644 runtime/queries/kotlin/folds.scm create mode 100644 runtime/queries/kotlin/highlights.scm create mode 100644 runtime/queries/kotlin/injections.scm create mode 100644 runtime/queries/kotlin/locals.scm diff --git a/.gitmodules b/.gitmodules index 5b6609a80d6d..336cec2aca2f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -229,3 +229,6 @@ [submodule "helix-syntax/languages/tree-sitter-erlang"] path = helix-syntax/languages/tree-sitter-erlang url = https://github.com/the-mikedavis/tree-sitter-erlang +[submodule "helix-syntax/languages/tree-sitter-kotlin"] + path = helix-syntax/languages/tree-sitter-kotlin + url = https://github.com/fwcd/tree-sitter-kotlin.git diff --git a/helix-syntax/languages/tree-sitter-kotlin b/helix-syntax/languages/tree-sitter-kotlin new file mode 160000 index 000000000000..a4f71eb9b8c9 --- /dev/null +++ b/helix-syntax/languages/tree-sitter-kotlin @@ -0,0 +1 @@ +Subproject commit a4f71eb9b8c9b19ded3e0e9470be4b1b77c2b569 diff --git a/languages.toml b/languages.toml index 35758566a4a4..b8673a0372d1 100644 --- a/languages.toml +++ b/languages.toml @@ -741,3 +741,13 @@ file-types = ["erl", "hrl", "app", "rebar.config"] roots = ["rebar.config"] comment-token = "%%" indent = { tab-width = 4, unit = " " } + + +[[language]] +name = "kotlin" +scope = "source.kotlin" +file-types = ["kt", "kts"] +roots = ["settings.gradle", "settings.gradle.kts"] +comment-token = "//" +indent = { tab-width = 4, unit = " " } +language-server = { command = "kotlin-language-server" } diff --git a/runtime/queries/kotlin/folds.scm b/runtime/queries/kotlin/folds.scm new file mode 100644 index 000000000000..768972b8b13d --- /dev/null +++ b/runtime/queries/kotlin/folds.scm @@ -0,0 +1,17 @@ +[ + (import_list) + + (when_expression) + (control_structure_body) + + (lambda_literal) + (function_body) + (primary_constructor) + (secondary_constructor) + (anonymous_initializer) + + (class_body) + (enum_class_body) + + (interpolated_expression) +] @fold diff --git a/runtime/queries/kotlin/highlights.scm b/runtime/queries/kotlin/highlights.scm new file mode 100644 index 000000000000..2567a74c1f73 --- /dev/null +++ b/runtime/queries/kotlin/highlights.scm @@ -0,0 +1,409 @@ +;;; Identifiers + +(simple_identifier) @variable + +; `it` keyword inside lambdas +; FIXME: This will highlight the keyword outside of lambdas since tree-sitter +; does not allow us to check for arbitrary nestation +((simple_identifier) @variable.builtin +(#eq? @variable.builtin "it")) + +; `field` keyword inside property getter/setter +; FIXME: This will highlight the keyword outside of getters and setters +; since tree-sitter does not allow us to check for arbitrary nestation +((simple_identifier) @variable.builtin +(#eq? @variable.builtin "field")) + +; `this` this keyword inside classes +(this_expression) @variable.builtin + +; `super` keyword inside classes +(super_expression) @variable.builtin + +(class_parameter + (simple_identifier) @property) + +(class_body + (property_declaration + (variable_declaration + (simple_identifier) @property))) + +; id_1.id_2.id_3: `id_2` and `id_3` are assumed as object properties +(_ + (navigation_suffix + (simple_identifier) @property)) + +; SCREAMING CASE identifiers are assumed to be constants +((simple_identifier) @constant +(#lua-match? @constant "^[A-Z][A-Z0-9_]*$")) + +(_ + (navigation_suffix + (simple_identifier) @constant + (#lua-match? @constant "^[A-Z][A-Z0-9_]*$"))) + +(enum_entry + (simple_identifier) @constant) + +(type_identifier) @type + +((type_identifier) @type.builtin + (#any-of? @type.builtin + "Byte" + "Short" + "Int" + "Long" + "UByte" + "UShort" + "UInt" + "ULong" + "Float" + "Double" + "Boolean" + "Char" + "String" + "Array" + "ByteArray" + "ShortArray" + "IntArray" + "LongArray" + "UByteArray" + "UShortArray" + "UIntArray" + "ULongArray" + "FloatArray" + "DoubleArray" + "BooleanArray" + "CharArray" + "Map" + "Set" + "List" + "EmptyMap" + "EmptySet" + "EmptyList" + "MutableMap" + "MutableSet" + "MutableList" +)) + +(package_header + . (identifier)) @namespace + +(import_header + "import" @include) + +; The last `simple_identifier` in a `import_header` will always either be a function +; or a type. Classes can appear anywhere in the import path, unlike functions +(import_header + (identifier + (simple_identifier) @type @_import) + (import_alias + (type_identifier) @type)? + (#lua-match? @_import "^[A-Z]")) + +(import_header + (identifier + (simple_identifier) @function @_import .) + (import_alias + (type_identifier) @function)? + (#lua-match? @_import "^[a-z]")) + +; TODO: Seperate labeled returns/breaks/continue/super/this +; Must be implemented in the parser first +(label) @label + +;;; Function definitions + +(function_declaration + . (simple_identifier) @function) + +(getter + ("get") @function.builtin) +(setter + ("set") @function.builtin) + +(primary_constructor) @constructor +(secondary_constructor + ("constructor") @constructor) + +(constructor_invocation + (user_type + (type_identifier) @constructor)) + +(anonymous_initializer + ("init") @constructor) + +(parameter + (simple_identifier) @parameter) + +(parameter_with_optional_type + (simple_identifier) @parameter) + +; lambda parameters +(lambda_literal + (lambda_parameters + (variable_declaration + (simple_identifier) @parameter))) + +;;; Function calls + +; function() +(call_expression + . (simple_identifier) @function) + +; object.function() or object.property.function() +(call_expression + (navigation_expression + (navigation_suffix + (simple_identifier) @function) . )) + +(call_expression + . (simple_identifier) @function.builtin + (#any-of? @function.builtin + "arrayOf" + "arrayOfNulls" + "byteArrayOf" + "shortArrayOf" + "intArrayOf" + "longArrayOf" + "ubyteArrayOf" + "ushortArrayOf" + "uintArrayOf" + "ulongArrayOf" + "floatArrayOf" + "doubleArrayOf" + "booleanArrayOf" + "charArrayOf" + "emptyArray" + "mapOf" + "setOf" + "listOf" + "emptyMap" + "emptySet" + "emptyList" + "mutableMapOf" + "mutableSetOf" + "mutableListOf" + "print" + "println" + "error" + "TODO" + "run" + "runCatching" + "repeat" + "lazy" + "lazyOf" + "enumValues" + "enumValueOf" + "assert" + "check" + "checkNotNull" + "require" + "requireNotNull" + "with" + "suspend" + "synchronized" +)) + +;;; Literals + +[ + (comment) + (shebang_line) +] @comment + +(real_literal) @float +[ + (integer_literal) + (long_literal) + (hex_literal) + (bin_literal) + (unsigned_literal) +] @number + +[ + "null" ; should be highlighted the same as booleans + (boolean_literal) +] @boolean + +(character_literal) @character + +[ + (line_string_literal) + (multi_line_string_literal) +] @string + +; NOTE: Escapes not allowed in multi-line strings +(line_string_literal (character_escape_seq) @string.escape) + +; There are 3 ways to define a regex +; - "[abc]?".toRegex() +(call_expression + (navigation_expression + ([(line_string_literal) (multi_line_string_literal)] @string.regex) + (navigation_suffix + ((simple_identifier) @_function + (#eq? @_function "toRegex"))))) + +; - Regex("[abc]?") +(call_expression + ((simple_identifier) @_function + (#eq? @_function "Regex")) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) + +; - Regex.fromLiteral("[abc]?") +(call_expression + (navigation_expression + ((simple_identifier) @_class + (#eq? @_class "Regex")) + (navigation_suffix + ((simple_identifier) @_function + (#eq? @_function "fromLiteral")))) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) + +;;; Keywords + +(type_alias "typealias" @keyword) +[ + (class_modifier) + (member_modifier) + (function_modifier) + (property_modifier) + (platform_modifier) + (variance_modifier) + (parameter_modifier) + (visibility_modifier) + (reification_modifier) + (inheritance_modifier) +]@keyword + +[ + "val" + "var" + "enum" + "class" + "object" + "interface" +; "typeof" ; NOTE: It is reserved for future use +] @keyword + +("fun") @keyword.function + +(jump_expression) @keyword.return + +[ + "if" + "else" + "when" +] @conditional + +[ + "for" + "do" + "while" +] @repeat + +[ + "try" + "catch" + "throw" + "finally" +] @exception + + +(annotation + "@" @attribute (use_site_target)? @attribute) +(annotation + (user_type + (type_identifier) @attribute)) +(annotation + (constructor_invocation + (user_type + (type_identifier) @attribute))) + +(file_annotation + "@" @attribute "file" @attribute ":" @attribute) +(file_annotation + (user_type + (type_identifier) @attribute)) +(file_annotation + (constructor_invocation + (user_type + (type_identifier) @attribute))) + +;;; Operators & Punctuation + +[ + "!" + "!=" + "!==" + "=" + "==" + "===" + ">" + ">=" + "<" + "<=" + "||" + "&&" + "+" + "++" + "+=" + "-" + "--" + "-=" + "*" + "*=" + "/" + "/=" + "%" + "%=" + "?." + "?:" + "!!" + "is" + "!is" + "in" + "!in" + "as" + "as?" + ".." + "->" +] @operator + +[ + "(" ")" + "[" "]" + "{" "}" +] @punctuation.bracket + +[ + "." + "," + ";" + ":" + "::" +] @punctuation.delimiter + +; NOTE: `interpolated_identifier`s can be highlighted in any way +(line_string_literal + "$" @punctuation.special + (interpolated_identifier) @none) +(line_string_literal + "${" @punctuation.special + (interpolated_expression) @none + "}" @punctuation.special) + +(multi_line_string_literal + "$" @punctuation.special + (interpolated_identifier) @none) +(multi_line_string_literal + "${" @punctuation.special + (interpolated_expression) @none + "}" @punctuation.special) diff --git a/runtime/queries/kotlin/injections.scm b/runtime/queries/kotlin/injections.scm new file mode 100644 index 000000000000..371345cfd01c --- /dev/null +++ b/runtime/queries/kotlin/injections.scm @@ -0,0 +1,32 @@ +(comment) @comment + +; There are 3 ways to define a regex +; - "[abc]?".toRegex() +(call_expression + (navigation_expression + ([(line_string_literal) (multi_line_string_literal)] @regex) + (navigation_suffix + ((simple_identifier) @_function + (#eq? @_function "toRegex"))))) + +; - Regex("[abc]?") +(call_expression + ((simple_identifier) @_function + (#eq? @_function "Regex")) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @regex)))) + +; - Regex.fromLiteral("[abc]?") +(call_expression + (navigation_expression + ((simple_identifier) @_class + (#eq? @_class "Regex")) + (navigation_suffix + ((simple_identifier) @_function + (#eq? @_function "fromLiteral")))) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @regex)))) diff --git a/runtime/queries/kotlin/locals.scm b/runtime/queries/kotlin/locals.scm new file mode 100644 index 000000000000..d1b45f276e1c --- /dev/null +++ b/runtime/queries/kotlin/locals.scm @@ -0,0 +1,83 @@ +;;; Imports + +(package_header + . (identifier) @definition.namespace) + +(import_header + (identifier + (simple_identifier) @definition.import .) + (import_alias + (type_identifier) @definition.import)?) + +;;; Functions + +(function_declaration + . (simple_identifier) @definition.function + (#set! "definition.function.scope" "parent")) + +(class_body + (function_declaration + . (simple_identifier) @definition.method) + (#set! "definition.method.scope" "parent")) + +;;; Variables + +(function_declaration + (parameter + (simple_identifier) @definition.parameter)) + +(lambda_literal + (lambda_parameters + (variable_declaration + (simple_identifier) @definition.parameter))) + +(class_body + (property_declaration + (variable_declaration + (simple_identifier) @definition.field))) + +(class_declaration + (primary_constructor + (class_parameter + (simple_identifier) @definition.field))) + +(enum_class_body + (enum_entry + (simple_identifier) @definition.field)) + +(variable_declaration + (simple_identifier) @definition.var) + +;;; Types + +(class_declaration + (type_identifier) @definition.type + (#set! "definition.type.scope" "parent")) + +(type_alias + (type_identifier) @definition.type + (#set! "definition.type.scope" "parent")) + +;;; Scopes + +[ + (if_expression) + (when_expression) + (when_entry) + + (for_statement) + (while_statement) + (do_while_statement) + + (lambda_literal) + (function_declaration) + (primary_constructor) + (secondary_constructor) + (anonymous_initializer) + + (class_declaration) + (enum_class_body) + (enum_entry) + + (interpolated_expression) +] @scope From f1cfd2f429185f303b04493788c58100dd750470 Mon Sep 17 00:00:00 2001 From: Michael Daffin Date: Mon, 21 Feb 2022 15:07:28 +0000 Subject: [PATCH 2/7] Update lang-support doc --- book/src/generated/lang-support.md | 1 + 1 file changed, 1 insertion(+) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 89405073135b..4953821529ad 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -27,6 +27,7 @@ | javascript | ✓ | | ✓ | `typescript-language-server` | | json | ✓ | | ✓ | | | julia | ✓ | | | `julia` | +| kotlin | ✓ | | | `kotlin-language-server` | | latex | ✓ | | | | | lean | ✓ | | | `lean` | | ledger | ✓ | | | | From 8060db9d1ff8a373cbc24e49dc86e871147bd939 Mon Sep 17 00:00:00 2001 From: Michael Daffin Date: Mon, 21 Feb 2022 20:18:08 +0000 Subject: [PATCH 3/7] Updates the kotlin highlight query to use helixs scopes --- runtime/queries/kotlin/highlights.scm | 621 +++++++++++++------------- 1 file changed, 309 insertions(+), 312 deletions(-) diff --git a/runtime/queries/kotlin/highlights.scm b/runtime/queries/kotlin/highlights.scm index 2567a74c1f73..3f2d21bf8ce4 100644 --- a/runtime/queries/kotlin/highlights.scm +++ b/runtime/queries/kotlin/highlights.scm @@ -1,162 +1,206 @@ -;;; Identifiers - -(simple_identifier) @variable - -; `it` keyword inside lambdas -; FIXME: This will highlight the keyword outside of lambdas since tree-sitter -; does not allow us to check for arbitrary nestation -((simple_identifier) @variable.builtin -(#eq? @variable.builtin "it")) - -; `field` keyword inside property getter/setter -; FIXME: This will highlight the keyword outside of getters and setters -; since tree-sitter does not allow us to check for arbitrary nestation -((simple_identifier) @variable.builtin -(#eq? @variable.builtin "field")) +;;; Operators & Punctuation -; `this` this keyword inside classes -(this_expression) @variable.builtin +(multi_line_string_literal + "$" @punctuation + (interpolated_identifier) @none) +(multi_line_string_literal + "${" @punctuation + (interpolated_expression) @none + "}" @punctuation.) -; `super` keyword inside classes -(super_expression) @variable.builtin +; NOTE: `interpolated_identifier`s can be highlighted in any way +(line_string_literal + "$" @punctuation + (interpolated_identifier) @none) +(line_string_literal + "${" @punctuation + (interpolated_expression) @none + "}" @punctuation) -(class_parameter - (simple_identifier) @property) +[ + "." + "," + ";" + ":" + "::" +] @punctuation.delimiter -(class_body - (property_declaration - (variable_declaration - (simple_identifier) @property))) +[ + "(" ")" + "[" "]" + "{" "}" +] @punctuation.bracket -; id_1.id_2.id_3: `id_2` and `id_3` are assumed as object properties -(_ - (navigation_suffix - (simple_identifier) @property)) +[ + "!" + "!=" + "!==" + "=" + "==" + "===" + ">" + ">=" + "<" + "<=" + "||" + "&&" + "+" + "++" + "+=" + "-" + "--" + "-=" + "*" + "*=" + "/" + "/=" + "%" + "%=" + "?." + "?:" + "!!" + "is" + "!is" + "in" + "!in" + "as" + "as?" + ".." + "->" +] @operator -; SCREAMING CASE identifiers are assumed to be constants -((simple_identifier) @constant -(#lua-match? @constant "^[A-Z][A-Z0-9_]*$")) +;;; Keywords -(_ - (navigation_suffix - (simple_identifier) @constant - (#lua-match? @constant "^[A-Z][A-Z0-9_]*$"))) +(type_alias "typealias" @keyword) +[ + (class_modifier) + (member_modifier) + (function_modifier) + (property_modifier) + (platform_modifier) + (variance_modifier) + (parameter_modifier) + (visibility_modifier) + (reification_modifier) + (inheritance_modifier) +]@keyword -(enum_entry - (simple_identifier) @constant) +[ + "val" + "var" + "enum" + "class" + "object" + "interface" +; "typeof" ; NOTE: It is reserved for future use +] @keyword -(type_identifier) @type +("fun") @keyword.function -((type_identifier) @type.builtin - (#any-of? @type.builtin - "Byte" - "Short" - "Int" - "Long" - "UByte" - "UShort" - "UInt" - "ULong" - "Float" - "Double" - "Boolean" - "Char" - "String" - "Array" - "ByteArray" - "ShortArray" - "IntArray" - "LongArray" - "UByteArray" - "UShortArray" - "UIntArray" - "ULongArray" - "FloatArray" - "DoubleArray" - "BooleanArray" - "CharArray" - "Map" - "Set" - "List" - "EmptyMap" - "EmptySet" - "EmptyList" - "MutableMap" - "MutableSet" - "MutableList" -)) +(jump_expression) @keyword.control.return -(package_header - . (identifier)) @namespace +[ + "if" + "else" + "when" +] @keyword.control.conditional -(import_header - "import" @include) +[ + "for" + "do" + "while" +] @keyword.control.repeat -; The last `simple_identifier` in a `import_header` will always either be a function -; or a type. Classes can appear anywhere in the import path, unlike functions -(import_header - (identifier - (simple_identifier) @type @_import) - (import_alias - (type_identifier) @type)? - (#lua-match? @_import "^[A-Z]")) +[ + "try" + "catch" + "throw" + "finally" +] @keyword.control.exception -(import_header - (identifier - (simple_identifier) @function @_import .) - (import_alias - (type_identifier) @function)? - (#lua-match? @_import "^[a-z]")) +(annotation + "@" @attribute (use_site_target)? @attribute) +(annotation + (user_type + (type_identifier) @attribute)) +(annotation + (constructor_invocation + (user_type + (type_identifier) @attribute))) -; TODO: Seperate labeled returns/breaks/continue/super/this -; Must be implemented in the parser first -(label) @label +(file_annotation + "@" @attribute "file" @attribute ":" @attribute) +(file_annotation + (user_type + (type_identifier) @attribute)) +(file_annotation + (constructor_invocation + (user_type + (type_identifier) @attribute))) -;;; Function definitions +;;; Literals +; - Regex.fromLiteral("[abc]?") +(call_expression + (navigation_expression + ((simple_identifier) @_class + (#eq? @_class "Regex")) + (navigation_suffix + ((simple_identifier) @_function + (#eq? @_function "fromLiteral")))) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) -(function_declaration - . (simple_identifier) @function) +; - Regex("[abc]?") +(call_expression + ((simple_identifier) @_function + (#eq? @_function "Regex")) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) -(getter - ("get") @function.builtin) -(setter - ("set") @function.builtin) +; There are 3 ways to define a regex +; - "[abc]?".toRegex() +(call_expression + (navigation_expression + ([(line_string_literal) (multi_line_string_literal)] @string.regex) + (navigation_suffix + ((simple_identifier) @_function + (#eq? @_function "toRegex"))))) -(primary_constructor) @constructor -(secondary_constructor - ("constructor") @constructor) +; NOTE: Escapes not allowed in multi-line strings +(line_string_literal (character_escape_seq) @constant.character.escape) -(constructor_invocation - (user_type - (type_identifier) @constructor)) +[ + (line_string_literal) + (multi_line_string_literal) +] @string -(anonymous_initializer - ("init") @constructor) +(character_literal) @constant.character -(parameter - (simple_identifier) @parameter) +[ + "null" ; should be highlighted the same as booleans + (boolean_literal) +] @constant.builtin.boolean -(parameter_with_optional_type - (simple_identifier) @parameter) +(real_literal) @constant.numeric.float +[ + (integer_literal) + (long_literal) + (hex_literal) + (bin_literal) + (unsigned_literal) +] @constant.numeric.integer -; lambda parameters -(lambda_literal - (lambda_parameters - (variable_declaration - (simple_identifier) @parameter))) +[ + (comment) + (shebang_line) +] @comment ;;; Function calls -; function() -(call_expression - . (simple_identifier) @function) - -; object.function() or object.property.function() -(call_expression - (navigation_expression - (navigation_suffix - (simple_identifier) @function) . )) - (call_expression . (simple_identifier) @function.builtin (#any-of? @function.builtin @@ -204,206 +248,159 @@ "suspend" "synchronized" )) - -;;; Literals - -[ - (comment) - (shebang_line) -] @comment - -(real_literal) @float -[ - (integer_literal) - (long_literal) - (hex_literal) - (bin_literal) - (unsigned_literal) -] @number - -[ - "null" ; should be highlighted the same as booleans - (boolean_literal) -] @boolean - -(character_literal) @character - -[ - (line_string_literal) - (multi_line_string_literal) -] @string - -; NOTE: Escapes not allowed in multi-line strings -(line_string_literal (character_escape_seq) @string.escape) - -; There are 3 ways to define a regex -; - "[abc]?".toRegex() + +; object.function() or object.property.function() (call_expression (navigation_expression - ([(line_string_literal) (multi_line_string_literal)] @string.regex) (navigation_suffix - ((simple_identifier) @_function - (#eq? @_function "toRegex"))))) + (simple_identifier) @function) . )) -; - Regex("[abc]?") +; function() (call_expression - ((simple_identifier) @_function - (#eq? @_function "Regex")) - (call_suffix - (value_arguments - (value_argument - [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) + . (simple_identifier) @function) -; - Regex.fromLiteral("[abc]?") -(call_expression - (navigation_expression - ((simple_identifier) @_class - (#eq? @_class "Regex")) - (navigation_suffix - ((simple_identifier) @_function - (#eq? @_function "fromLiteral")))) - (call_suffix - (value_arguments - (value_argument - [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) +;;; Function definitions -;;; Keywords +; lambda parameters +(lambda_literal + (lambda_parameters + (variable_declaration + (simple_identifier) @variable.parameter))) + +(parameter_with_optional_type + (simple_identifier) @variable.parameter) + +(parameter + (simple_identifier) @variable.parameter) + +(anonymous_initializer + ("init") @constructor) -(type_alias "typealias" @keyword) -[ - (class_modifier) - (member_modifier) - (function_modifier) - (property_modifier) - (platform_modifier) - (variance_modifier) - (parameter_modifier) - (visibility_modifier) - (reification_modifier) - (inheritance_modifier) -]@keyword +(constructor_invocation + (user_type + (type_identifier) @constructor)) + +(secondary_constructor + ("constructor") @constructor) +(primary_constructor) @constructor + +(getter + ("get") @function.builtin) +(setter + ("set") @function.builtin) -[ - "val" - "var" - "enum" - "class" - "object" - "interface" -; "typeof" ; NOTE: It is reserved for future use -] @keyword +(function_declaration + . (simple_identifier) @function) -("fun") @keyword.function +; TODO: Seperate labeled returns/breaks/continue/super/this +; Must be implemented in the parser first +(label) @label -(jump_expression) @keyword.return +(import_header + (identifier + (simple_identifier) @function @_import .) + (import_alias + (type_identifier) @function)? + (#lua-match? @_import "^[a-z]")) -[ - "if" - "else" - "when" -] @conditional +; The last `simple_identifier` in a `import_header` will always either be a function +; or a type. Classes can appear anywhere in the import path, unlike functions +(import_header + (identifier + (simple_identifier) @type @_import) + (import_alias + (type_identifier) @type)? + (#lua-match? @_import "^[A-Z]")) -[ - "for" - "do" - "while" -] @repeat +(import_header + "import" @keyword.control.import) -[ - "try" - "catch" - "throw" - "finally" -] @exception +(package_header + . (identifier)) @namespace + +((type_identifier) @type.builtin + (#any-of? @type.builtin + "Byte" + "Short" + "Int" + "Long" + "UByte" + "UShort" + "UInt" + "ULong" + "Float" + "Double" + "Boolean" + "Char" + "String" + "Array" + "ByteArray" + "ShortArray" + "IntArray" + "LongArray" + "UByteArray" + "UShortArray" + "UIntArray" + "ULongArray" + "FloatArray" + "DoubleArray" + "BooleanArray" + "CharArray" + "Map" + "Set" + "List" + "EmptyMap" + "EmptySet" + "EmptyList" + "MutableMap" + "MutableSet" + "MutableList" +)) +(type_identifier) @type -(annotation - "@" @attribute (use_site_target)? @attribute) -(annotation - (user_type - (type_identifier) @attribute)) -(annotation - (constructor_invocation - (user_type - (type_identifier) @attribute))) +(enum_entry + (simple_identifier) @constant) -(file_annotation - "@" @attribute "file" @attribute ":" @attribute) -(file_annotation - (user_type - (type_identifier) @attribute)) -(file_annotation - (constructor_invocation - (user_type - (type_identifier) @attribute))) +(_ + (navigation_suffix + (simple_identifier) @constant + (#lua-match? @constant "^[A-Z][A-Z0-9_]*$"))) -;;; Operators & Punctuation +; SCREAMING CASE identifiers are assumed to be constants +((simple_identifier) @constant +(#lua-match? @constant "^[A-Z][A-Z0-9_]*$")) -[ - "!" - "!=" - "!==" - "=" - "==" - "===" - ">" - ">=" - "<" - "<=" - "||" - "&&" - "+" - "++" - "+=" - "-" - "--" - "-=" - "*" - "*=" - "/" - "/=" - "%" - "%=" - "?." - "?:" - "!!" - "is" - "!is" - "in" - "!in" - "as" - "as?" - ".." - "->" -] @operator +; id_1.id_2.id_3: `id_2` and `id_3` are assumed as object properties +(_ + (navigation_suffix + (simple_identifier) @variable.other.member)) -[ - "(" ")" - "[" "]" - "{" "}" -] @punctuation.bracket +(class_body + (property_declaration + (variable_declaration + (simple_identifier) @variable.other.member))) -[ - "." - "," - ";" - ":" - "::" -] @punctuation.delimiter +(class_parameter + (simple_identifier) @variable.other.member) -; NOTE: `interpolated_identifier`s can be highlighted in any way -(line_string_literal - "$" @punctuation.special - (interpolated_identifier) @none) -(line_string_literal - "${" @punctuation.special - (interpolated_expression) @none - "}" @punctuation.special) +; `super` keyword inside classes +(super_expression) @variable.builtin -(multi_line_string_literal - "$" @punctuation.special - (interpolated_identifier) @none) -(multi_line_string_literal - "${" @punctuation.special - (interpolated_expression) @none - "}" @punctuation.special) +; `this` this keyword inside classes +(this_expression) @variable.builtin + +;;; Identifiers +; `field` keyword inside property getter/setter +; FIXME: This will highlight the keyword outside of getters and setters +; since tree-sitter does not allow us to check for arbitrary nestation +((simple_identifier) @variable.builtin +(#eq? @variable.builtin "field")) + +; `it` keyword inside lambdas +; FIXME: This will highlight the keyword outside of lambdas since tree-sitter +; does not allow us to check for arbitrary nestation +((simple_identifier) @variable.builtin +(#eq? @variable.builtin "it")) + +(simple_identifier) @variable From af93586218eada40ccf16409003fdd155f338ac2 Mon Sep 17 00:00:00 2001 From: Michael Daffin Date: Tue, 22 Feb 2022 12:30:26 +0000 Subject: [PATCH 4/7] Updates the queries from PR feedback --- runtime/queries/kotlin/highlights.scm | 123 ++------------------------ runtime/queries/kotlin/injections.scm | 18 ++-- 2 files changed, 17 insertions(+), 124 deletions(-) diff --git a/runtime/queries/kotlin/highlights.scm b/runtime/queries/kotlin/highlights.scm index 3f2d21bf8ce4..7b90fcf929ad 100644 --- a/runtime/queries/kotlin/highlights.scm +++ b/runtime/queries/kotlin/highlights.scm @@ -139,37 +139,6 @@ (type_identifier) @attribute))) ;;; Literals -; - Regex.fromLiteral("[abc]?") -(call_expression - (navigation_expression - ((simple_identifier) @_class - (#eq? @_class "Regex")) - (navigation_suffix - ((simple_identifier) @_function - (#eq? @_function "fromLiteral")))) - (call_suffix - (value_arguments - (value_argument - [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) - -; - Regex("[abc]?") -(call_expression - ((simple_identifier) @_function - (#eq? @_function "Regex")) - (call_suffix - (value_arguments - (value_argument - [ (line_string_literal) (multi_line_string_literal) ] @string.regex)))) - -; There are 3 ways to define a regex -; - "[abc]?".toRegex() -(call_expression - (navigation_expression - ([(line_string_literal) (multi_line_string_literal)] @string.regex) - (navigation_suffix - ((simple_identifier) @_function - (#eq? @_function "toRegex"))))) - ; NOTE: Escapes not allowed in multi-line strings (line_string_literal (character_escape_seq) @constant.character.escape) @@ -203,51 +172,7 @@ (call_expression . (simple_identifier) @function.builtin - (#any-of? @function.builtin - "arrayOf" - "arrayOfNulls" - "byteArrayOf" - "shortArrayOf" - "intArrayOf" - "longArrayOf" - "ubyteArrayOf" - "ushortArrayOf" - "uintArrayOf" - "ulongArrayOf" - "floatArrayOf" - "doubleArrayOf" - "booleanArrayOf" - "charArrayOf" - "emptyArray" - "mapOf" - "setOf" - "listOf" - "emptyMap" - "emptySet" - "emptyList" - "mutableMapOf" - "mutableSetOf" - "mutableListOf" - "print" - "println" - "error" - "TODO" - "run" - "runCatching" - "repeat" - "lazy" - "lazyOf" - "enumValues" - "enumValueOf" - "assert" - "check" - "checkNotNull" - "require" - "requireNotNull" - "with" - "suspend" - "synchronized" -)) + (#match? @function.builtin "^(arrayOf|arrayOfNulls|byteArrayOf|shortArrayOf|intArrayOf|longArrayOf|ubyteArrayOf|ushortArrayOf|uintArrayOf|ulongArrayOf|floatArrayOf|doubleArrayOf|booleanArrayOf|charArrayOf|emptyArray|mapOf|setOf|listOf|emptyMap|emptySet|emptyList|mutableMapOf|mutableSetOf|mutableListOf|print|println|error|TODO|run|runCatching|repeat|lazy|lazyOf|enumValues|enumValueOf|assert|check|checkNotNull|require|requireNotNull|with|suspend|synchronized)$")) ; object.function() or object.property.function() (call_expression @@ -301,7 +226,7 @@ (simple_identifier) @function @_import .) (import_alias (type_identifier) @function)? - (#lua-match? @_import "^[a-z]")) + (#match? @_import "^[a-z]")) ; The last `simple_identifier` in a `import_header` will always either be a function ; or a type. Classes can appear anywhere in the import path, unlike functions @@ -310,7 +235,7 @@ (simple_identifier) @type @_import) (import_alias (type_identifier) @type)? - (#lua-match? @_import "^[A-Z]")) + (#match? @_import "^[A-Z]")) (import_header "import" @keyword.control.import) @@ -319,43 +244,7 @@ . (identifier)) @namespace ((type_identifier) @type.builtin - (#any-of? @type.builtin - "Byte" - "Short" - "Int" - "Long" - "UByte" - "UShort" - "UInt" - "ULong" - "Float" - "Double" - "Boolean" - "Char" - "String" - "Array" - "ByteArray" - "ShortArray" - "IntArray" - "LongArray" - "UByteArray" - "UShortArray" - "UIntArray" - "ULongArray" - "FloatArray" - "DoubleArray" - "BooleanArray" - "CharArray" - "Map" - "Set" - "List" - "EmptyMap" - "EmptySet" - "EmptyList" - "MutableMap" - "MutableSet" - "MutableList" -)) + (#match? @function.builtin "^(Byte|Short|Int|Long|UByte|UShort|UInt|ULong|Float|Double|Boolean|Char|String|Array|ByteArray|ShortArray|IntArray|LongArray|UByteArray|UShortArray|UIntArray|ULongArray|FloatArray|DoubleArray|BooleanArray|CharArray|Map|Set|List|EmptyMap|EmptySet|EmptyList|MutableMap|MutableSet|MutableList)$")) (type_identifier) @type @@ -365,11 +254,11 @@ (_ (navigation_suffix (simple_identifier) @constant - (#lua-match? @constant "^[A-Z][A-Z0-9_]*$"))) + (#match? @constant "^[A-Z][A-Z0-9_]*$"))) ; SCREAMING CASE identifiers are assumed to be constants ((simple_identifier) @constant -(#lua-match? @constant "^[A-Z][A-Z0-9_]*$")) +(#match? @constant "^[A-Z][A-Z0-9_]*$")) ; id_1.id_2.id_3: `id_2` and `id_3` are assumed as object properties (_ diff --git a/runtime/queries/kotlin/injections.scm b/runtime/queries/kotlin/injections.scm index 371345cfd01c..abdc20502448 100644 --- a/runtime/queries/kotlin/injections.scm +++ b/runtime/queries/kotlin/injections.scm @@ -1,25 +1,28 @@ -(comment) @comment +((comment) @injection.content + (#set! injection.language "comment")) ; There are 3 ways to define a regex ; - "[abc]?".toRegex() -(call_expression +((call_expression (navigation_expression - ([(line_string_literal) (multi_line_string_literal)] @regex) + ([(line_string_literal) (multi_line_string_literal)] @injection.content) (navigation_suffix ((simple_identifier) @_function (#eq? @_function "toRegex"))))) + (#set! injection.language "regex")) ; - Regex("[abc]?") -(call_expression +((call_expression ((simple_identifier) @_function (#eq? @_function "Regex")) (call_suffix (value_arguments (value_argument - [ (line_string_literal) (multi_line_string_literal) ] @regex)))) + [ (line_string_literal) (multi_line_string_literal) ] @injection.content)))) + (#set! injection.language "regex")) ; - Regex.fromLiteral("[abc]?") -(call_expression +((call_expression (navigation_expression ((simple_identifier) @_class (#eq? @_class "Regex")) @@ -29,4 +32,5 @@ (call_suffix (value_arguments (value_argument - [ (line_string_literal) (multi_line_string_literal) ] @regex)))) + [ (line_string_literal) (multi_line_string_literal) ] @injection.content)))) + (#set! injection.language "regex")) From faf266e895ea7ab48ac605e6236218d7137f995b Mon Sep 17 00:00:00 2001 From: Michael Daffin Date: Tue, 22 Feb 2022 12:31:30 +0000 Subject: [PATCH 5/7] Adds 'shallow = true' to gitmodules --- .gitmodules | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 336cec2aca2f..fa1e0900ac91 100644 --- a/.gitmodules +++ b/.gitmodules @@ -209,7 +209,7 @@ [submodule "helix-syntax/languages/tree-sitter-graphql"] path = helix-syntax/languages/tree-sitter-graphql url = https://github.com/bkegley/tree-sitter-graphql - shallow = true + shallow = true [submodule "helix-syntax/languages/tree-sitter-elm"] path = helix-syntax/languages/tree-sitter-elm url = https://github.com/elm-tooling/tree-sitter-elm @@ -229,6 +229,8 @@ [submodule "helix-syntax/languages/tree-sitter-erlang"] path = helix-syntax/languages/tree-sitter-erlang url = https://github.com/the-mikedavis/tree-sitter-erlang + shallow = true [submodule "helix-syntax/languages/tree-sitter-kotlin"] path = helix-syntax/languages/tree-sitter-kotlin url = https://github.com/fwcd/tree-sitter-kotlin.git + shallow = true From 2574d8b5e52527f0999793ea4d89206ef4a648c3 Mon Sep 17 00:00:00 2001 From: Michael Daffin Date: Wed, 23 Feb 2022 10:11:04 +0000 Subject: [PATCH 6/7] Removes kotlin locals.scm --- runtime/queries/kotlin/locals.scm | 83 ------------------------------- 1 file changed, 83 deletions(-) delete mode 100644 runtime/queries/kotlin/locals.scm diff --git a/runtime/queries/kotlin/locals.scm b/runtime/queries/kotlin/locals.scm deleted file mode 100644 index d1b45f276e1c..000000000000 --- a/runtime/queries/kotlin/locals.scm +++ /dev/null @@ -1,83 +0,0 @@ -;;; Imports - -(package_header - . (identifier) @definition.namespace) - -(import_header - (identifier - (simple_identifier) @definition.import .) - (import_alias - (type_identifier) @definition.import)?) - -;;; Functions - -(function_declaration - . (simple_identifier) @definition.function - (#set! "definition.function.scope" "parent")) - -(class_body - (function_declaration - . (simple_identifier) @definition.method) - (#set! "definition.method.scope" "parent")) - -;;; Variables - -(function_declaration - (parameter - (simple_identifier) @definition.parameter)) - -(lambda_literal - (lambda_parameters - (variable_declaration - (simple_identifier) @definition.parameter))) - -(class_body - (property_declaration - (variable_declaration - (simple_identifier) @definition.field))) - -(class_declaration - (primary_constructor - (class_parameter - (simple_identifier) @definition.field))) - -(enum_class_body - (enum_entry - (simple_identifier) @definition.field)) - -(variable_declaration - (simple_identifier) @definition.var) - -;;; Types - -(class_declaration - (type_identifier) @definition.type - (#set! "definition.type.scope" "parent")) - -(type_alias - (type_identifier) @definition.type - (#set! "definition.type.scope" "parent")) - -;;; Scopes - -[ - (if_expression) - (when_expression) - (when_entry) - - (for_statement) - (while_statement) - (do_while_statement) - - (lambda_literal) - (function_declaration) - (primary_constructor) - (secondary_constructor) - (anonymous_initializer) - - (class_declaration) - (enum_class_body) - (enum_entry) - - (interpolated_expression) -] @scope From 1bf00f24e016095a5aea125008fdb0be855a025e Mon Sep 17 00:00:00 2001 From: Michael Daffin Date: Wed, 23 Feb 2022 12:44:33 +0000 Subject: [PATCH 7/7] Remove blank line Co-authored-by: Ivan Tham --- languages.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/languages.toml b/languages.toml index b8673a0372d1..9876bcf10e59 100644 --- a/languages.toml +++ b/languages.toml @@ -742,7 +742,6 @@ roots = ["rebar.config"] comment-token = "%%" indent = { tab-width = 4, unit = " " } - [[language]] name = "kotlin" scope = "source.kotlin"