From f83843ceba65f7719d8b208eda0ebf15fae77603 Mon Sep 17 00:00:00 2001 From: Michael Daffin Date: Wed, 23 Feb 2022 14:25:44 +0000 Subject: Add kotlin language (#1689) * 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. * Update lang-support doc * Updates the kotlin highlight query to use helixs scopes * Updates the queries from PR feedback * Adds 'shallow = true' to gitmodules * Removes kotlin locals.scm * Remove blank line Co-authored-by: Ivan Tham Co-authored-by: Ivan Tham --- runtime/queries/kotlin/folds.scm | 17 ++ runtime/queries/kotlin/highlights.scm | 295 ++++++++++++++++++++++++++++++++++ runtime/queries/kotlin/injections.scm | 36 +++++ 3 files changed, 348 insertions(+) create mode 100644 runtime/queries/kotlin/folds.scm create mode 100644 runtime/queries/kotlin/highlights.scm create mode 100644 runtime/queries/kotlin/injections.scm (limited to 'runtime/queries/kotlin') diff --git a/runtime/queries/kotlin/folds.scm b/runtime/queries/kotlin/folds.scm new file mode 100644 index 00000000..768972b8 --- /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 00000000..7b90fcf9 --- /dev/null +++ b/runtime/queries/kotlin/highlights.scm @@ -0,0 +1,295 @@ +;;; Operators & Punctuation + +(multi_line_string_literal + "$" @punctuation + (interpolated_identifier) @none) +(multi_line_string_literal + "${" @punctuation + (interpolated_expression) @none + "}" @punctuation.) + +; 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) + +[ + "." + "," + ";" + ":" + "::" +] @punctuation.delimiter + +[ + "(" ")" + "[" "]" + "{" "}" +] @punctuation.bracket + +[ + "!" + "!=" + "!==" + "=" + "==" + "===" + ">" + ">=" + "<" + "<=" + "||" + "&&" + "+" + "++" + "+=" + "-" + "--" + "-=" + "*" + "*=" + "/" + "/=" + "%" + "%=" + "?." + "?:" + "!!" + "is" + "!is" + "in" + "!in" + "as" + "as?" + ".." + "->" +] @operator + +;;; 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.control.return + +[ + "if" + "else" + "when" +] @keyword.control.conditional + +[ + "for" + "do" + "while" +] @keyword.control.repeat + +[ + "try" + "catch" + "throw" + "finally" +] @keyword.control.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))) + +;;; Literals +; NOTE: Escapes not allowed in multi-line strings +(line_string_literal (character_escape_seq) @constant.character.escape) + +[ + (line_string_literal) + (multi_line_string_literal) +] @string + +(character_literal) @constant.character + +[ + "null" ; should be highlighted the same as booleans + (boolean_literal) +] @constant.builtin.boolean + +(real_literal) @constant.numeric.float +[ + (integer_literal) + (long_literal) + (hex_literal) + (bin_literal) + (unsigned_literal) +] @constant.numeric.integer + +[ + (comment) + (shebang_line) +] @comment + +;;; Function calls + +(call_expression + . (simple_identifier) @function.builtin + (#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 + (navigation_expression + (navigation_suffix + (simple_identifier) @function) . )) + +; function() +(call_expression + . (simple_identifier) @function) + +;;; Function definitions + +; 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) + +(constructor_invocation + (user_type + (type_identifier) @constructor)) + +(secondary_constructor + ("constructor") @constructor) +(primary_constructor) @constructor + +(getter + ("get") @function.builtin) +(setter + ("set") @function.builtin) + +(function_declaration + . (simple_identifier) @function) + +; TODO: Seperate labeled returns/breaks/continue/super/this +; Must be implemented in the parser first +(label) @label + +(import_header + (identifier + (simple_identifier) @function @_import .) + (import_alias + (type_identifier) @function)? + (#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 +(import_header + (identifier + (simple_identifier) @type @_import) + (import_alias + (type_identifier) @type)? + (#match? @_import "^[A-Z]")) + +(import_header + "import" @keyword.control.import) + +(package_header + . (identifier)) @namespace + +((type_identifier) @type.builtin + (#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 + +(enum_entry + (simple_identifier) @constant) + +(_ + (navigation_suffix + (simple_identifier) @constant + (#match? @constant "^[A-Z][A-Z0-9_]*$"))) + +; SCREAMING CASE identifiers are assumed to be constants +((simple_identifier) @constant +(#match? @constant "^[A-Z][A-Z0-9_]*$")) + +; id_1.id_2.id_3: `id_2` and `id_3` are assumed as object properties +(_ + (navigation_suffix + (simple_identifier) @variable.other.member)) + +(class_body + (property_declaration + (variable_declaration + (simple_identifier) @variable.other.member))) + +(class_parameter + (simple_identifier) @variable.other.member) + +; `super` keyword inside classes +(super_expression) @variable.builtin + +; `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 diff --git a/runtime/queries/kotlin/injections.scm b/runtime/queries/kotlin/injections.scm new file mode 100644 index 00000000..abdc2050 --- /dev/null +++ b/runtime/queries/kotlin/injections.scm @@ -0,0 +1,36 @@ +((comment) @injection.content + (#set! injection.language "comment")) + +; There are 3 ways to define a regex +; - "[abc]?".toRegex() +((call_expression + (navigation_expression + ([(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 + ((simple_identifier) @_function + (#eq? @_function "Regex")) + (call_suffix + (value_arguments + (value_argument + [ (line_string_literal) (multi_line_string_literal) ] @injection.content)))) + (#set! injection.language "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) ] @injection.content)))) + (#set! injection.language "regex")) -- cgit v1.2.3-70-g09d2