Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
* The language IDs that we have full tree-sitter support for using our legacy
* modifiers.
*/
export const legacyLanguageIds = ["clojure", "latex", "rust"] as const;
export const legacyLanguageIds = ["latex", "rust"] as const;

export type LegacyLanguageId = (typeof legacyLanguageIds)[number];
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import type { Range, TextDocument } from "@cursorless/common";
import type { Point } from "web-tree-sitter";
import type { Point, TreeCursor } from "web-tree-sitter";

/**
* Simple representation of the tree sitter syntax node. Used by
* {@link MutableQueryCapture} to avoid using range/text and other mutable
* parameters directly from the node.
*/
interface SimpleSyntaxNode {
export interface SimpleSyntaxNode {
readonly id: number;
readonly type: string;
readonly isNamed: boolean;
readonly parent: SimpleSyntaxNode | null;
readonly children: Array<SimpleChildSyntaxNode>;
walk(): TreeCursor;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { SimpleSyntaxNode } from "./QueryCapture";

export function getChildNodesForFieldName(
node: SimpleSyntaxNode,
fieldName: string,
): SimpleSyntaxNode[] {
const nodes = [];
const treeCursor = node.walk();
let hasNext = treeCursor.gotoFirstChild();

while (hasNext) {
if (treeCursor.currentFieldName === fieldName) {
nodes.push(treeCursor.currentNode);
}
hasNext = treeCursor.gotoNextSibling();
}

return nodes;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { SimpleSyntaxNode } from "./QueryCapture";

/**
* Checks if a node is at an even index within its parent's field.
*
* @param node - The node to check.
* @param fieldName - The name of the field in the parent node.
* @returns True if the node is at an even index, false otherwise.
*/
export function isEven(node: SimpleSyntaxNode, fieldName: string): boolean {
if (node.parent == null) {
throw Error("Node has no parent");
}

const treeCursor = node.parent.walk();
let hasNext = treeCursor.gotoFirstChild();
let even = true;

while (hasNext) {
if (treeCursor.currentFieldName === fieldName) {
if (treeCursor.currentNode.id === node.id) {
return even;
}
even = !even;
}
hasNext = treeCursor.gotoNextSibling();
}

throw Error(`Node not found in parent for field: ${fieldName}`);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,49 @@ import { z } from "zod";
import { makeRangeFromPositions } from "../../util/nodeSelectors";
import type { MutableQueryCapture } from "./QueryCapture";
import { QueryPredicateOperator } from "./QueryPredicateOperator";
import { isEven } from "./isEven";
import { q } from "./operatorArgumentSchemaTypes";

/**
* A predicate operator that returns true if the node is at an even index within
* its parents field. For example, `(#even? @foo value)` will accept the match
* if the `@foo` capture is at an even index among its parents value children.
*/
class Even extends QueryPredicateOperator<Even> {
name = "even?" as const;
schema = z.tuple([q.node, q.string]);
run({ node }: MutableQueryCapture, fieldName: string) {
return isEven(node, fieldName);
}
}

/**
* A predicate operator that returns true if the node is at an odd index within
* its parents field. For example, `(#odd? @foo value)` will accept the match
* if the `@foo` capture is at an odd index among its parents value children.
*/
class Odd extends QueryPredicateOperator<Odd> {
name = "odd?" as const;
schema = z.tuple([q.node, q.string]);
run({ node }: MutableQueryCapture, fieldName: string) {
return !isEven(node, fieldName);
}
}

/**
* A predicate operator that returns true if the node matches the given text.
* For example, `(#text? @foo bar)` will accept the match if the `@foo`
* captures text is `bar`. It is acceptable to pass in multiple texts, e.g.
* `(#text? @foo bar baz)`.
*/
class Text extends QueryPredicateOperator<Text> {
name = "text?" as const;
schema = z.tuple([q.node, q.string]).rest(q.string);
run({ document, range }: MutableQueryCapture, ...texts: string[]) {
return texts.includes(document.getText(range));
}
}

/**
* A predicate operator that returns true if the node is of the given type.
* For example, `(#type? @foo string)` will accept the match if the `@foo`
Expand Down Expand Up @@ -388,6 +429,9 @@ class EmptySingleMultiDelimiter extends QueryPredicateOperator<EmptySingleMultiD

export const queryPredicateOperators = [
new Log(),
new Even(),
new Odd(),
new Text(),
new Type(),
new NotType(),
new TrimEnd(),
Expand Down
162 changes: 0 additions & 162 deletions packages/cursorless-engine/src/languages/clojure.ts

This file was deleted.

6 changes: 2 additions & 4 deletions packages/cursorless-engine/src/languages/getNodeMatcher.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import type { SimpleScopeTypeType } from "@cursorless/common";
import { UnsupportedLanguageError } from "@cursorless/common";
import type { Node } from "web-tree-sitter";
import type { SimpleScopeTypeType } from "@cursorless/common";
import type {
NodeMatcher,
NodeMatcherValue,
SelectionWithEditor,
} from "../typings/Types";
import { notSupported } from "../util/nodeMatchers";
import { selectionWithEditorFromRange } from "../util/selectionUtils";
import clojure from "./clojure";
import type { LegacyLanguageId } from "./LegacyLanguageId";
import latex from "./latex";
import type { LegacyLanguageId } from "./LegacyLanguageId";
import rust from "./rust";

export function getNodeMatcher(
Expand Down Expand Up @@ -41,7 +40,6 @@ export const languageMatchers: Record<
LegacyLanguageId,
Partial<Record<SimpleScopeTypeType, NodeMatcher>>
> = {
clojure,
latex,
rust,
};
Expand Down
Loading
Loading