moved get node at location into editor

This commit is contained in:
Andreas Arvidsson 2022-11-15 09:47:15 +01:00
parent 9b6598b887
commit 4c2ec1cfab
15 changed files with 64 additions and 95 deletions

View File

@ -1,4 +1,3 @@
import { Location } from "@cursorless/common";
import { fromVscodeRange } from "@cursorless/vscode-common"; import { fromVscodeRange } from "@cursorless/vscode-common";
import { import {
Disposable, Disposable,
@ -87,14 +86,11 @@ export default class Debug {
} }
private logBranchTypes(event: TextEditorSelectionChangeEvent) { private logBranchTypes(event: TextEditorSelectionChangeEvent) {
const location = new Location(
ide().activeTextEditor!.document.uri,
fromVscodeRange(event.selections[0]),
);
let node: SyntaxNode; let node: SyntaxNode;
try { try {
node = this.graph.getNodeAtLocation(location); node = ide().activeTextEditor!.getNodeAtLocation(
fromVscodeRange(event.selections[0]),
);
} catch (error) { } catch (error) {
return; return;
} }

View File

@ -121,7 +121,6 @@ export default class CommandRunner {
hatTokenMap: readableHatMap, hatTokenMap: readableHatMap,
thatMark: this.thatMark.exists() ? this.thatMark.get() : [], thatMark: this.thatMark.exists() ? this.thatMark.get() : [],
sourceMark: this.sourceMark.exists() ? this.sourceMark.get() : [], sourceMark: this.sourceMark.exists() ? this.sourceMark.get() : [],
getNodeAtLocation: this.graph.getNodeAtLocation,
}; };
if (this.graph.testCaseRecorder.isActive()) { if (this.graph.testCaseRecorder.isActive()) {

View File

@ -29,10 +29,10 @@ import makeGraph, { FactoryMap } from "./util/makeGraph";
export async function activate( export async function activate(
context: vscode.ExtensionContext, context: vscode.ExtensionContext,
): Promise<CursorlessApi> { ): Promise<CursorlessApi> {
const { getNodeAtLocation } = await getParseTreeApi(); const parseTreeApi = await getParseTreeApi();
const commandServerApi = await getCommandServerApi(); const commandServerApi = await getCommandServerApi();
const vscodeIDE = new VscodeIDE(context); const vscodeIDE = new VscodeIDE(context, parseTreeApi);
if (isTesting()) { if (isTesting()) {
// FIXME: At some point we'll probably want to support partial mocking // FIXME: At some point we'll probably want to support partial mocking
@ -48,7 +48,6 @@ export async function activate(
...graphFactories, ...graphFactories,
extensionContext: () => context, extensionContext: () => context,
commandServerApi: () => commandServerApi, commandServerApi: () => commandServerApi,
getNodeAtLocation: () => getNodeAtLocation,
} as FactoryMap<Graph>); } as FactoryMap<Graph>);
graph.debug.init(); graph.debug.init();
graph.snippets.init(); graph.snippets.init();

View File

@ -8,6 +8,7 @@ import type {
TextEditorOptions, TextEditorOptions,
} from "@cursorless/common"; } from "@cursorless/common";
import { import {
ParseTreeApi,
toVscodePositionOrRange, toVscodePositionOrRange,
toVscodeRange, toVscodeRange,
toVscodeSelection, toVscodeSelection,
@ -22,8 +23,8 @@ export class VscodeEditableTextEditorImpl
extends VscodeTextEditorImpl extends VscodeTextEditorImpl
implements EditableTextEditor implements EditableTextEditor
{ {
constructor(editor: vscode.TextEditor) { constructor(parseTreeApi: ParseTreeApi, editor: vscode.TextEditor) {
super(editor); super(parseTreeApi, editor);
} }
get selections(): Selection[] { get selections(): Selection[] {

View File

@ -1,5 +1,5 @@
import type { EditableTextEditor, TextEditor } from "@cursorless/common"; 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 { pull } from "lodash";
import type * as vscode from "vscode"; import type * as vscode from "vscode";
import { ExtensionContext, window, workspace, WorkspaceFolder } from "vscode"; import { ExtensionContext, window, workspace, WorkspaceFolder } from "vscode";
@ -25,7 +25,10 @@ export default class VscodeIDE implements IDE {
clipboard: VscodeClipboard; clipboard: VscodeClipboard;
private editorMap; private editorMap;
constructor(private extensionContext: ExtensionContext) { constructor(
private extensionContext: ExtensionContext,
private parseTreeApi: ParseTreeApi,
) {
this.configuration = new VscodeConfiguration(this); this.configuration = new VscodeConfiguration(this);
this.globalState = new VscodeGlobalState(extensionContext); this.globalState = new VscodeGlobalState(extensionContext);
this.messages = new VscodeMessages(); this.messages = new VscodeMessages();
@ -53,7 +56,10 @@ export default class VscodeIDE implements IDE {
get activeEditableTextEditor(): EditableTextEditor | undefined { get activeEditableTextEditor(): EditableTextEditor | undefined {
return window.activeTextEditor != null return window.activeTextEditor != null
? new VscodeEditableTextEditorImpl(window.activeTextEditor) ? new VscodeEditableTextEditorImpl(
this.parseTreeApi,
window.activeTextEditor,
)
: undefined; : undefined;
} }
@ -62,7 +68,10 @@ export default class VscodeIDE implements IDE {
} }
public getEditableTextEditor(editor: TextEditor): EditableTextEditor { public getEditableTextEditor(editor: TextEditor): EditableTextEditor {
return new VscodeEditableTextEditorImpl(toVscodeEditor(editor)); return new VscodeEditableTextEditorImpl(
this.parseTreeApi,
toVscodeEditor(editor),
);
} }
public onDidChangeTextDocument( public onDidChangeTextDocument(
@ -73,7 +82,10 @@ export default class VscodeIDE implements IDE {
public fromVscodeEditor(editor: vscode.TextEditor): TextEditor { public fromVscodeEditor(editor: vscode.TextEditor): TextEditor {
if (!this.editorMap.has(editor)) { 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)!; return this.editorMap.get(editor)!;
} }

View File

@ -1,4 +1,5 @@
import type { import type {
Position,
Range, Range,
Selection, Selection,
TextDocument, TextDocument,
@ -8,16 +9,22 @@ import type {
import { import {
fromVscodeRange, fromVscodeRange,
fromVscodeSelection, fromVscodeSelection,
ParseTreeApi,
toVscodePositionOrRange,
} from "@cursorless/vscode-common"; } from "@cursorless/vscode-common";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import * as vscode from "vscode"; import * as vscode from "vscode";
import { SyntaxNode } from "web-tree-sitter";
import { fromVscodeDocument } from "./vscodeIdeUtil"; import { fromVscodeDocument } from "./vscodeIdeUtil";
export class VscodeTextEditorImpl implements TextEditor { export class VscodeTextEditorImpl implements TextEditor {
readonly id: string; readonly id: string;
readonly document: TextDocument; readonly document: TextDocument;
constructor(protected editor: vscode.TextEditor) { constructor(
protected parseTreeApi: ParseTreeApi,
protected editor: vscode.TextEditor,
) {
this.id = uuid(); this.id = uuid();
this.document = fromVscodeDocument(editor.document); this.document = fromVscodeDocument(editor.document);
} }
@ -42,6 +49,15 @@ export class VscodeTextEditorImpl implements TextEditor {
return this.editor === vscode.window.activeTextEditor; 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 { public isEqual(other: TextEditor): boolean {
return this.id === other.id; return this.id === other.id;
} }

View File

@ -17,7 +17,6 @@ export { walkFilesSync } from "./util/walkSync";
export { Listener, Notifier } from "./util/Notifier"; export { Listener, Notifier } from "./util/Notifier";
export { TokenHatSplittingMode } from "./ide/types/Configuration"; export { TokenHatSplittingMode } from "./ide/types/Configuration";
export * from "./ide/types/ide.types"; export * from "./ide/types/ide.types";
export * from "./types/Location";
export * from "./types/Position"; export * from "./types/Position";
export * from "./types/Range"; export * from "./types/Range";
export * from "./types/Selection"; export * from "./types/Selection";

View File

@ -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);
}
}

View File

@ -7,6 +7,7 @@ import type {
TextEditorEdit, TextEditorEdit,
TextEditorOptions, TextEditorOptions,
} from "@cursorless/common"; } from "@cursorless/common";
import type { SyntaxNode } from "web-tree-sitter";
export interface TextEditor { export interface TextEditor {
/** /**
@ -47,6 +48,14 @@ export interface TextEditor {
* @return `true` if the this text editor is equal to `other`. * @return `true` if the this text editor is equal to `other`.
*/ */
isEqual(other: TextEditor): boolean; 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 { export interface EditableTextEditor extends TextEditor {

View File

@ -16,16 +16,11 @@ export function getIterationScope(
context: ProcessedTargetsContext, context: ProcessedTargetsContext,
target: Target, target: Target,
): { range: Range; boundary?: [Range, Range] } { ): { range: Range; boundary?: [Range, Range] } {
let pairInfo = getSurroundingPair( let pairInfo = getSurroundingPair(target.editor, target.contentRange);
context,
target.editor,
target.contentRange,
);
// Iteration is necessary in case of nested strings // Iteration is necessary in case of nested strings
while (pairInfo != null) { while (pairInfo != null) {
const stringPairInfo = getStringSurroundingPair( const stringPairInfo = getStringSurroundingPair(
context,
target.editor, target.editor,
pairInfo.contentRange, 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. // We have not found a surrounding pair. Use the line.
@ -53,7 +48,6 @@ export function getIterationScope(
} }
function getParentSurroundingPair( function getParentSurroundingPair(
context: ProcessedTargetsContext,
editor: TextEditor, editor: TextEditor,
pairInfo: SurroundingPairInfo, pairInfo: SurroundingPairInfo,
) { ) {
@ -64,27 +58,19 @@ function getParentSurroundingPair(
} }
// Step out of this pair and see if we have a parent // Step out of this pair and see if we have a parent
const position = editor.document.positionAt(startOffset - 1); const position = editor.document.positionAt(startOffset - 1);
return getSurroundingPair(context, editor, new Range(position, position)); return getSurroundingPair(editor, new Range(position, position));
} }
function getSurroundingPair( function getSurroundingPair(editor: TextEditor, contentRange: Range) {
context: ProcessedTargetsContext, return processSurroundingPair(editor, contentRange, {
editor: TextEditor,
contentRange: Range,
) {
return processSurroundingPair(context, editor, contentRange, {
type: "surroundingPair", type: "surroundingPair",
delimiter: "collectionBoundary", delimiter: "collectionBoundary",
requireStrongContainment: true, requireStrongContainment: true,
}); });
} }
function getStringSurroundingPair( function getStringSurroundingPair(editor: TextEditor, contentRange: Range) {
context: ProcessedTargetsContext, return processSurroundingPair(editor, contentRange, {
editor: TextEditor,
contentRange: Range,
) {
return processSurroundingPair(context, editor, contentRange, {
type: "surroundingPair", type: "surroundingPair",
delimiter: "string", delimiter: "string",
requireStrongContainment: true, requireStrongContainment: true,

View File

@ -42,7 +42,6 @@ function processedSurroundingPairTarget(
target: Target, target: Target,
): SurroundingPairTarget[] { ): SurroundingPairTarget[] {
const pairInfo = processSurroundingPair( const pairInfo = processSurroundingPair(
context,
target.editor, target.editor,
target.contentRange, target.contentRange,
modifier.scopeType, modifier.scopeType,

View File

@ -29,7 +29,6 @@ export default class BoundedNonWhitespaceSequenceStage
const paintTargets = paintStage.run(context, target); const paintTargets = paintStage.run(context, target);
const pairInfo = processSurroundingPair( const pairInfo = processSurroundingPair(
context,
target.editor, target.editor,
target.contentRange, target.contentRange,
{ {

View File

@ -1,4 +1,4 @@
import { Location, Selection } from "@cursorless/common"; import { Selection } from "@cursorless/common";
import type { SyntaxNode } from "web-tree-sitter"; import type { SyntaxNode } from "web-tree-sitter";
import { NoContainingScopeError } from "../../../errors"; import { NoContainingScopeError } from "../../../errors";
import { getNodeMatcher } from "../../../languages/getNodeMatcher"; import { getNodeMatcher } from "../../../languages/getNodeMatcher";
@ -38,8 +38,8 @@ export default class implements ModifierStage {
this.modifier.type === "everyScope", this.modifier.type === "everyScope",
); );
const node: SyntaxNode | null = context.getNodeAtLocation( const node: SyntaxNode | null = target.editor.getNodeAtLocation(
new Location(target.editor.document.uri, target.contentRange), target.contentRange,
); );
const scopeNodes = findNearestContainingAncestorNode(node, nodeMatcher, { const scopeNodes = findNearestContainingAncestorNode(node, nodeMatcher, {

View File

@ -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 { SyntaxNode } from "web-tree-sitter";
import getTextFragmentExtractor, { import getTextFragmentExtractor, {
TextFragmentExtractor, TextFragmentExtractor,
@ -7,7 +7,6 @@ import {
ComplexSurroundingPairName, ComplexSurroundingPairName,
SurroundingPairScopeType, SurroundingPairScopeType,
} from "../../../typings/targetDescriptor.types"; } from "../../../typings/targetDescriptor.types";
import { ProcessedTargetsContext } from "../../../typings/Types";
import { complexDelimiterMap } from "./delimiterMaps"; import { complexDelimiterMap } from "./delimiterMaps";
import { SurroundingPairInfo } from "./extractSelectionFromSurroundingPairOffsets"; import { SurroundingPairInfo } from "./extractSelectionFromSurroundingPairOffsets";
import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased";
@ -28,7 +27,6 @@ import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased";
* `null` if none was found * `null` if none was found
*/ */
export function processSurroundingPair( export function processSurroundingPair(
context: ProcessedTargetsContext,
editor: TextEditor, editor: TextEditor,
range: Range, range: Range,
scopeType: SurroundingPairScopeType, scopeType: SurroundingPairScopeType,
@ -42,7 +40,7 @@ export function processSurroundingPair(
let textFragmentExtractor: TextFragmentExtractor; let textFragmentExtractor: TextFragmentExtractor;
try { try {
node = context.getNodeAtLocation(new Location(document.uri, range)); node = editor.getNodeAtLocation(range);
textFragmentExtractor = getTextFragmentExtractor(document.languageId); textFragmentExtractor = getTextFragmentExtractor(document.languageId);
} catch (err) { } catch (err) {

View File

@ -1,9 +1,4 @@
import type { import type { Range, Selection, TextEditor } from "@cursorless/common";
Location,
Range,
Selection,
TextEditor,
} from "@cursorless/common";
import { SyntaxNode } from "web-tree-sitter"; import { SyntaxNode } from "web-tree-sitter";
import { ActionRecord } from "../actions/actions.types"; import { ActionRecord } from "../actions/actions.types";
import Cheatsheet from "../core/Cheatsheet"; import Cheatsheet from "../core/Cheatsheet";
@ -46,7 +41,6 @@ export interface ProcessedTargetsContext {
hatTokenMap: ReadOnlyHatMap; hatTokenMap: ReadOnlyHatMap;
thatMark: Target[]; thatMark: Target[];
sourceMark: Target[]; sourceMark: Target[];
getNodeAtLocation: (location: Location) => SyntaxNode;
} }
export interface SelectionWithEditor { export interface SelectionWithEditor {
@ -137,11 +131,6 @@ export interface Graph {
*/ */
readonly commandServerApi: CommandServerApi | null; readonly commandServerApi: CommandServerApi | null;
/**
* Function to access nodes in the tree sitter.
*/
readonly getNodeAtLocation: (location: Location) => SyntaxNode;
/** /**
* Debug logger * Debug logger
*/ */