diff --git a/src/core/Debug.ts b/src/core/Debug.ts index 9fd447a41..036b96f79 100644 --- a/src/core/Debug.ts +++ b/src/core/Debug.ts @@ -1,4 +1,3 @@ -import { Location } from "@cursorless/common"; import { fromVscodeRange } from "@cursorless/vscode-common"; import { Disposable, @@ -87,14 +86,11 @@ export default class Debug { } private logBranchTypes(event: TextEditorSelectionChangeEvent) { - const location = new Location( - ide().activeTextEditor!.document.uri, - fromVscodeRange(event.selections[0]), - ); - let node: SyntaxNode; try { - node = this.graph.getNodeAtLocation(location); + node = ide().activeTextEditor!.getNodeAtLocation( + fromVscodeRange(event.selections[0]), + ); } catch (error) { return; } diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index dcc82a9de..d61adaa8c 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -121,7 +121,6 @@ export default class CommandRunner { hatTokenMap: readableHatMap, thatMark: this.thatMark.exists() ? this.thatMark.get() : [], sourceMark: this.sourceMark.exists() ? this.sourceMark.get() : [], - getNodeAtLocation: this.graph.getNodeAtLocation, }; if (this.graph.testCaseRecorder.isActive()) { diff --git a/src/extension.ts b/src/extension.ts index 8c541993f..d2064f47a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -29,10 +29,10 @@ import makeGraph, { FactoryMap } from "./util/makeGraph"; export async function activate( context: vscode.ExtensionContext, ): Promise { - const { getNodeAtLocation } = await getParseTreeApi(); + const parseTreeApi = await getParseTreeApi(); const commandServerApi = await getCommandServerApi(); - const vscodeIDE = new VscodeIDE(context); + const vscodeIDE = new VscodeIDE(context, parseTreeApi); if (isTesting()) { // FIXME: At some point we'll probably want to support partial mocking @@ -48,7 +48,6 @@ export async function activate( ...graphFactories, extensionContext: () => context, commandServerApi: () => commandServerApi, - getNodeAtLocation: () => getNodeAtLocation, } as FactoryMap); graph.debug.init(); graph.snippets.init(); diff --git a/src/ide/vscode/VscodeEditableTextEditorImpl.ts b/src/ide/vscode/VscodeEditableTextEditorImpl.ts index ff375bdbc..328047585 100644 --- a/src/ide/vscode/VscodeEditableTextEditorImpl.ts +++ b/src/ide/vscode/VscodeEditableTextEditorImpl.ts @@ -8,6 +8,7 @@ import type { TextEditorOptions, } from "@cursorless/common"; import { + ParseTreeApi, toVscodePositionOrRange, toVscodeRange, toVscodeSelection, @@ -22,8 +23,8 @@ export class VscodeEditableTextEditorImpl extends VscodeTextEditorImpl implements EditableTextEditor { - constructor(editor: vscode.TextEditor) { - super(editor); + constructor(parseTreeApi: ParseTreeApi, editor: vscode.TextEditor) { + super(parseTreeApi, editor); } get selections(): Selection[] { diff --git a/src/ide/vscode/VscodeIDE.ts b/src/ide/vscode/VscodeIDE.ts index 783120958..16d409a26 100644 --- a/src/ide/vscode/VscodeIDE.ts +++ b/src/ide/vscode/VscodeIDE.ts @@ -1,5 +1,5 @@ import type { EditableTextEditor, TextEditor } from "@cursorless/common"; -import { toVscodeEditor } from "@cursorless/vscode-common"; +import { ParseTreeApi, toVscodeEditor } from "@cursorless/vscode-common"; import { pull } from "lodash"; import type * as vscode from "vscode"; import { ExtensionContext, window, workspace, WorkspaceFolder } from "vscode"; @@ -25,7 +25,10 @@ export default class VscodeIDE implements IDE { clipboard: VscodeClipboard; private editorMap; - constructor(private extensionContext: ExtensionContext) { + constructor( + private extensionContext: ExtensionContext, + private parseTreeApi: ParseTreeApi, + ) { this.configuration = new VscodeConfiguration(this); this.globalState = new VscodeGlobalState(extensionContext); this.messages = new VscodeMessages(); @@ -53,7 +56,10 @@ export default class VscodeIDE implements IDE { get activeEditableTextEditor(): EditableTextEditor | undefined { return window.activeTextEditor != null - ? new VscodeEditableTextEditorImpl(window.activeTextEditor) + ? new VscodeEditableTextEditorImpl( + this.parseTreeApi, + window.activeTextEditor, + ) : undefined; } @@ -62,7 +68,10 @@ export default class VscodeIDE implements IDE { } public getEditableTextEditor(editor: TextEditor): EditableTextEditor { - return new VscodeEditableTextEditorImpl(toVscodeEditor(editor)); + return new VscodeEditableTextEditorImpl( + this.parseTreeApi, + toVscodeEditor(editor), + ); } public onDidChangeTextDocument( @@ -73,7 +82,10 @@ export default class VscodeIDE implements IDE { public fromVscodeEditor(editor: vscode.TextEditor): TextEditor { if (!this.editorMap.has(editor)) { - this.editorMap.set(editor, new VscodeTextEditorImpl(editor)); + this.editorMap.set( + editor, + new VscodeTextEditorImpl(this.parseTreeApi, editor), + ); } return this.editorMap.get(editor)!; } diff --git a/src/ide/vscode/VscodeTextEditorImpl.ts b/src/ide/vscode/VscodeTextEditorImpl.ts index 85d48785d..58118a5cd 100644 --- a/src/ide/vscode/VscodeTextEditorImpl.ts +++ b/src/ide/vscode/VscodeTextEditorImpl.ts @@ -1,4 +1,5 @@ import type { + Position, Range, Selection, TextDocument, @@ -8,16 +9,22 @@ import type { import { fromVscodeRange, fromVscodeSelection, + ParseTreeApi, + toVscodePositionOrRange, } from "@cursorless/vscode-common"; import { v4 as uuid } from "uuid"; import * as vscode from "vscode"; +import { SyntaxNode } from "web-tree-sitter"; import { fromVscodeDocument } from "./vscodeIdeUtil"; export class VscodeTextEditorImpl implements TextEditor { readonly id: string; readonly document: TextDocument; - constructor(protected editor: vscode.TextEditor) { + constructor( + protected parseTreeApi: ParseTreeApi, + protected editor: vscode.TextEditor, + ) { this.id = uuid(); this.document = fromVscodeDocument(editor.document); } @@ -42,6 +49,15 @@ export class VscodeTextEditorImpl implements TextEditor { return this.editor === vscode.window.activeTextEditor; } + public getNodeAtLocation(positionOrRange: Position | Range): SyntaxNode { + return this.parseTreeApi.getNodeAtLocation( + new vscode.Location( + this.document.uri, + toVscodePositionOrRange(positionOrRange), + ), + ); + } + public isEqual(other: TextEditor): boolean { return this.id === other.id; } diff --git a/src/libs/common/index.ts b/src/libs/common/index.ts index 20cf4673a..47ad83280 100644 --- a/src/libs/common/index.ts +++ b/src/libs/common/index.ts @@ -17,7 +17,6 @@ export { walkFilesSync } from "./util/walkSync"; export { Listener, Notifier } from "./util/Notifier"; export { TokenHatSplittingMode } from "./ide/types/Configuration"; export * from "./ide/types/ide.types"; -export * from "./types/Location"; export * from "./types/Position"; export * from "./types/Range"; export * from "./types/Selection"; diff --git a/src/libs/common/types/Location.ts b/src/libs/common/types/Location.ts deleted file mode 100644 index ed95ea604..000000000 --- a/src/libs/common/types/Location.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { URI } from "vscode-uri"; -import type { Position } from "@cursorless/common"; -import { Range } from "@cursorless/common"; - -/** - * Represents a location inside a resource, such as a line - * inside a text file. - */ -export class Location { - /** - * The resource identifier of this location. - */ - readonly uri: URI; - - /** - * The document range of this location. - */ - readonly range: Range; - - /** - * Creates a new location object. - * - * @param uri The resource identifier. - * @param rangeOrPosition The range or position. Positions will be converted to an empty range. - */ - constructor(uri: URI, rangeOrPosition: Range | Position) { - this.uri = uri; - this.range = - "start" in rangeOrPosition - ? rangeOrPosition - : new Range(rangeOrPosition, rangeOrPosition); - } -} diff --git a/src/libs/common/types/TextEditor.ts b/src/libs/common/types/TextEditor.ts index f72df4254..0aa4cd8d4 100644 --- a/src/libs/common/types/TextEditor.ts +++ b/src/libs/common/types/TextEditor.ts @@ -7,6 +7,7 @@ import type { TextEditorEdit, TextEditorOptions, } from "@cursorless/common"; +import type { SyntaxNode } from "web-tree-sitter"; export interface TextEditor { /** @@ -47,6 +48,14 @@ export interface TextEditor { * @return `true` if the this text editor is equal to `other`. */ isEqual(other: TextEditor): boolean; + + /** + * Function to access nodes in the tree sitter. + * + * @param positionOrRange The position or range. Positions will be converted to an empty range. + * @returns A {@link SyntaxNode node} + */ + getNodeAtLocation(positionOrRange: Position | Range): SyntaxNode; } export interface EditableTextEditor extends TextEditor { diff --git a/src/processTargets/modifiers/ItemStage/getIterationScope.ts b/src/processTargets/modifiers/ItemStage/getIterationScope.ts index e0d1831fa..462ce3d7c 100644 --- a/src/processTargets/modifiers/ItemStage/getIterationScope.ts +++ b/src/processTargets/modifiers/ItemStage/getIterationScope.ts @@ -16,16 +16,11 @@ export function getIterationScope( context: ProcessedTargetsContext, target: Target, ): { range: Range; boundary?: [Range, Range] } { - let pairInfo = getSurroundingPair( - context, - target.editor, - target.contentRange, - ); + let pairInfo = getSurroundingPair(target.editor, target.contentRange); // Iteration is necessary in case of nested strings while (pairInfo != null) { const stringPairInfo = getStringSurroundingPair( - context, target.editor, pairInfo.contentRange, ); @@ -43,7 +38,7 @@ export function getIterationScope( }; } - pairInfo = getParentSurroundingPair(context, target.editor, pairInfo); + pairInfo = getParentSurroundingPair(target.editor, pairInfo); } // We have not found a surrounding pair. Use the line. @@ -53,7 +48,6 @@ export function getIterationScope( } function getParentSurroundingPair( - context: ProcessedTargetsContext, editor: TextEditor, pairInfo: SurroundingPairInfo, ) { @@ -64,27 +58,19 @@ function getParentSurroundingPair( } // Step out of this pair and see if we have a parent const position = editor.document.positionAt(startOffset - 1); - return getSurroundingPair(context, editor, new Range(position, position)); + return getSurroundingPair(editor, new Range(position, position)); } -function getSurroundingPair( - context: ProcessedTargetsContext, - editor: TextEditor, - contentRange: Range, -) { - return processSurroundingPair(context, editor, contentRange, { +function getSurroundingPair(editor: TextEditor, contentRange: Range) { + return processSurroundingPair(editor, contentRange, { type: "surroundingPair", delimiter: "collectionBoundary", requireStrongContainment: true, }); } -function getStringSurroundingPair( - context: ProcessedTargetsContext, - editor: TextEditor, - contentRange: Range, -) { - return processSurroundingPair(context, editor, contentRange, { +function getStringSurroundingPair(editor: TextEditor, contentRange: Range) { + return processSurroundingPair(editor, contentRange, { type: "surroundingPair", delimiter: "string", requireStrongContainment: true, diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 294799db4..c752aacf1 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -42,7 +42,6 @@ function processedSurroundingPairTarget( target: Target, ): SurroundingPairTarget[] { const pairInfo = processSurroundingPair( - context, target.editor, target.contentRange, modifier.scopeType, diff --git a/src/processTargets/modifiers/scopeTypeStages/BoundedNonWhitespaceStage.ts b/src/processTargets/modifiers/scopeTypeStages/BoundedNonWhitespaceStage.ts index 70cd95d1d..cd3787c15 100644 --- a/src/processTargets/modifiers/scopeTypeStages/BoundedNonWhitespaceStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/BoundedNonWhitespaceStage.ts @@ -29,7 +29,6 @@ export default class BoundedNonWhitespaceSequenceStage const paintTargets = paintStage.run(context, target); const pairInfo = processSurroundingPair( - context, target.editor, target.contentRange, { diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 698aa3489..2aabfa64f 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -1,4 +1,4 @@ -import { Location, Selection } from "@cursorless/common"; +import { Selection } from "@cursorless/common"; import type { SyntaxNode } from "web-tree-sitter"; import { NoContainingScopeError } from "../../../errors"; import { getNodeMatcher } from "../../../languages/getNodeMatcher"; @@ -38,8 +38,8 @@ export default class implements ModifierStage { this.modifier.type === "everyScope", ); - const node: SyntaxNode | null = context.getNodeAtLocation( - new Location(target.editor.document.uri, target.contentRange), + const node: SyntaxNode | null = target.editor.getNodeAtLocation( + target.contentRange, ); const scopeNodes = findNearestContainingAncestorNode(node, nodeMatcher, { diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index 48986850f..0beef96f6 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -1,4 +1,4 @@ -import { Location, Range, Selection, TextEditor } from "@cursorless/common"; +import { Range, Selection, TextEditor } from "@cursorless/common"; import { SyntaxNode } from "web-tree-sitter"; import getTextFragmentExtractor, { TextFragmentExtractor, @@ -7,7 +7,6 @@ import { ComplexSurroundingPairName, SurroundingPairScopeType, } from "../../../typings/targetDescriptor.types"; -import { ProcessedTargetsContext } from "../../../typings/Types"; import { complexDelimiterMap } from "./delimiterMaps"; import { SurroundingPairInfo } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; @@ -28,7 +27,6 @@ import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased"; * `null` if none was found */ export function processSurroundingPair( - context: ProcessedTargetsContext, editor: TextEditor, range: Range, scopeType: SurroundingPairScopeType, @@ -42,7 +40,7 @@ export function processSurroundingPair( let textFragmentExtractor: TextFragmentExtractor; try { - node = context.getNodeAtLocation(new Location(document.uri, range)); + node = editor.getNodeAtLocation(range); textFragmentExtractor = getTextFragmentExtractor(document.languageId); } catch (err) { diff --git a/src/typings/Types.ts b/src/typings/Types.ts index d1ea9514d..3ce37338a 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -1,9 +1,4 @@ -import type { - Location, - Range, - Selection, - TextEditor, -} from "@cursorless/common"; +import type { Range, Selection, TextEditor } from "@cursorless/common"; import { SyntaxNode } from "web-tree-sitter"; import { ActionRecord } from "../actions/actions.types"; import Cheatsheet from "../core/Cheatsheet"; @@ -46,7 +41,6 @@ export interface ProcessedTargetsContext { hatTokenMap: ReadOnlyHatMap; thatMark: Target[]; sourceMark: Target[]; - getNodeAtLocation: (location: Location) => SyntaxNode; } export interface SelectionWithEditor { @@ -137,11 +131,6 @@ export interface Graph { */ readonly commandServerApi: CommandServerApi | null; - /** - * Function to access nodes in the tree sitter. - */ - readonly getNodeAtLocation: (location: Location) => SyntaxNode; - /** * Debug logger */