forked from cursorless-dev/cursorless
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add surrounding pair modifier (cursorless-dev#3)
- Loading branch information
1 parent
7b3db14
commit 150cc84
Showing
24 changed files
with
650 additions
and
34 deletions.
There are no files selected for viewing
This file contains 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 |
---|---|---|
|
@@ -3,3 +3,4 @@ dist | |
node_modules | ||
.vscode-test/ | ||
*.vsix | ||
package-lock.json |
This file contains 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 |
---|---|---|
|
@@ -221,4 +221,4 @@ | |
"immutability-helper": "^3.1.1", | ||
"lodash": "^4.17.21" | ||
} | ||
} | ||
} |
This file contains 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 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 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 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,154 @@ | ||
import { Position, TextEditor, Selection } from "vscode"; | ||
import { Point, SyntaxNode } from "web-tree-sitter"; | ||
import { | ||
Delimiter, | ||
NodeMatcher, | ||
NodeMatcherValue, | ||
SelectionWithContext, | ||
SelectionWithEditor, | ||
SurroundingPairModifierSubtype, | ||
} from "../Types"; | ||
|
||
function positionFromPoint(point: Point): Position { | ||
return new Position(point.row, point.column); | ||
} | ||
|
||
const delimiterToText: Record<Delimiter, String[]> = { | ||
squareBrackets: ["[", "]"], | ||
curlyBrackets: ["{", "}"], | ||
angleBrackets: ["<", ">"], | ||
parentheses: ["(", ")"], | ||
singleQuotes: ["'", "'"], | ||
doubleQuotes: ['"', '"'], | ||
}; | ||
function isSyntaxNodeLeftPartOfMatching( | ||
node: SyntaxNode, | ||
delimiter: Delimiter | ||
): boolean { | ||
return node.type === delimiterToText[delimiter][0]; | ||
} | ||
function isSyntaxNodeRightPartOfMatching( | ||
node: SyntaxNode, | ||
delimiter: Delimiter | ||
): boolean { | ||
return node.type === delimiterToText[delimiter][1]; | ||
} | ||
|
||
export function createSurroundingPairMatcher( | ||
delimiter: Delimiter | null, | ||
matchingSubtype: SurroundingPairModifierSubtype | ||
): NodeMatcher { | ||
return function nodeMatcher( | ||
selection: SelectionWithEditor, | ||
node: SyntaxNode | ||
) { | ||
let delimetersToCheck: Delimiter[]; | ||
if (delimiter != null) { | ||
delimetersToCheck = [delimiter]; | ||
} else { | ||
delimetersToCheck = [ | ||
"squareBrackets", | ||
"curlyBrackets", | ||
"angleBrackets", | ||
"parentheses", | ||
"singleQuotes", | ||
"doubleQuotes", | ||
]; | ||
} | ||
|
||
// This is a special case. | ||
let nodeLeftOfSelection: SyntaxNode | null = null; | ||
let nodeRightOfSelection: SyntaxNode | null = null; | ||
for (const child of node.children) { | ||
// We iterate from the so we take the **last** node that is good | ||
if ( | ||
positionFromPoint(child.endPosition).isBeforeOrEqual( | ||
selection.selection.start | ||
) | ||
) { | ||
nodeLeftOfSelection = child; | ||
} | ||
// We iterate from the so we take the **first** node that is good | ||
if ( | ||
nodeRightOfSelection == null && | ||
selection.selection.start.isBeforeOrEqual( | ||
positionFromPoint(child.startPosition) | ||
) | ||
) { | ||
nodeRightOfSelection = child; | ||
} | ||
} | ||
if (nodeLeftOfSelection != null && nodeRightOfSelection != null) { | ||
let result = doOutwardScan( | ||
nodeLeftOfSelection, | ||
nodeRightOfSelection, | ||
delimetersToCheck, | ||
matchingSubtype | ||
); | ||
if (result != null) { | ||
return result; | ||
} | ||
} | ||
|
||
if (node.parent == null) { | ||
return null; | ||
} | ||
// We don't take the next sibling here, because if current node is a | ||
// closing element of the pair we want to take it. | ||
return doOutwardScan( | ||
node.previousSibling, | ||
node, | ||
delimetersToCheck, | ||
matchingSubtype | ||
); | ||
}; | ||
} | ||
|
||
function doOutwardScan( | ||
scanLeftStartNode: SyntaxNode | null, | ||
scanRightStartNode: SyntaxNode | null, | ||
delimetersToCheck: Delimiter[], | ||
matchingSubtype: SurroundingPairModifierSubtype | ||
): NodeMatcherValue[] | null { | ||
for (const delimiter of delimetersToCheck) { | ||
let left = scanLeftStartNode; | ||
while (left != null) { | ||
if (isSyntaxNodeLeftPartOfMatching(left, delimiter)) { | ||
break; | ||
} | ||
left = left.previousSibling; | ||
} | ||
let right = scanRightStartNode; | ||
while (right != null) { | ||
if (isSyntaxNodeRightPartOfMatching(right, delimiter)) { | ||
break; | ||
} | ||
right = right.nextSibling; | ||
} | ||
if (left != null && right != null) { | ||
// We have found the matching pair | ||
if (matchingSubtype === "matchingSubtype") { | ||
return [ | ||
{ | ||
node: left, | ||
selection: { | ||
selection: new Selection( | ||
positionFromPoint(left.endPosition), | ||
positionFromPoint(right.startPosition) | ||
), | ||
context: { | ||
outerSelection: new Selection( | ||
positionFromPoint(left.startPosition), | ||
positionFromPoint(right.endPosition) | ||
), | ||
}, | ||
}, | ||
}, | ||
]; | ||
} else { | ||
throw new Error("Not implemented"); | ||
} | ||
} | ||
} | ||
return null; | ||
} |
This file contains 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
25 changes: 25 additions & 0 deletions
25
src/test/suite/fixtures/recorded/surroundingPair/clearMatch.yml
This file contains 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,25 @@ | ||
spokenForm: clear match | ||
languageId: python | ||
command: | ||
actionName: clear | ||
partialTargets: | ||
- type: primitive | ||
modifier: {type: surroundingPair, subtype: matchingSubtype, delimiter: null} | ||
extraArgs: [] | ||
marks: {} | ||
initialState: | ||
documentContents: | | ||
"fdsfads" | ||
selections: | ||
- anchor: {line: 0, character: 5} | ||
active: {line: 0, character: 5} | ||
finalState: | ||
documentContents: | | ||
"" | ||
selections: | ||
- anchor: {line: 0, character: 1} | ||
active: {line: 0, character: 1} | ||
thatMark: | ||
- anchor: {line: 0, character: 1} | ||
active: {line: 0, character: 1} | ||
fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, modifier: {type: surroundingPair, subtype: matchingSubtype, delimiter: null}, insideOutsideType: inside}] |
Oops, something went wrong.