-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
feat(core): add plaintext matching fallback to tree-sitter matching #4288
Conversation
Let me know your thoughts about this. |
d446f9c
to
2f38d0b
Compare
hi, any progress here possible? |
@archseer thoughts on this PR? |
helix-term/src/commands.rs
Outdated
if let Some(pos) = match_brackets::find_matching_bracket_fuzzy(syntax, text, pos) | ||
.or_else(|| match_brackets::find_matching_bracket_current_line_plaintext(text, pos)) |
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 doesn't seem to be quite what we want. This always perform the plaintext matching if the TS matching doesn't find a match. Meanwhile for plaintext files this won't work as in that case doc.syntax()
is None
(condition above).
I think we can do better for treesitter than the current implementation (which gets easily broken by comments for example). That solution might partially reuse your solution but would be constrained to not leave the current TS node. You can decide whether you want to do that in this PR or a followup PR, that would be the right fix for #3357
As it's implemented right now I think it's better to only us the plaintext matching for files without a TS grammar (so doc.syntax()
would be None
)
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 see, this fallback will never run when there's no grammar. However, most of the users of this editor will be coding, and likely have an active TS grammar. My hope is that adding this fallback now already brings improvement, and eventually it will be useless if the TS logic improves.
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.
Agreed, this makes the worst case (no matching bracket) a lot worse: first the TS lookup will fail, then this will scan backwards through the whole document (!!), failing too.
I think this is a great improvement for languages with no tree sitter grammar though.
I agree with Pascal:
find_matching_bracket_current_line_plaintext
should only be used if there's no TS grammar available- If there's a grammar available, this scan should only happen inside the current TS node to limit how far we're attempting to scan.
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.
That should settle it: adf0fbd
50e0366
to
a1bf10f
Compare
helix-term/src/commands.rs
Outdated
if let Some(pos) = match_brackets::find_matching_bracket_fuzzy(syntax, text, pos) | ||
.or_else(|| match_brackets::find_matching_bracket_current_line_plaintext(text, pos)) |
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.
Agreed, this makes the worst case (no matching bracket) a lot worse: first the TS lookup will fail, then this will scan backwards through the whole document (!!), failing too.
I think this is a great improvement for languages with no tree sitter grammar though.
I agree with Pascal:
find_matching_bracket_current_line_plaintext
should only be used if there's no TS grammar available- If there's a grammar available, this scan should only happen inside the current TS node to limit how far we're attempting to scan.
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.
A few style nits, other than that and what has already been said by @pascalkuthe and @archseer looks good!
…hing This patch introduces bracket matching independent of tree-sitter grammar. For the initial iteration of this feature, only match on the current line. This matching is introduced as a fallback in cases where the tree-sitter matcher does not match any bracket. This fallback should provide a better experience to users that are editing documents without tree-sitter grammar, but also provides a better experience in cases like the ones reported in helix-editor#3614 If we find that this feature works well, we could consider extending it for multi-line matching, but I wanted to keep it small for the first iteration and gather thoughts beforehand.
- Introduce new variables only when needed - Avoid calling twice `is_valid_pair` on worst-case scenarios - Remove checking if we've closed all brackets on each iteration, this check only makes sense whenever we encouter a closing bracket.
Less overlapping variable names, now it should be even more clear to read. Also added some extra testing, specially to verify that this feature only works on the current line.
…rest Also fix some typos.
Move the decrement operation *after* checking if this is the last bracket to close. This avoids a useless operation. When `is_valid_pair` is entered, we already know we are closing a bracket, when there's only 1 bracket pending to be closed, we already know we're going to return immediately anyway, no need to decrement.
- Remove constraint to work only on current line - Improve iteration by properly using ropes
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.
One minor thing the rest lgtm
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.
LGTM 👍
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 good to me, thanks for your contribution!
|
||
let mut open_cnt = 1; | ||
|
||
for (i, candidate) in chars_iter.take(MAX_PLAINTEXT_SCAN).enumerate() { |
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.
One minor thing I'm noticing is that this doesn't limit the search to the current line only, as it advertises; it simply limits the scan to a max number of chars. I actually think this is fine, because limiting matching to the current line only seems unnecessarily restrictive to me, but we should probably update the function name and doc comment.
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.
yeah it was changed to a fixed limit (from only matching on the current line) after feedback from @archseer and me. I missed that the doc comment wasn't updated good catch
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.
Do you folks use something to embed a constant inside a Doc? I wanted to do this:
diff --git a/helix-core/src/match_brackets.rs b/helix-core/src/match_brackets.rs
index 0ec040e5..07eb261a 100644
--- a/helix-core/src/match_brackets.rs
+++ b/helix-core/src/match_brackets.rs
@@ -73,9 +73,9 @@ fn find_pair(syntax: &Syntax, doc: &Rope, pos: usize, traverse_parents: bool) ->
}
}
-/// Returns the position of the matching bracket under cursor, the search
-/// is limited to the current line. This function works on plain text, it
-/// ignores tree-sitter grammar.
+/// Returns the position of the matching bracket under cursor.
+/// This function works on plain text and ignores tree-sitter grammar.
+/// The search is limited to [`MAX_PLAINTEXT_SCAN`] characters.
///
/// If the cursor is on the opening bracket, the position of
/// the closing bracket is returned. If the cursor on the closing
But that would require making the constant public for the docs to link to it correctly. If you are okay with that anyway (it works, but does not link) then I can push this
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.
That seems fine to me 👍
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.
Just remove the angle brackets SL that cargo xtask docgen doesn't complain. The link doesn't matter much. The docs are not build anyway.
This patch introduces bracket matching independent of tree-sitter grammar. This matching is introduced as a fallback in cases where the tree-sitter matcher does not match any bracket. The fallback should provide a better experience in cases like the ones reported in #3614
Relates to #3584 as well