-
-
Notifications
You must be signed in to change notification settings - Fork 83
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
Contiguous scope #2101
base: main
Are you sure you want to change the base?
Contiguous scope #2101
Conversation
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.
seems like a good implementation approach. left some comments. also, please add some tests with "next" / "previous", and be sure to test boundaries on edges of scopes and between constituent scopes
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Show resolved
Hide resolved
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts
Outdated
Show resolved
Hide resolved
…andlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <[email protected]>
…andlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <[email protected]>
…andlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <[email protected]>
…andlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <[email protected]>
…andlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <[email protected]>
…andlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <[email protected]>
packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts
Outdated
Show resolved
Hide resolved
…ss into contiguous_scope
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.
Well this code simplified nicely 😄. Left a couple more comments
}; | ||
} | ||
|
||
function* generateTargetRangesInDirection( |
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'm not convinced this function is correct. Eg corner cases like single scope not adjacent to others that's last in the file. To me it looks like if you've already yielded anything, then the final yield after the loop body won't fire.
Some proper unit tests for ContiguousScopeHandler
would help. See https://github.com/cursorless-dev/cursorless/blob/main/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/BaseScopeHandler.test.ts if you're not sure how to do unit tests for this kinda thing. There's a limit to how far you can get using existing scopes
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.
Actually might make sense to hold off on unit tests for the following reasons:
- Your code actually looks at document text, unlike the test I linked, so might be harder to mock that properly
- On second thought, I think your code is probably correct
- I'm actually not convinced of the utility of this contiguous scope thing 😅. The only example I saw that was actually useful was "comment", and tbh I'd be tempted to just automatically merge adjacent single-line comments, as we could target a single one using "line". And I worry users will try "fat arg" to get something like Support "all" modifier #473, and then be surprised when it breaks if there's a comment between args. So maybe we ship this with slightly fewer tests, maybe marked private? idk
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.
Update from discussion today:
- We agreed "comment" is the only use case we can come up with, and we probably just want that to be default behaviour for line comments
- If @josharian wants to fight for supporting "fat" for arbitrary scopes, then we might keep it; otherwise it dies
- We potentially could reuse this code to make contiguous be default behaviour for 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.
If @josharian wants to fight for supporting "fat" for arbitrary scopes, then we might keep it; otherwise it diesau
looking at these test cases, i think it should die
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.
Sounds good. Any opinion on making single-line comments behave this way by default? (Ie auto expand to all comments that aren't separated by an empty line)
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.
Update from meet-up: let's do the following:
(
(comment) @comment
(#match? @comment "^//")
(#contiguous! @comment)
)
(comment) @comment
We both don't love this option or the option in this PR, but it's the best we can do with what we have today. Fwiw we would prefer something like
(
(comment) @comment
($if
(#match? @comment "^//")
(#contiguous! @comment)
)
)
but that's a bit out of scope here 😅
const [startTarget, endTarget] = getTargetsInDocumentOrder( | ||
scope1.getTargets(false)[0], | ||
scope2.getTargets(false)[0], | ||
); |
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 we want to throw an error if there's more than one target? Should we have a utility function function ensureSingleTarget(scope: Scope): Target
that checks there's only one target and returns it? That worked out well for ensureSingleEditor
I think
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.
Reused our existing and shore single target. They should really never trigger with our current implementation so am fine with using an error message that might not be perfect.
packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts
Outdated
Show resolved
Hide resolved
@pokey @josharian The current implementation now only effects the command scope type and there is no spoken form for it. |
return true; | ||
} | ||
|
||
const [startTarget, endTarget] = getTargetsInDocumentOrder( |
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 file is now general enough to be used with most scopes. If we wanted to we could remove a bunch of code here and rely on the fact that we only use it for comments. I could go either way.
Won't this cause adjacent multiline comments to be merged as well? eg /*
* foo
*/
/*
* bar
*/ Looking at this, it feels like not a particularly big deal 😅. But figured I'd point it out as I don't think it quite matches what we discussed |
Yes unless we make this more comment specific and check for single line ranges. Ideally we would have single and multi-line as separate scopes and only use this for single line. Or add a new predicate for contiguous scope. That is probably the best solution? |
hmm so the predicate would just set a flag on the capture. I think that sounds reasonable? |
Yes exactly. |
There is no problem really with this implementation except for the fact that in javascript there is no Tree sitter difference between block and line comments. I guess that contiguous predicate could take a boolean that requires single line ranges? Or a regex pattern? edit: Solved with a regex pattern |
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.
left a few comments
|
||
/** | ||
* Returns true if the given scope type should use a contiguous scope handler. | ||
*/ | ||
function useContiguousScopeHandler(scopeType: ScopeType): boolean { | ||
switch (scopeType.type) { | ||
case "comment": | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} |
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 thought you were using a query predicate for this 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.
We use both. I don't know how to check it at this stage. When we actually fetch the matched scope it's to late to inject this handler. Not without a lot of rewrites at least.
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.
Sorry I'm not following how you would use both. When do you use one vs the other?
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 code decides to use the handler. Then the scope.contiguous is used to determine when to merge two scopes. That way we can ignore block comments.
Line 119 in b6ac60f
if (!scope1.contiguous || !scope2.contiguous) { |
Fixes #1835
Now implemented as a modifier of the comment scope
I decided to implement this as a scope type instead of a modifier. Now you can say things likechuck fat comment
orchanged next fat alpha
. This behavior of having alternatives to existing scopes is already something we started withBoundedNonWhitespaceSequenceStage
albeit in a less capacity.Checklist