diff --git a/Cargo.toml b/Cargo.toml index 973eb3d..1e5ba68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zed_roc" -version = "0.0.5" +version = "0.1.1" authors = ["Alf Richter "] edition = "2021" diff --git a/README.md b/README.md index e757932..e51a69f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Roc lang support for Zed -> **Note:** This branch (`use-new-roc-lsp`) uses a fork of tree-sitter-roc with modern Roc syntax support. It is not ready to merge until the changes land upstream at [faldor20/tree-sitter-roc](https://github.com/faldor20/tree-sitter-roc). - An extension for Zed that adds Roc language support: - syntax highlighting through treesitter and @@ -16,7 +14,7 @@ An extension for Zed that adds Roc language support: ## ROC - Website: [roc-lang.org](https://roc-lang.org) -- Tree Sitter: [tree-sitter-roc](https://github.com/lukewilliamboswell/tree-sitter-roc) +- Tree Sitter: [tree-sitter-roc](https://github.com/faldor20/tree-sitter-roc) - Language Server: This extension uses the new experimental LSP integrated into the `roc` CLI via `roc experimental-lsp`. ## Development diff --git a/extension.toml b/extension.toml index 5d1a38e..f4d259a 100644 --- a/extension.toml +++ b/extension.toml @@ -1,15 +1,15 @@ id = "roc" name = "Roc" description = "Roc language support for Zed" -version = "0.1.0" +version = "0.1.1" schema_version = 1 authors = ["Alf Richter "] repository = "https://github.com/h2000/zed-roc" languages = ["languages/roc"] [grammars.roc] -repository = "https://github.com/lukewilliamboswell/tree-sitter-roc" -commit = "80b6bbe1bab45396db0943db410b97e6f4579801" +repository = "https://github.com/faldor20/tree-sitter-roc" +commit = "edc18052a9d7382ac9f9f5bf413db3a78d5ea12c" [language_servers.roc] language = "Roc" diff --git a/languages/roc/highlights.scm b/languages/roc/highlights.scm index 44c4d97..fb3fd50 100644 --- a/languages/roc/highlights.scm +++ b/languages/roc/highlights.scm @@ -1,61 +1,134 @@ -;;----comments---- +(identifier) @variable + + [ - (line_comment) - (doc_comment) @comment.block.documentation -] @comment + (concrete_type) + (tag_type)] @type + + + +(module) @namespace + + + +;; +;; Lower-priorty queries +;; + + + +(argument_patterns (identifier_pattern (identifier) @variable.parameter)) +(argument_patterns (_ (identifier_pattern (identifier) @variable.parameter))) +(argument_patterns (_ (_ (identifier_pattern (identifier) @variable.parameter)))) +(argument_patterns (_ (_ (_ (identifier_pattern (identifier) @variable.parameter))))) +(argument_patterns (_ (_ (_ (_ (identifier_pattern (identifier) @variable.parameter)))))) +(argument_patterns (_ (_ (_ (_ (_ (identifier_pattern (identifier) @variable.parameter))))))) +(spread_pattern (identifier) @variable.parameter) +(match_branch pattern: (_ (identifier_pattern (identifier) @variable.parameter))) + +; N/A +; @variable.other.member.private + +(field_name) @variable.other.member +; Note: This query matches the second identifier and all subsequent ones. +(field_access_expr (identifier) @variable.other.member) +; Note: This query highlights module members as records instead of free variables, +; which avoids highlighting them as out-of-scope vars. +(variable_expr (module) (identifier) @variable.other.member) + +; N/A +; @variable.other -;;----typedefs----- +; N/A +; @variable.builtin -;; opinion: typedefs cross into documentation and should be -;; highlighted differently from normal code +(record_field_pattern (_ (identifier) @variable)) -(nominal_type_def (_ (concrete_type) @type.definition)) -(function_type (arrow) @punctuation.delimiter.structural.typedef) -(function_type (effect_arrow) @punctuation.delimiter.structural.typedef) +; Note: See the lower-priority queries below for a `@variable` query. -(parenthesized_type ["(" ")"] @punctuation.bracket.typedef) -(tuple_type ["(" ")"] @punctuation.bracket.typedef) -(record_type ["{" "}"] @punctuation.bracket.typedef) -(tags_type ["[" "]"] @punctuation.bracket.typedef) -(function_type "," @punctuation.delimiter.typedef) -(tuple_type "," @punctuation.delimiter.typedef) -(record_type "," @punctuation.delimiter.typedef) -(record_field_type ":" @punctuation.delimiter.typedef) -(record_field_type (field_name) @variable.other.enum.typedef) -(where_clause - (where) @type.keyword) +(inferred) @type.roc-special.inferred + +(bound_variable) @type.parameter + +(tag_type) @type.enum.variant + +; N/A +; @type.enum + +; Opinion: Type defs cross into documentation +; and should be highlighted differently from normal code. +(opaque_type_def (_ (concrete_type) @type.definition)) ((concrete_type) @type.builtin - (#match? @type.builtin "^(Bool|Str|Num|List|Result|Dict|Set|Dec)")) + (#match? @type.builtin "^(Dec|F(32|64))")) ((concrete_type) @type.builtin (#match? @type.builtin "^[IU](8|16|32|64|128)")) ((concrete_type) @type.builtin - (#match? @type.builtin "^F(32|64)")) + (#match? @type.builtin "^(Bool|Box|Dec|Decode|Dict|Encode|Hash|Inspect|Int|List|Num|Result|Set|Str)")) + +; Note: See the lower-priority queries below for a `@type` query. + + + +; N/A +; @tag.builtin + +; N/A (We use `@constructor` and `@type.enum.variant` for "tags".) +; @tag + + + +(app_header (packages_list (platform_ref ((package_uri) @string.special.url)))) + + + + +(app_header (packages_list (platform_ref ((package_uri) @string.special.url)))) + +; N/A +; @string.special.symbol + +; N/A +; @string.special.path + +; N/A +; @string.special + +; N/A +; @string.regexp + +(string) @string +(multiline_string) @string + + + +; TODO: Differentiate between values, functions, and types. +(import_expr (exposing ((ident) @special.roc-special.exposed))) + +(app_header (packages_list ((platform_ref) @special.roc-special.package))) + +; TODO: Differentiate between values, functions, and types. +(app_header (provides_list ((identifier) @special.roc-special.provided))) + +; N/A +; @special -(bound_variable) @type.parameter -(tags_type (apply_type(concrete_type) @type.enum.variant)) -(concrete_type) @type -;;-----Punctuation---- [ -"?" -(arrow) -(back_arrow) -] @punctuation.delimiter.structural - -; Lambda pipes -(anon_fun_expr "|" @punctuation.delimiter.structural) -(bang_expr "!" @punctuation.delimiter.structural) + (interpolation_char) +] @punctuation.special + [ "," ":" + (arrow) + (fat_arrow) ] @punctuation.delimiter - [ "(" ")" @@ -63,153 +136,192 @@ "}" "[" "]" - (interpolation_char) + "|" ; TODO: This conflicts with the `"|" @operator` query, so improve both. ] @punctuation.bracket +; N/A +; @punctuation + + + [ - "|" + "=" + "." "&" + ; "|" ; TODO: This conflicts with the `"|" @punctuation.bracket` query, so improve both. + "<-" + "->" ".." - (operator) + "!" + "*" + "-" + "^" (wildcard_pattern) + (operator) ] @operator + + +; N/A +; @label + + + +; TODO: Implement this for `var`. +; @keyword.storage.type + +; N/A +; @keyword.storage.modifier + +; TODO: Implement this for `and`, `or`, and any others. [ - "if" - "else" -] @keyword.control.conditional + (suffix_operator) + ] @keyword.operator + +; N/A +; @keyword.function + +; N/A +; @keyword.directive + +; TODO: Also implement this for `return`. +[(suffix_operator ) "return"]@keyword.control.return + +; TODO: Implement this for `for` and `while`. +; @keyword.control.repeat [ -"match" -"as" -(to) -] @keyword.control.roc + "import" +] @keyword.control.import -; Match expression fat arrow -(match_branch "=>" @punctuation.delimiter.structural) +; N/A +; @keyword.control.exception -;----headers----- +[ + "else" + "if" + + (match) +] @keyword.control.conditional [ "app" + (as) + "as" "expect" + "exposing" "module" "package" - "import" - ] @keyword.control + "platform" + (to) + "var" + (where) +] @keyword.control -;---annotations---- +; N/A +; +; @keyword -(annotation_type_def - (annotation_pre_colon - (identifier)@function ) - (function_type)) -(annotation_type_def - (annotation_pre_colon - (identifier)@parameter.definition )) +[ + "dbg" +] @function.builtin + +(value_declaration (decl_left (identifier_pattern (identifier) @function)) + (expr_body (anon_fun_expr))) +(function_call_pnc_expr caller: (variable_expr (identifier) @function)) +(function_call_pnc_expr caller: (field_access_expr (identifier) @function .)) +(bin_op_expr (operator "->") (variable_expr (identifier) @function)) +(annotation_type_def (annotation_pre_colon (identifier) @function) + (function_type)) -;----decleration types---- -(value_declaration(decl_left - (identifier_pattern - (identifier)@function.definition))(expr_body(anon_fun_expr))) -(value_declaration(decl_left - (identifier_pattern - (identifier) @parameter.definition))) -(backpassing_expr assignee: (identifier_pattern (identifier) @parameter.definition)) + (tag (identifier)@constructor) -;----tags---- -(tag)@constructor -(opaque_tag)@constructor -;-----builtins---- -(variable_expr - (module)@module - (identifier)@constant.builtin.boolean - (#eq? @constant.builtin.boolean "true" ) - (#eq? @module "Bool" ) - ) -(variable_expr - (module)@module - (identifier)@constant.builtin.boolean - (#eq? @constant.builtin.boolean "false" ) - (#eq? @module "Bool" ) - ) [ -"dbg" -] @constant.builtin -;----function invocations ---- -(function_call_expr - caller: (variable_expr - (identifier)@function)) + (decimal) + (float) +] @constant.numeric.float -(function_call_expr - caller: (field_access_expr (identifier)@function .)) +[ + (iint) + (int) + (natural) + (uint) + (xint) +] @constant.numeric.integer -;----function arguments---- +; N/A +; @constant.numeric -(argument_patterns(identifier_pattern - (identifier)@variable.parameter)) -(argument_patterns(_(identifier_pattern(identifier)@variable.parameter))) -(argument_patterns(_(_(identifier_pattern(identifier)@variable.parameter)))) -(argument_patterns(_(_(_(identifier_pattern(identifier)@variable.parameter))))) -(argument_patterns(_(_(_(_(identifier_pattern(identifier)@variable.parameter)))))) -(argument_patterns(_(_(_(_(_(identifier_pattern(identifier)@variable.parameter))))))) +(escape_char) @constant.character.escape -; pattern captures -(match_branch pattern: (_ (identifier_pattern (identifier) @variable.parameter))) -(range_pattern (identifier) @variable.parameter) +(char) @constant.character +(tag_expr(tag (module) @ignoreme.module "." (identifier)@constant.builtin.boolean) + (#eq? @constant.builtin.boolean "True") (#eq? @ignoreme.module "Bool")) +(tag_expr (tag(module) @module "." (identifier)@constant.builtin.boolean) + (#eq? @constant.builtin.boolean "False") (#eq? @module "Bool")) -;;----records---- +; N/A +; @constant.builtin -(field_name)@variable.other.member -(record_field_pattern (_(identifier) @variable)) +; N/A +; @constant -;matches the second identifier and all subsequent ones -(field_access_expr (identifier) @variable.other.member) +(line_comment) @comment.line -;highlight module members as records instead of free variables -; avoids highlighting them as out-of-scope vars -(variable_expr (module) (identifier) @variable.other.member) +(doc_comment) @comment.block.documentation + +; N/A +; @comment.block + +; N/A +; @comment + + + +; N/A +; @attribute + + + +(record_field_type (field_name) @variable.other.member.roc-special.in-typedef) + + +(function_type "," @punctuation.delimiter.roc-special.in-typedef) +(record_type "," @punctuation.delimiter.roc-special.in-typedef) +(tuple_type "," @punctuation.delimiter.roc-special.in-typedef) + +(parenthesized_type ["(" ")"] @punctuation.bracket.roc-special.in-typedef) +(record_type ["{" "}"] @punctuation.bracket.roc-special.in-typedef) +(tags_type ["[" "]"] @punctuation.bracket.roc-special.in-typedef) +(tuple_type ["(" ")"] @punctuation.bracket.roc-special.in-typedef) + +(static_dispatch_target +(identifier)@function.method) + + +((module) @namespace.roc-special.builtin + (#match? @namespace.roc-special.builtin "^(Bool|Box|Decode|Dict|Encode|Hash|Inspect|List|Num|Result|Set|Str)")) +; TODO(bugfix): `Set` yields an ERROR in `expect Set.from_list(paths_as_str) == Set.from_list(["nested-dir/a", "nested-dir/child"])` + + + +;; +;; Higher-priorty queries +;; -;-----consts----- -[ - (int) - (uint) - (iint) - (xint) - (natural) -] @constant.numeric.integer -[ - (decimal) - (float) -] @constant.numeric.float -(string)@string -(multiline_string)@string -(line_string)@string -(char) @constant.character -(escape_char)@constant.character.escape - -;---keep most generic types at bottom for helix--- -;; #any-of? not working in the tree-sitter for helix 23.10 -((module) @namespace.builtin (#eq? @namespace.builtin "Bool")) -((module) @namespace.builtin (#eq? @namespace.builtin "Str")) -((module) @namespace.builtin (#eq? @namespace.builtin "Num")) -((module) @namespace.builtin (#eq? @namespace.builtin "List")) -((module) @namespace.builtin (#eq? @namespace.builtin "Result")) -((module) @namespace.builtin (#eq? @namespace.builtin "Dict")) -((module) @namespace.builtin (#eq? @namespace.builtin "Set")) -(module)@namespace -(module)@module - -(identifier)@variable +;; Highlight names (like `@comment.block.documentation`) are arbitrary. +;; However, some text editors encourage a standard set in their themes. +;; For consistency and quality, these queries assign the highlight names that Helix uses: +;; see https://docs.helix-editor.com/themes.html#scopes diff --git a/languages/roc/indents.scm b/languages/roc/indents.scm index 5514196..ad14816 100644 --- a/languages/roc/indents.scm +++ b/languages/roc/indents.scm @@ -3,125 +3,4 @@ ; ;;think about the structures that indicate the end of an indent and mark them with extend.prevent-once ; ;;find partially complete structures and create speciall rules for them. ; ;;eg: (ERROR (is)) -; [ -; (value_declaration) -; (then) -; (else) -; (when_is_expr) -; (when_is_branch) -; (record_field_expr) -; ;(function_call_expr) -; ; (function_type) -; (annotation_type_def) -; ; (parenthesized_type) -; (interface_header) -; (expect) - -; ] @indent -; [ -; (value_declaration) -; (then) -; (else) -; (when_is_expr) -; (when_is_branch) -; (record_field_expr) -; ;(function_call_expr) -; ; (function_type) -; (annotation_type_def) -; (interface_header) -; (expect) - -; ; (record_expr) -; ] @extend -; [ -; (exposes) -; (imports) -; (provides) -; (requires) -; ]@indent - -; (ERROR "expect")@indent @extend - -; [ -; "[" -; "{" -; "("]@indent @extend - -; ["}" -; "]" -; ")"]@outdent - -; [ -; (record_expr) -; (list_expr) -; (tuple_expr) -; (record_pattern) -; (list_pattern) -; (tuple_pattern) -; (tuple_type) -; (parenthesized_type) -; (parenthesized_expr) -; (paren_pattern) - -; ]@indent - - -; ;;starting a when is expression -; (ERROR (is)@indent @extend) -; ;;starting a record_field -; (ERROR ":"@indent @extend) -; ;starting a type annotation -; (ERROR "(")@indent @extend -; ;starting a variable declaration -; (ERROR "=")@indent @extend - - -; ;;It's annoying when pipelines automatically dedent this pervents that -; (expr_body -; result: (bin_op_expr) -; )@extend - -; ;this automatically dedents, this may be more annying than helpful when writing pipelines -; (expr_body -; result: (_) -; ) @extend.prevent-once - - -; ;;If we maybe don't want all expressions causing dedents - -; ; (value_declaration -; ; (expr_body -; ; result: (_) -; ; ) @extend.prevent-once -; ; ) -; ; (then -; ; (expr_body -; ; result: (_) -; ; ) @extend.prevent-once -; ; ) -; ; (else -; ; (expr_body -; ; result: (_) -; ; ) @extend.prevent-once -; ; ) -; ; (when_is_branch -; ; (expr_body -; ; result: (_) -; ; )@extend.prevent-once -; ; ) -; ; (expect -; ; (expr_body -; ; result: (_) -; ; )@extend.prevent-once -; ; ) -; ; (record_field_expr -; ; (expr_body -; ; result: (_) -; ; ) @extend.prevent-once -; ; ) -; ; (record_field_expr -; ; (expr_body -; ; result: (_) -; ; ) @extend.prevent-once -; ; ) - +(expr_body)@indent \ No newline at end of file diff --git a/languages/roc/injections.scm b/languages/roc/injections.scm index 47a8dde..56cc235 100644 --- a/languages/roc/injections.scm +++ b/languages/roc/injections.scm @@ -1,6 +1,6 @@ ;injection from function calls -(function_call_expr - (variable_expr (identifier) @injection.language) +(function_call_pnc_expr + caller: (variable_expr (identifier) @injection.language) (const [(multiline_string) (string)] @injection.content) (#any-of? @injection.language "json" @@ -25,7 +25,7 @@ part: (const [(multiline_string) (string)] @injection.content ) - part: (operator) + part: (operator ("->")) part: (variable_expr (identifier) @injection.language ) diff --git a/languages/roc/locals.scm b/languages/roc/locals.scm index 5027cee..3fd5aaf 100644 --- a/languages/roc/locals.scm +++ b/languages/roc/locals.scm @@ -1,30 +1,32 @@ (expr_body) @local.scope +(file) @local.scope +(provides_list (identifier)@local.reference) -(value_declaration(decl_left - (identifier_pattern - (identifier)@local.definition))) +; (value_declaration(decl_left +; (identifier_pattern +; (identifier)@local.definition))) ;;This would make parameters that are functions not get highlighted as functions but as parameters.. not sure if that's something we ever want ; (argument_patterns(identifier_pattern ; (identifier)@local.definition)) (argument_patterns(identifier_pattern - (identifier)@local.definition)) -(argument_patterns(_(identifier_pattern(identifier)@local.definition))) -(argument_patterns(_(_(identifier_pattern(identifier)@local.definition)))) -(argument_patterns(_(_(_(identifier_pattern(identifier)@local.definition))))) -(argument_patterns(_(_(_(_(identifier_pattern(identifier)@local.definition)))))) -(argument_patterns(_(_(_(_(_(identifier_pattern(identifier)@local.definition))))))) + (identifier)@local.definition.variable.parameter)) +(argument_patterns(_(identifier_pattern(identifier)@local.definition.variable.parameter))) +(argument_patterns(_(_(identifier_pattern(identifier)@local.definition.variable.parameter)))) +(argument_patterns(_(_(_(identifier_pattern(identifier)@local.definition.variable.parameter))))) +(argument_patterns(_(_(_(_(identifier_pattern(identifier)@local.definition.variable.parameter)))))) +(argument_patterns(_(_(_(_(_(identifier_pattern(identifier)@local.definition.variable.parameter))))))) -(exposes_list(ident)@local.reference) -(import_expr(as)(module)@local.definition) +; (exposes_list(ident)@local.reference) +; (import_expr(as)(module)@local.definition) -(nominal_type_def(apply_type(concrete_type)@local.definition)) -(alias_type_def(apply_type(concrete_type)@local.definition)) +; (opaque_type_def(apply_type(concrete_type)@local.definition)) +; (alias_type_def(apply_type(concrete_type)@local.definition)) -(match_branch pattern: (_ (identifier_pattern (identifier) @local.definition))) -(range_pattern (identifier) @local.definition) +; (match_branch pattern: (_ (identifier_pattern (identifier) @local.definition))) +; (spread_pattern (identifier) @local.definition) (identifier)@local.reference -(tag_expr(tag))@local.reference +; (tag_expr(tag))@local.reference diff --git a/outline.scm b/languages/roc/outline.scm similarity index 100% rename from outline.scm rename to languages/roc/outline.scm diff --git a/languages/roc/rainbows.scm b/languages/roc/rainbows.scm new file mode 100644 index 0000000..52bd41e --- /dev/null +++ b/languages/roc/rainbows.scm @@ -0,0 +1,10 @@ + +[ +(expr_body)] @rainbow.scope + +[ + "[" "]" + "(" ")" + "{" "}" + "|" +] @rainbow.bracket diff --git a/languages/roc/tags.scm b/languages/roc/tags.scm index 4876067..e5e5b86 100644 --- a/languages/roc/tags.scm +++ b/languages/roc/tags.scm @@ -1,13 +1,14 @@ ; Function calls -(function_call_expr - caller: (variable_expr - (identifier)@name ))@reference.call +(function_call_pnc_expr + caller: (variable_expr (identifier)@name ))@reference.call -(function_call_expr +(function_call_pnc_expr caller: (field_access_expr (identifier)@name .))@reference.call -; Function definitions -(value_declaration(decl_left - (identifier_pattern - (identifier)@name))(expr_body(anon_fun_expr)))@definition.function - +;function definition: + (value_declaration + (decl_left + (identifier_pattern + (identifier)@name + )) + body: (expr_body(anon_fun_expr)))@definition.function diff --git a/languages/roc/textobjects.scm b/languages/roc/textobjects.scm index a2b729a..51797c4 100644 --- a/languages/roc/textobjects.scm +++ b/languages/roc/textobjects.scm @@ -10,13 +10,13 @@ ((_) @parameter.inside . ","? @parameter.around) @parameter.around(#not-eq? @parameter.inside "->") ) -(function_call_expr +(function_call_pnc_expr . (_) (parenthesized_expr (expr_body) @parameter.inside) @parameter.around ) -(function_call_expr +(function_call_pnc_expr . (_) ((_) @parameter.inside) @parameter.around ) @@ -24,7 +24,7 @@ [ (annotation_type_def ) @class.inside (alias_type_def ) @class.inside - (nominal_type_def ) @class.inside + (opaque_type_def ) @class.inside ] @class.around (apply_type_arg) @parameter.inside