-
-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding Rust Support #546
Adding Rust Support #546
Conversation
@pokey think this PR is in a pretty good spot now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking really good. Left a few inline comments. In addition, I've taken the liberty of editing the description to use the PR template for adding a language. It would be great if you could make sure you check all the boxes there
In particular, I see that you've used "chuck" for all your tests, but we generally use that one just when the removal is interesting, eg it needs to clean up a ,
or :
. We use "change"
test (or "clear"
, if you're still using that spoken form) as the default action for tests. Otherwise you're basically just testing our whitespace removal code in addition to your intended test case 😅
I don't think you need to re-record all your test cases, but for the ones where removal is interesting, (eg "arg", "type", etc), it would be good to add a "change"
test as well
Also:
- Looks like you're missing a few tests:
- "lambda"
- "if state"
- "state"
- type declarations (as opposed to just type annotations)
|
||
// Generated by the following command: | ||
// `curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-rust/master/src/node-types.json | jq '[.[] | select(.type == "_declaration_statement" or .type == "_expression") | .subtypes[].type]'` | ||
const STATEMENT_TYPES = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to be way too broad. You'll prob want to just look for children of _declaration_statement
, and then add expression_statement
to the list. You don't want to get trapped in an expression when you say "take state"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think _declaration_statement will be too narrow, it wouldn't include if statements for example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Looks like the Rust parser is like Ruby, where the expression_statement
node doesn't appear in the parse tree. The problem is that we need to distinguish between eg an if
statement as a statement, vs if
statement as an expression. For example, when you say "take state", you'll capture the if statement here:
let foo = if bar { "hello" } else { "there" }
which you don't want, because that if
statement is actually functioning as an expression. In Ruby, we resorted to inspecting the parent node to see if the expression is at statement level vs a nested expression. See https://github.com/cursorless-dev/cursorless-vscode/blob/993fbc8d14846414dbfc374c6fa56d3098f03465/src/languages/ruby.ts#L157-L166. Should be able to do something similar here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhhh I see what you are saying now
"let_declaration.identifier!", | ||
"parameter.identifier!", | ||
], | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you're missing a few scope types here:
-
class
. Might also want to include structs in this one -
item
. This is for list elements as well as pairs in a map -
map
-
value
. This one is for RHS of an assignment, as well as value in a map -
key
Maybe a few others? Worth looking at eg Typescript impl for inspiration here. I think the other Rust PR might have a couple of these as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the map/key/value thing doesn't really exist in rust as far as I know: https://doc.rust-lang.org/book/ch08-03-hash-maps.html. Given the syntax, it would probably make more sense to just target key, values as args
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
items are proving hard to implement...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added class, I'm not sure I can actually implement item
though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re map/key/value, fair enough; let's leave that out
Re item
, did argumentMatcher("array_expression")
not work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, although there are no "values" in the map sense of the word, you'll still want "value" as right-hand side of assignment, default value of parameter, return value of function, etc
initialState: | ||
documentContents: |- | ||
let expensive_closure = |num| { | ||
println!("calculating slowly..."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is nice. Worth also testing that "change state" with cursor inside calculating
clears this line exactly
@trace-andreason shall I take this one to the finish line? I think it's getting pretty close |
Hi, I wanted to continue the work on this. I’ve done a rebase and tried to run this, but instructions aren’t clear to me. This is what I see when I try to run the extension. out.mp4 |
Hi @purpleP great to hear you are interested in picking it back up! It's a bit tough to tell what's happening in your video, but you will probably want to run step 3 from https://www.cursorless.org/docs/contributing/#steps if you haven't already |
Oh, yeah. I forgot to say that it gives me an error about fs/promises not being installed. |
Strange. Does that also happen on |
Huh. Maybe remove your |
|
Thanks, updating to 16 LTS helped. |
@pokey How do I match a function call? Right now cursorless select the whole |
That's actually considered correct behaviour for cursorless "call" scope type. I believe what you're after is #707. That should probably happen as a separate PR so that we can introduce it in a few languages for consistency |
What should I do with type constructors and type arguments? I think they should work the same way functions and function arguments work. Also what should I do when I want to delete things like |
I think it's fine to support "arg" for those type arguments. But I wouldn't support "type" for them. That's just for the top-level one (green in your annotations). Be sure to clean up that arrow on "chuck" if you're not already
Sorry not sure I'm following. Is this for "type", "arg", or something else? |
I’m talking about |
my 2c: in |
either way, rustfmt will clean up any lingering whitespace, right? probably not a huge problem for deleting |
Re modifiers, a few thoughts:
|
Finished in #775 |
What
Adds support for the
rust
programming languageChecklist
"change"
/"clear"
instead of"take"
for selection tests to make recorded tests easier to read"chuck"
instead of"change"
to test removal behaviour when it's interesting, especially:"chuck arg"
with single argument in list"chuck arg"
with multiple arguments in list"chuck item"
with single argument in list"chuck item"
with multiple arguments in list"change round"
inside a string, eg"hello (there)"
"type"
both for type annotations (egfoo: string
) and declarations (eginterface Foo {}
) (and added tests for this behaviour 😊)"item"
both for map pairs and list entries (with tests of course)