cursorless icon indicating copy to clipboard operation
cursorless copied to clipboard

WIP: Support Elm Programming Language

Open anmolitor opened this issue 1 year ago • 6 comments

What

Adds support for the Elm programming language. I have tried to bring https://github.com/cursorless-dev/cursorless/pull/891 up to date.

Is there a good way to unit test the generated tree sitter queries? I am currently struggling to extend the functionality - Elm is quite different in its syntax from most currently supported languages. For example, record_expr[field][expression] for change value inside of a map/struct { a = 1, b = 2 } currently always results in { a = , b = 2 }, even if the cursor/target is on "b". I read https://www.cursorless.org/docs/contributing/parse-tree-patterns/ and set up tree-sitter-node locally with tree-sitter-elm to easily inspect the trees, but there are a lot of utility functions in use in the cursorless codebase regarding NodeMatchers that I do not fully understand. Is there some additional documentation/examples that I haven't found yet?

EDIT: I have looked at the open Haskell MR which has a similar syntax. Scm Queries seem to be easier to debug to I will be trying that for now.

Checklist

  • [x] Recorded tests for the new language
  • [x] Used "change" / "clear" instead of "take" for selection tests to make recorded tests easier to read
  • [x] Added a few specific tests that use "chuck" instead of "change" to test removal behaviour when it's interesting, especially:
    • [x] "chuck arg" with single argument in list
    • [x] "chuck arg" with multiple arguments in list
    • [x] "chuck item" with single argument in list
    • [x] "chuck item" with multiple arguments in list
  • [ ] Added @textFragment captures. Usually you want to put these on comment and string nodes. This enables "take round" to work within comments and strings.
  • [ ] Added a test for "change round" inside a string, eg "hello (there)"
  • [x] Supported "type" both for type annotations (eg foo: string) and declarations (eg interface Foo {}) (and added tests for this behaviour 😊)
  • [ ] Supported "item" both for map pairs and list entries (with tests of course)

anmolitor avatar Feb 02 '24 09:02 anmolitor

I added most of the scm queries that I understood. Currently I am struggling with scopes - many of the previously recorded tests are now failing because of "NoContainingScopeError"s. I could fix some of them by adding @.domain on the outer query, which I saw in other languages (and still don't fully understand), but others were not so easy to fix. In particular, I have no idea how to fix argumentAndParameter tagging. If I match all params using ()*, cursorless throws an error because there are multiple matches when it expected only one. If I instead list every possible param by hand as seperate queries, I get "NoContainingScopeError: Couldn't find containing argumentOrParameter". Using just (_) inside of the functionDeclarationLeft node gives the same scope related error.

For reference, here is what I thought should work:

;; namedFunction

;;!! f x y = x
;;!  ^^^^^^^^^
(value_declaration 
  functionDeclarationLeft: (function_declaration_left
    (lower_case_identifier) @functionName @name
    pattern: (_) @argumentOrParameter
  )
  body: (_) @namedFunction.interior
) @namedFunction @functionName.domain

Can you give me some hints? I've tried looking at other languages, but most have a mixed bag of scm and ts queries.

anmolitor avatar Feb 04 '24 17:02 anmolitor

I think @.domain represents the domain of the scope, which is sort of like the area around the actual scope, as a sort of way of getting to the the scope that you're in, without actually literally being in the scope. there's a video of it here

tankorsmash avatar Feb 08 '24 00:02 tankorsmash

@anmolitor I think you're running into https://github.com/tree-sitter/tree-sitter/issues/2984. You can work around it as follows:

(function_declaration_left (_) @argumentOrParameter (#not-type? @argumentOrParameter lower_case_identifier))

pokey avatar Feb 09 '24 17:02 pokey

also, be sure to use andreas's extension to format your code

pokey avatar Feb 09 '24 17:02 pokey

@anmolitor I forked this PR to see if I could help. I couldn't get far, but I did manage to the linked formatter going. It took a while to run on the entire repo but it seems like all it needed to format was the elm.scm file. https://github.com/anmolitor/cursorless/compare/main...tankorsmash:cursorless:main

steps:

  • install the linked extension
  • right click elm.scm in tree
  • very bottom of the dropdown is 'Format' which opens, formats and closes the file

The PR seems to be working though, (without being able to run tests for some reason).


I'd love to have support for state and item scopes on top of what is currently here. Maybe it's not possible though, with how everything is an expression. I'm certainly having trouble getting it going myself!

Based on how python.scm and java.scm are written, I did something similar via a jq filter to get the subtypes for the type bin_op_expr, [.[] | select(.type == "bin_op_expr") | .fields.part.types[].type] (also tried function_call_expr and others), but that led to errors are runtime about overlapping, but I think that's getting some part of the way there.

All the ones in this PR seem to work great (save for arg)!

tankorsmash avatar Feb 24 '24 23:02 tankorsmash

Wow thanks for the help everyone! I'm currently dedicating my free time to prepare https://github.com/anmolitor/protoc-gen-elm 4.0.0, but that should only take a few more days. I'll come back to work on this PR right afterwards :)

anmolitor avatar Feb 25 '24 07:02 anmolitor

@anmolitor if you don't think you'll have capacity to bring this one home, maybe @tankorsmash should open a new PR so that the formatting changes can be incorporated and push things forward? (assuming @tankorsmash has time)

pokey avatar Apr 22 '24 12:04 pokey

I'll take another stab at this this weekend, if @anmolitor is busy!

tankorsmash avatar Apr 25 '24 04:04 tankorsmash