-
-
Notifications
You must be signed in to change notification settings - Fork 88
Add "branch"
scope type
#1149
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
Merged
Merged
Add "branch"
scope type
#1149
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
7ba66c5
Add `branch` scope type
pokey de8c240
Merge branch 'main' into pokey/add-branch-scope-type
pokey 6109fae
Fix scala branch content range
pokey 8ddfc95
Add support for else branches
pokey 72a3d5b
Update docs
pokey a66d4c0
Doc strings
pokey 4118428
More comments
pokey 20f4c8b
Tweaks
pokey 48b6b5b
Remove accidental tests
pokey e030bd5
Python branches for try-catch statements
pokey 40a6444
Support ternary branches for Python and Typescript
pokey a819b7d
Supprt try-catch branches for Typescript
pokey 659eeb7
Improved docs
pokey 51588e7
Move tests
pokey f0b48cd
Rename tests
pokey e674d77
Support python for else and while else
pokey 643090e
Merge branch 'main' into pokey/add-branch-scope-type
pokey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { NodeMatcher } from "../typings/Types"; | ||
import { patternFinder } from "../util/nodeFinders"; | ||
import { | ||
cascadingMatcher, | ||
matcher, | ||
patternMatcher, | ||
} from "../util/nodeMatchers"; | ||
import { childRangeSelector } from "../util/nodeSelectors"; | ||
|
||
/** | ||
* Constructs a branch matcher for constructs that have a primary branch | ||
* followed by zero or more optional branches, such as `if` statements or `try` | ||
* statements | ||
* @param statementType The top-level statement type for this construct, eg | ||
* "if_statement" or "try_statement" | ||
* @param optionalBranchTypes The optional branch type names that can be | ||
* children of the top-level statement, eg "else_clause" or "except_clause" | ||
* @returns A node matcher capabale of matching this type of branch | ||
*/ | ||
export function branchMatcher( | ||
statementType: string, | ||
optionalBranchTypes: string[], | ||
): NodeMatcher { | ||
return cascadingMatcher( | ||
patternMatcher(...optionalBranchTypes), | ||
matcher( | ||
patternFinder(statementType), | ||
childRangeSelector(optionalBranchTypes, [], { | ||
includeUnnamedChildren: true, | ||
}), | ||
), | ||
); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { Selection, TextEditor } from "@cursorless/common"; | ||
import { SyntaxNode } from "web-tree-sitter"; | ||
import { SelectionExtractor, SelectionWithContext } from "../typings/Types"; | ||
import { | ||
childRangeSelector, | ||
positionFromPoint, | ||
simpleSelectionExtractor, | ||
} from "../util/nodeSelectors"; | ||
|
||
/** | ||
* Returns an extractor that can be used to extract `else if` branches in languages | ||
* with C-like structure, where the `if` portion of an `else if` structure is | ||
* structurally just an arbitrary statement that happens to be an `if` | ||
* statement. | ||
* @returns An extractor that will exctract `else if` branches | ||
*/ | ||
export function elseIfExtractor(): SelectionExtractor { | ||
/** | ||
* This extractor pulls out `if (foo) {}` from `if (foo) {} else {}`, ie it | ||
* excludes any child `else` statement if it exists. It will be used as the | ||
* content range, but the removal range will want to include a leading or | ||
* trailing `else` keyword if one exists. | ||
*/ | ||
const contentRangeExtractor = childRangeSelector(["else_clause"], [], { | ||
includeUnnamedChildren: true, | ||
}); | ||
|
||
return function (editor: TextEditor, node: SyntaxNode): SelectionWithContext { | ||
const contentRange = contentRangeExtractor(editor, node); | ||
|
||
const parent = node.parent; | ||
if (parent?.type !== "else_clause") { | ||
// We have no leading `else` clause; ie we are a standalone `if` | ||
// statement. We may still have our own `else` child, but we are not | ||
// ourselves a branch of a bigger `if` statement. | ||
const alternative = node.childForFieldName("alternative"); | ||
|
||
if (alternative == null) { | ||
// If we have no nested else clause, and are not part of an else clause | ||
// ourself, then we don't need to remove any leading / trailing `else` | ||
// keyword | ||
return contentRange; | ||
} | ||
|
||
// Otherwise, we have no leading `else`, but we do have our own nested | ||
// `else` clause, so we want to remove its `else` keyword | ||
const { selection } = contentRange; | ||
return { | ||
selection, | ||
context: { | ||
removalRange: new Selection( | ||
selection.start, | ||
positionFromPoint(alternative.namedChild(0)!.startPosition), | ||
), | ||
}, | ||
}; | ||
} | ||
|
||
// If we get here, we are part of a bigger `if` statement; extend our | ||
// removal range past our leading `else` keyword. | ||
const { selection } = contentRange; | ||
return { | ||
selection, | ||
context: { | ||
removalRange: new Selection( | ||
positionFromPoint(parent.child(0)!.startPosition), | ||
selection.end, | ||
), | ||
}, | ||
}; | ||
}; | ||
} | ||
|
||
/** | ||
* Returns an extractor that can be used to extract `else` branches in languages | ||
* with C-like structure, where the `if` portion of an `else if` structure is | ||
* structurally just an arbitrary statement that happens to be an `if` | ||
* statement. | ||
* @param ifNodeType The node type for `if` statements | ||
* @returns An extractor that will exctract `else` branches | ||
*/ | ||
export function elseExtractor(ifNodeType: string): SelectionExtractor { | ||
const nestedElseIfExtractor = elseIfExtractor(); | ||
|
||
return function (editor: TextEditor, node: SyntaxNode): SelectionWithContext { | ||
// If we are an `else if` statement, then we just run `elseIfExtractor` on | ||
// our nested `if` node. Otherwise we are a simple `else` branch and don't | ||
// need to do anything fancy. | ||
return node.namedChild(0)!.type === ifNodeType | ||
? nestedElseIfExtractor(editor, node.namedChild(0)!) | ||
: simpleSelectionExtractor(editor, node); | ||
}; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { SyntaxNode } from "web-tree-sitter"; | ||
import { NodeMatcher } from "../typings/Types"; | ||
import { matcher } from "../util/nodeMatchers"; | ||
|
||
/** | ||
* Constructs a matcher for matching ternary branches. Branches are expected to | ||
* be named children at particular indices of a ternary node. | ||
* | ||
* NB: We can't just use the "foo[0]" syntax of our pattern language because | ||
* that just uses `foo` for the finder; the `[0]` is just part of the extractor, | ||
* so if we had `foo[0]` and `foo[1]`, they would both match for either branch. | ||
* @param ternaryTypename The type name for ternary expressions | ||
* @param acceptableNamedChildIndices Which named children, by index, of the | ||
* ternary node correspond to branches | ||
* @returns A matcher that can match ternary branches | ||
*/ | ||
export function ternaryBranchMatcher( | ||
ternaryTypename: string, | ||
acceptableNamedChildIndices: number[], | ||
): NodeMatcher { | ||
function finder(node: SyntaxNode) { | ||
const parent = node.parent; | ||
if (parent == null) { | ||
return null; | ||
} | ||
|
||
if ( | ||
parent.type === ternaryTypename && | ||
acceptableNamedChildIndices.some((index) => | ||
parent.namedChild(index)!.equals(node), | ||
) | ||
) { | ||
return node; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
return matcher(finder); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
src/test/suite/fixtures/recorded/languages/java/clearBranch.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
languageId: java | ||
command: | ||
spokenForm: clear branch | ||
version: 3 | ||
targets: | ||
- type: primitive | ||
modifiers: | ||
- type: containingScope | ||
scopeType: {type: branch} | ||
usePrePhraseSnapshot: true | ||
action: {name: clearAndSetSelection} | ||
initialState: | ||
documentContents: |- | ||
class Aaa { | ||
static void bbb() { | ||
switch ("0") { | ||
case ("0"): | ||
break; | ||
case ("1"): | ||
break; | ||
} | ||
} | ||
} | ||
selections: | ||
- anchor: {line: 4, character: 12} | ||
active: {line: 4, character: 12} | ||
marks: {} | ||
finalState: | ||
documentContents: |- | ||
class Aaa { | ||
static void bbb() { | ||
switch ("0") { | ||
|
||
case ("1"): | ||
break; | ||
} | ||
} | ||
} | ||
selections: | ||
- anchor: {line: 3, character: 6} | ||
active: {line: 3, character: 6} | ||
fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: branch}}]}] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
nit: any reason this is listed in this order in particular?
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.
Not really. I should prob file a follow-up to alphabetise; didn't want to mess with the diff