Skip to content
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

helix-core/surround: Syntax aware #6893

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

cole-h
Copy link
Contributor

@cole-h cole-h commented Apr 26, 2023

Prior to this change, attempting to replace the double quotes in " asdf " would fail with "Cursor on ambiguous surround pair".

Now, after running e.g. :set-language rust in a file with the contents " asdf ", it is now possible to replace the double quotes with mr as you could with any other pair.

This change essentially makes any pair that you can use mm on to go to the matching pair also able to be replaced with mr or deleted with md (whether they be built-in, or provided by a tree-sitter grammar).


I would like to add tests for this, but I don't know how I should go about doing this (specifically, creating e.g. a Rust tree-sitter Syntax instance). I noticed one instance in helix-core/tests/indent.rs, but.... it seemed kinda heavy-weight. I'd be happy to use that approach, but I'm hoping to learn about something that's less verbose. Suggestions / examples appreciated :)

Prior to this change, attempting to replace the double quotes in
`" asdf "` would fail with "Cursor on ambiguous surround pair".

Now, after running e.g. `:set-language rust` in a file with the contents
`" asdf "`, it is now possible to replace the double quotes with `mr` as
you could with any other pair.

This change essentially makes any pair that you can use `mm` on to go
to the matching pair also able to be replaced with `mr` or deleted with
`md` (whether they be built-in, or provided by a tree-sitter grammar).
@clo4
Copy link
Contributor

clo4 commented Apr 27, 2023

This is a great change, I run up against this all the time. A much more robust solution than what vim plugins tend to do!

@pascalkuthe
Copy link
Member

For testing you can use the integration test framework which runs a full editors instance. You can then simply invoke the appropriate keybindings and compare the resulting text. An easy to understand example might be helix-terms/tests/test/auto_indent.rs. helix-terms/tests/test/commands.rs contains many more examples

@cole-h
Copy link
Contributor Author

cole-h commented Apr 27, 2023

Ah, that sounds like the best place then. I was sorta-kinda hoping to not need to setup docker/podman again, but I'd much rather test this than not, so I guess podman wins! Embarrassing, I was thinking of another project that ran their integration tests in docker. 😅

I'll try to whip something up shortly.

@pascalkuthe
Copy link
Member

you don't need podman/docker for the integration tests AFAIK

@cole-h
Copy link
Contributor Author

cole-h commented Apr 27, 2023

Yeah, you're 100% right, I was thinking of another project I had once hacked on 😅 Sorry for the confusion; I'll gladly write a test regardless!

@cole-h
Copy link
Contributor Author

cole-h commented Apr 28, 2023

OK, integration tests added in da73d79! Everything passes for me.

Copy link
Member

@pascalkuthe pascalkuthe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nice improvement.

However there can be inconsistencies between what TS returns and the simple textual matching. I think only using TS in such a special case is too much of a hack. TS based matching works fundamentally differently than textual matching. It would be weird if MD" would work differently (better) if the " was selected than if the cursor was inside of the match.

Instead I wonder whether we should change the pair matching to always use tree sitter when available. This would work much better with strings and escapes. For example currently while foo is selected in (foo, ")") and using mr([ would yield [foo, "]") instead if [foo, ")" ].

Implementation wise you would probably need to add some custom lgoic tough. Basically asecndjng the TS tree from the current cursor and stopping at the first node that start and end with thendesirted start/close character. (For each n you would go up one extra layer)


let match_pos = find_matching_bracket(syntax, &text.into(), pos)
.ok_or(Error::CursorOnAmbiguousPair)?;
let close_char = text.char(match_pos);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be reading the close_char again here. If we run into some edgecase where find_matching_bracket does not return the same close char we should just return an error. Everything else would be unintuitive.

@cole-h
Copy link
Contributor Author

cole-h commented Apr 29, 2023

I think I get what you mean. I'll do some playing, and probably end up asking some questions in the Matrix room.

My TS-fu is non-existent, so the work will be slow going, but I'll try to keep this PR apprised of my current progress. (I'll likely end up making the history ugly in the process, but I'll squash it once it appears to work.)

@shaleh
Copy link
Contributor

shaleh commented Apr 15, 2024

What is needed to resurrect this?

// which side of the char we should be searching on.
let syntax = syntax.ok_or(Error::CursorOnAmbiguousPair)?;

let match_pos = find_matching_bracket(syntax, &text.into(), pos)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is the source of the current merge conflict. The RopeSlice can be passed on through now.

Suggested change
let match_pos = find_matching_bracket(syntax, &text.into(), pos)
let match_pos = find_matching_bracket(syntax, text, pos)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants