Skip to content

Commit

Permalink
Merge branch 'main' into pokey/keyboard-parser
Browse files Browse the repository at this point in the history
  • Loading branch information
pokey committed Dec 1, 2023
2 parents 48ab4e9 + bc9cf96 commit a44b2f9
Show file tree
Hide file tree
Showing 159 changed files with 4,508 additions and 862 deletions.
57 changes: 57 additions & 0 deletions data/playground/go/branch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package p

func switches(x any) {
switch x {
case 1:
// bar
case 2:
x = nil
case "s":
case 4, "t":
x = 7
// qux
case 5:
// foo
fallthrough
default:
panic("x")
}
switch x := x.(type) {
case int:
x++
case string, struct{}:
println(x)
default:
panic(x)
}
switch {
case x == 1:
panic("one")
case false:
// unreachable
}
}

func ifElseChains(x int) {
if y := 0; x == 1 {
// foo
} else if z:=0; x == 2 {
x--
x--
x--
} else if z:=0; x == 2 {
x--
x--
x--
} else if x == 3 {
x++
} else if x == 3 {
x++
} else {
x *= 2
}

if x == 4{
x++
}
}
18 changes: 17 additions & 1 deletion packages/common/src/types/Position.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Range } from "..";
import { Range, TextDocument } from "..";

export class Position {
/**
Expand Down Expand Up @@ -151,3 +151,19 @@ export class Position {
return this.concise();
}
}

/**
* adjustPosition returns a new position that is offset by the given amount.
* It corrects line and character positions to remain valid in doc.
* @param doc The document
* @param pos The position to adjust
* @param by The amount to adjust by
* @returns The adjusted position
*/
export function adjustPosition(
doc: TextDocument,
pos: Position,
by: number,
): Position {
return doc.positionAt(doc.offsetAt(pos) + by);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Range } from "@cursorless/common";
import { Range, adjustPosition } from "@cursorless/common";
import { z } from "zod";
import { makeRangeFromPositions } from "../../util/nodeSelectors";
import { MutableQueryCapture } from "./QueryCapture";
Expand Down Expand Up @@ -139,6 +139,26 @@ class ShrinkToMatch extends QueryPredicateOperator<ShrinkToMatch> {
}
}

/**
* A predicate operator that modifies the range of the match by trimming trailing whitespace,
* similar to the javascript trimEnd function.
*/
class TrimEnd extends QueryPredicateOperator<TrimEnd> {
name = "trim-end!" as const;
schema = z.tuple([q.node]);

run(nodeInfo: MutableQueryCapture) {
const { document, range } = nodeInfo;
const text = document.getText(range);
const whitespaceLength = text.length - text.trimEnd().length;
nodeInfo.range = new Range(
range.start,
adjustPosition(document, range.end, -whitespaceLength),
);
return true;
}
}

/**
* Indicates that it is ok for multiple captures to have the same domain but
* different targets. For example, if we have the query `(#allow-multiple!
Expand Down Expand Up @@ -197,6 +217,7 @@ class InsertionDelimiter extends QueryPredicateOperator<InsertionDelimiter> {
export const queryPredicateOperators = [
new Log(),
new NotType(),
new TrimEnd(),
new NotParentType(),
new IsNthChild(),
new ChildRange(),
Expand Down
3 changes: 0 additions & 3 deletions packages/cursorless-engine/src/languages/getNodeMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import csharp from "./csharp";
import go from "./go";
import { patternMatchers as html } from "./html";
import java from "./java";
import { patternMatchers as json } from "./json";
import latex from "./latex";
import markdown from "./markdown";
import php from "./php";
Expand Down Expand Up @@ -64,8 +63,6 @@ export const languageMatchers: Record<
java,
javascript: typescript,
javascriptreact: typescript,
json,
jsonc: json,
latex,
markdown,
php,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ import { notSupported } from "../util/nodeMatchers";
import { getNodeInternalRange, getNodeRange } from "../util/nodeSelectors";
import { LegacyLanguageId } from "./LegacyLanguageId";
import { getNodeMatcher } from "./getNodeMatcher";
import { stringTextFragmentExtractor as htmlStringTextFragmentExtractor } from "./html";
import { stringTextFragmentExtractor as jsonStringTextFragmentExtractor } from "./json";
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 @@ -128,32 +125,7 @@ const textFragmentExtractors: Record<
"css",
scssStringTextFragmentExtractor,
),
html: constructDefaultTextFragmentExtractor(
"html",
htmlStringTextFragmentExtractor,
),
java: constructDefaultTextFragmentExtractor(
"java",
constructHackedStringTextFragmentExtractor("java"),
),
javascript: constructDefaultTextFragmentExtractor(
"javascript",
typescriptStringTextFragmentExtractor,
),
javascriptreact: constructDefaultTextFragmentExtractor(
"javascriptreact",
typescriptStringTextFragmentExtractor,
),
jsonc: constructDefaultTextFragmentExtractor(
"jsonc",
jsonStringTextFragmentExtractor,
),
json: constructDefaultTextFragmentExtractor(
"json",
jsonStringTextFragmentExtractor,
),
latex: fullDocumentTextFragmentExtractor,
markdown: fullDocumentTextFragmentExtractor,
ruby: constructDefaultTextFragmentExtractor(
"ruby",
rubyStringTextFragmentExtractor,
Expand All @@ -167,16 +139,4 @@ const textFragmentExtractors: Record<
scssStringTextFragmentExtractor,
),
rust: constructDefaultTextFragmentExtractor("rust"),
typescript: constructDefaultTextFragmentExtractor(
"typescript",
typescriptStringTextFragmentExtractor,
),
typescriptreact: constructDefaultTextFragmentExtractor(
"typescriptreact",
typescriptStringTextFragmentExtractor,
),
xml: constructDefaultTextFragmentExtractor(
"xml",
htmlStringTextFragmentExtractor,
),
};
54 changes: 3 additions & 51 deletions packages/cursorless-engine/src/languages/html.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,11 @@
import type { SyntaxNode } from "web-tree-sitter";
import { SimpleScopeTypeType } from "@cursorless/common";
import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types";
import { typedNodeFinder } from "../util/nodeFinders";
import {
createPatternMatchers,
leadingMatcher,
matcher,
patternMatcher,
} from "../util/nodeMatchers";
import { xmlElementExtractor, getNodeRange } from "../util/nodeSelectors";

const attribute = "*?.attribute!";

const getStartTag = patternMatcher(`*?.start_tag!`);
const getEndTag = patternMatcher(`*?.end_tag!`);

const getTags = (selection: SelectionWithEditor, node: SyntaxNode) => {
const startTag = getStartTag(selection, node);
const endTag = getEndTag(selection, node);
return startTag != null && endTag != null ? startTag.concat(endTag) : null;
};
import { NodeMatcherAlternative } from "../typings/Types";
import { createPatternMatchers } from "../util/nodeMatchers";

const nodeMatchers: Partial<
Record<SimpleScopeTypeType, NodeMatcherAlternative>
> = {
xmlElement: matcher(
typedNodeFinder("element", "script_element", "style_element"),
xmlElementExtractor,
),
xmlBothTags: getTags,
xmlStartTag: getStartTag,
xmlEndTag: getEndTag,
attribute: attribute,
collectionItem: attribute,
name: "*?.tag_name!",
collectionKey: ["*?.attribute_name!"],
value: leadingMatcher(
["*?.quoted_attribute_value!.attribute_value", "*?.attribute_value!"],
["="],
),
string: "quoted_attribute_value",
comment: "comment",
collectionItem: "*?.attribute!",
};

export const patternMatchers = createPatternMatchers(nodeMatchers);

const textFragmentTypes = ["attribute_value", "raw_text", "text"];

export function stringTextFragmentExtractor(
node: SyntaxNode,
_selection: SelectionWithEditor,
) {
if (textFragmentTypes.includes(node.type)) {
return getNodeRange(node);
}

return null;
}
114 changes: 2 additions & 112 deletions packages/cursorless-engine/src/languages/java.ts
Original file line number Diff line number Diff line change
@@ -1,122 +1,12 @@
import {
createPatternMatchers,
argumentMatcher,
leadingMatcher,
conditionMatcher,
trailingMatcher,
matcher,
cascadingMatcher,
} from "../util/nodeMatchers";
import { childRangeSelector } from "../util/nodeSelectors";
import { patternFinder } from "../util/nodeFinders";
import { argumentMatcher, createPatternMatchers } from "../util/nodeMatchers";

import { NodeMatcherAlternative } from "../typings/Types";
import { SimpleScopeTypeType } from "@cursorless/common";

// Generated by the following command:
// > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-java/master/src/node-types.json | jq '[.[] | select(.type == "statement" or .type == "declaration") | .subtypes[].type]'
const STATEMENT_TYPES = [
"annotation_type_declaration",
"class_declaration",
"enum_declaration",
"import_declaration",
"interface_declaration",
"module_declaration",
"package_declaration",
"assert_statement",
"break_statement",
"continue_statement",
"declaration",
"do_statement",
"enhanced_for_statement",
"expression_statement",
"for_statement",
"if_statement",
"labeled_statement",
"local_variable_declaration",
"return_statement",
"switch_expression",
"synchronized_statement",
"throw_statement",
"try_statement",
"try_with_resources_statement",
"while_statement",
"yield_statement",

// exceptions
// ";",
// "block",
"switch_statement",
"method_declaration",
"constructor_declaration",
"field_declaration",
];
import { NodeMatcherAlternative } from "../typings/Types";

const nodeMatchers: Partial<
Record<SimpleScopeTypeType, NodeMatcherAlternative>
> = {
statement: STATEMENT_TYPES,
class: "class_declaration",
className: "class_declaration[name]",
ifStatement: "if_statement",
string: "string_literal",
comment: ["line_comment", "block_comment", "comment"],
anonymousFunction: "lambda_expression",
list: "array_initializer",
functionCall: [
"method_invocation",
"object_creation_expression",
"explicit_constructor_invocation",
],
functionCallee: cascadingMatcher(
matcher(
patternFinder("method_invocation"),
childRangeSelector(["argument_list"], []),
),
matcher(
patternFinder("object_creation_expression"),
childRangeSelector(["argument_list"], []),
),
matcher(
patternFinder("explicit_constructor_invocation"),
childRangeSelector(["argument_list", ";"], []),
),
),
map: "block",
name: [
"*[declarator][name]",
"assignment_expression[left]",
"*[name]",
"formal_parameter.identifier!",
],
namedFunction: ["method_declaration", "constructor_declaration"],
type: trailingMatcher([
"generic_type.type_arguments.type_identifier",
"generic_type.type_identifier",
"generic_type.scoped_type_identifier.type_identifier",
"type_identifier",
"local_variable_declaration[type]",
"array_creation_expression[type]",
"formal_parameter[type]",
"method_declaration[type]",
]),
functionName: [
"method_declaration.identifier!",
"constructor_declaration.identifier!",
],
value: leadingMatcher(
[
"*[declarator][value]",
"assignment_expression[right]",
"return_statement[0]",
"*[value]",
],
["=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>="],
),
condition: conditionMatcher("*[condition]"),
argumentOrParameter: argumentMatcher("formal_parameters", "argument_list"),
branch: ["switch_block_statement_group", "switch_rule"],
["private.switchStatementSubject"]: "switch_expression[condition][0]",
};

export default createPatternMatchers(nodeMatchers);
Loading

0 comments on commit a44b2f9

Please sign in to comment.