Skip to content

Commit

Permalink
Migrate typescript scopes (#2040)
Browse files Browse the repository at this point in the history
Fixes #1892

## Checklist

- [x] I have added
[tests](https://www.cursorless.org/docs/contributing/test-case-recorder/)
- [-] I have updated the
[docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and
[cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet)
- [-] I have not broken the cheatsheet

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Pokey Rule <[email protected]>
  • Loading branch information
3 people authored Nov 25, 2023
1 parent 0e266f0 commit 2af63fd
Show file tree
Hide file tree
Showing 12 changed files with 415 additions and 222 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { getNodeMatcher } from "./getNodeMatcher";
import { stringTextFragmentExtractor as htmlStringTextFragmentExtractor } from "./html";
import { stringTextFragmentExtractor as rubyStringTextFragmentExtractor } from "./ruby";
import { stringTextFragmentExtractor as scssStringTextFragmentExtractor } from "./scss";
import { stringTextFragmentExtractor as typescriptStringTextFragmentExtractor } from "./typescript";

export type TextFragmentExtractor = (
node: SyntaxNode,
Expand Down Expand Up @@ -131,14 +130,6 @@ const textFragmentExtractors: Record<
"html",
htmlStringTextFragmentExtractor,
),
javascript: constructDefaultTextFragmentExtractor(
"javascript",
typescriptStringTextFragmentExtractor,
),
javascriptreact: constructDefaultTextFragmentExtractor(
"javascriptreact",
typescriptStringTextFragmentExtractor,
),
latex: fullDocumentTextFragmentExtractor,
markdown: fullDocumentTextFragmentExtractor,
ruby: constructDefaultTextFragmentExtractor(
Expand All @@ -154,14 +145,6 @@ const textFragmentExtractors: Record<
scssStringTextFragmentExtractor,
),
rust: constructDefaultTextFragmentExtractor("rust"),
typescript: constructDefaultTextFragmentExtractor(
"typescript",
typescriptStringTextFragmentExtractor,
),
typescriptreact: constructDefaultTextFragmentExtractor(
"typescriptreact",
typescriptStringTextFragmentExtractor,
),
xml: constructDefaultTextFragmentExtractor(
"xml",
htmlStringTextFragmentExtractor,
Expand Down
152 changes: 2 additions & 150 deletions packages/cursorless-engine/src/languages/typescript.ts
Original file line number Diff line number Diff line change
@@ -1,160 +1,12 @@
import { SimpleScopeTypeType } from "@cursorless/common";
import type { SyntaxNode } from "web-tree-sitter";
import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types";
import { patternFinder } from "../util/nodeFinders";
import {
argumentMatcher,
cascadingMatcher,
conditionMatcher,
createPatternMatchers,
matcher,
patternMatcher,
trailingMatcher,
} from "../util/nodeMatchers";
import {
childRangeSelector,
extendForwardPastOptional,
getNodeInternalRange,
getNodeRange,
unwrapSelectionExtractor,
} from "../util/nodeSelectors";
import { branchMatcher } from "./branchMatcher";
import { elseExtractor, elseIfExtractor } from "./elseIfExtractor";
import { ternaryBranchMatcher } from "./ternaryBranchMatcher";

// Generated by the following command:
// > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-typescript/4c20b54771e4b390ee058af2930feb2cd55f2bf8/typescript/src/node-types.json \
// | jq '[.[] | select(.type == "statement" or .type == "declaration") | .subtypes[].type]'
const STATEMENT_TYPES = [
"abstract_class_declaration",
"ambient_declaration",
"break_statement",
"class_declaration",
"continue_statement",
"debugger_statement",
"declaration",
"do_statement",
"empty_statement",
"enum_declaration",
"export_statement",
"expression_statement",
"for_in_statement",
"for_statement",
"function_declaration",
"function_signature",
"generator_function_declaration",
"if_statement",
"import_alias",
"import_statement",
"interface_declaration",
"internal_module",
"labeled_statement",
"lexical_declaration",
"module",
"return_statement",
// "statement_block", This is disabled since we want the whole statement and not just the block
"switch_statement",
"throw_statement",
"try_statement",
"type_alias_declaration",
"variable_declaration",
"while_statement",
"with_statement",
];

const mapTypes = ["object", "object_pattern"];
const listTypes = ["array", "array_pattern"];
import { NodeMatcherAlternative } from "../typings/Types";
import { argumentMatcher, createPatternMatchers } from "../util/nodeMatchers";

const nodeMatchers: Partial<
Record<SimpleScopeTypeType, NodeMatcherAlternative>
> = {
map: mapTypes,
list: listTypes,
string: ["string", "template_string"],
collectionItem: "jsx_attribute",
collectionKey: trailingMatcher(
[
"pair[key]",
"jsx_attribute.property_identifier!",
"object_type.property_signature[name]!",
"shorthand_property_identifier",
],
[":"],
),
ifStatement: "if_statement",
comment: "comment",
regularExpression: "regex",
className: ["class_declaration[name]", "class[name]"],
functionCall: ["call_expression", "new_expression"],
functionCallee: cascadingMatcher(
patternMatcher("call_expression[function]"),
matcher(
patternFinder("new_expression"),
childRangeSelector(["arguments"], []),
),
),
statement: cascadingMatcher(
matcher(
patternFinder(
"property_signature",
"public_field_definition",
"abstract_method_signature",
),
extendForwardPastOptional(";"),
),
patternMatcher(
...STATEMENT_TYPES.map((type) => `export_statement?.${type}`),
"method_definition",
),
),
condition: cascadingMatcher(
patternMatcher("ternary_expression[condition]"),
conditionMatcher(
"if_statement[condition]",
"for_statement[condition]",
"while_statement[condition]",
"do_statement[condition]",
),
),
["private.switchStatementSubject"]: matcher(
patternFinder("switch_statement[value]"),
unwrapSelectionExtractor,
),
branch: cascadingMatcher(
patternMatcher("switch_case"),
matcher(patternFinder("else_clause"), elseExtractor("if_statement")),
matcher(patternFinder("if_statement"), elseIfExtractor()),
branchMatcher("try_statement", ["catch_clause", "finally_clause"]),
ternaryBranchMatcher("ternary_expression", [1, 2]),
),
class: [
"export_statement?.class_declaration", // export class | class
"export_statement?.abstract_class_declaration", // export abstract class | abstract class
"export_statement.class", // export default class
],
argumentOrParameter: argumentMatcher("formal_parameters", "arguments"),
// XML, JSX
attribute: ["jsx_attribute"],
};

export const patternMatchers = createPatternMatchers(nodeMatchers);

export function stringTextFragmentExtractor(
node: SyntaxNode,
_selection: SelectionWithEditor,
) {
if (
node.type === "string_fragment" ||
node.type === "regex_pattern" ||
node.type === "jsx_text"
) {
return getNodeRange(node);
}

if (node.type === "template_string") {
// Exclude starting and ending quotation marks
return getNodeInternalRange(node);
}

return null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ initialState:
active: {line: 0, character: 24}
marks: {}
finalState:
documentContents: let test = new ()
documentContents: let test = ()
selections:
- anchor: {line: 0, character: 15}
active: {line: 0, character: 15}
- anchor: {line: 0, character: 11}
active: {line: 0, character: 11}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ initialState:
active: {line: 0, character: 28}
marks: {}
finalState:
documentContents: let test = new ()
documentContents: let test = ()
selections:
- anchor: {line: 0, character: 15}
active: {line: 0, character: 15}
- anchor: {line: 0, character: 11}
active: {line: 0, character: 11}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ initialState:
active: {line: 0, character: 24}
marks: {}
finalState:
documentContents: let test = new ()
documentContents: let test = ()
selections:
- anchor: {line: 0, character: 15}
active: {line: 0, character: 15}
- anchor: {line: 0, character: 11}
active: {line: 0, character: 11}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
languageId: typescript
command:
version: 6
spokenForm: chuck type
action:
name: remove
target:
type: primitive
modifiers:
- type: containingScope
scopeType: {type: type}
usePrePhraseSnapshot: true
initialState:
documentContents: <Type>foo
selections:
- anchor: {line: 0, character: 1}
active: {line: 0, character: 1}
marks: {}
finalState:
documentContents: foo
selections:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 0}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
languageId: typescript
command:
version: 1
spokenForm: take every key
action: setSelection
spokenForm: change every key
action: clearAndSetSelection
targets:
- type: primitive
modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: true}
Expand All @@ -19,11 +19,11 @@ initialState:
finalState:
documentContents: |-
const value = {
key1: "hello",
key2: "there",
: "hello",
: "there",
};
selections:
- anchor: {line: 1, character: 4}
active: {line: 1, character: 8}
active: {line: 1, character: 4}
- anchor: {line: 2, character: 4}
active: {line: 2, character: 8}
active: {line: 2, character: 4}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
languageId: typescript
command:
version: 1
spokenForm: take every key
action: setSelection
spokenForm: change every key
action: clearAndSetSelection
targets:
- type: primitive
modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: true}
Expand All @@ -19,11 +19,11 @@ initialState:
finalState:
documentContents: |-
{
foo: "hello",
bar,
: "hello",
,
}
selections:
- anchor: {line: 1, character: 4}
active: {line: 1, character: 7}
active: {line: 1, character: 4}
- anchor: {line: 2, character: 4}
active: {line: 2, character: 7}
active: {line: 2, character: 4}
Loading

0 comments on commit 2af63fd

Please sign in to comment.