Skip to content
Merged
18 changes: 11 additions & 7 deletions packages/cursorless-engine/src/actions/BreakLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "@cursorless/common";
import { flatten, zip } from "lodash-es";
import type { RangeUpdater } from "../core/updateSelections/RangeUpdater";
import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections";
import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections";
import { ide } from "../singletons/ide.singleton";
import { Target } from "../typings/target.types";
import { flashTargets, runOnTargetsForEachEditor } from "../util/targetUtils";
Expand All @@ -25,13 +25,17 @@ export class BreakLine {
await runOnTargetsForEachEditor(targets, async (editor, targets) => {
const contentRanges = targets.map(({ contentRange }) => contentRange);
const edits = getEdits(editor, contentRanges);
const editableEditor = ide().getEditableTextEditor(editor);

const [updatedRanges] = await performEditsAndUpdateRanges(
this.rangeUpdater,
ide().getEditableTextEditor(editor),
edits,
[contentRanges],
);
const { contentRanges: updatedRanges } =
await performEditsAndUpdateSelections({
rangeUpdater: this.rangeUpdater,
editor: editableEditor,
edits,
selections: {
contentRanges,
},
});
Comment on lines +30 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tempting to have shorthand

Suggested change
const { contentRanges: updatedRanges } =
await performEditsAndUpdateSelections({
rangeUpdater: this.rangeUpdater,
editor: editableEditor,
edits,
selections: {
contentRanges,
},
});
const updatedRanges =
await performEditsAndUpdateSelections({
rangeUpdater: this.rangeUpdater,
editor: editableEditor,
edits,
selections: contentRanges,
});

but that might be getting a bit too overloaded 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think that is to much


return zip(targets, updatedRanges).map(([target, range]) => ({
editor: target!.editor,
Expand Down
91 changes: 28 additions & 63 deletions packages/cursorless-engine/src/actions/BringMoveSwap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import {
} from "@cursorless/common";
import { flatten } from "lodash-es";
import { RangeUpdater } from "../core/updateSelections/RangeUpdater";
import {
getSelectionInfo,
performEditsAndUpdateFullSelectionInfos,
} from "../core/updateSelections/updateSelections";
import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections";
import { ide } from "../singletons/ide.singleton";
import { EditWithRangeUpdater } from "../typings/Types";
import { Destination, Target } from "../typings/target.types";
Expand Down Expand Up @@ -158,64 +155,35 @@ abstract class BringMoveSwap {
? edits
: edits.filter(({ isSource }) => !isSource);

// Sources should be closedClosed, because they should be logically
// the same as the original source.
const sourceEditSelectionInfos = sourceEdits.map(
({ edit: { range }, originalTarget }) =>
getSelectionInfo(
editor.document,
range.toSelection(originalTarget.isReversed),
RangeExpansionBehavior.closedClosed,
),
);

// Destinations should be openOpen, because they should grow to contain
// the new text.
const destinationEditSelectionInfos = destinationEdits.map(
({ edit: { range }, originalTarget }) =>
getSelectionInfo(
editor.document,
range.toSelection(originalTarget.isReversed),
RangeExpansionBehavior.openOpen,
),
);

const cursorSelectionInfos = editor.selections.map((selection) =>
getSelectionInfo(
editor.document,
selection,
RangeExpansionBehavior.closedClosed,
),
const sourceEditRanges = sourceEdits.map(({ edit }) => edit.range);
const destinationEditRanges = destinationEdits.map(
({ edit }) => edit.range,
);

const editableEditor = ide().getEditableTextEditor(editor);

const [
updatedSourceEditSelections,
updatedDestinationEditSelections,
cursorSelections,
]: Selection[][] = await performEditsAndUpdateFullSelectionInfos(
this.rangeUpdater,
editableEditor,
filteredEdits.map(({ edit }) => edit),
[
sourceEditSelectionInfos,
destinationEditSelectionInfos,
cursorSelectionInfos,
],
);

// NB: We set the selections here because we don't trust vscode to
// properly move the cursor on a bring. Sometimes it will smear an
// empty selection
await editableEditor.setSelections(cursorSelections);
const {
sourceEditRanges: updatedSourceEditRanges,
destinationEditRanges: updatedDestinationEditRanges,
} = await performEditsAndUpdateSelections({
rangeUpdater: this.rangeUpdater,
editor: editableEditor,
edits: filteredEdits.map(({ edit }) => edit),
selections: {
// Sources should be closedClosed, because they should be logically
// the same as the original source.
sourceEditRanges,
// Destinations should be openOpen, because they should grow to contain
// the new text.
destinationEditRanges: {
selections: destinationEditRanges,
behavior: RangeExpansionBehavior.openOpen,
},
},
});

const marks = [
...this.getMarks(sourceEdits, updatedSourceEditSelections),
...this.getMarks(
destinationEdits,
updatedDestinationEditSelections,
),
...this.getMarks(sourceEdits, updatedSourceEditRanges),
...this.getMarks(destinationEdits, updatedDestinationEditRanges),
];

// Restore original order before split into source and destination
Expand All @@ -231,13 +199,10 @@ abstract class BringMoveSwap {
);
}

private getMarks(
edits: ExtendedEdit[],
selections: Selection[],
): MarkEntry[] {
private getMarks(edits: ExtendedEdit[], ranges: Range[]): MarkEntry[] {
return edits.map((edit, index): MarkEntry => {
const selection = selections[index];
const range = edit.edit.updateRange(selection);
const originalRange = ranges[index];
const range = edit.edit.updateRange(originalRange);
const target = edit.originalTarget;
return {
editor: edit.editor,
Expand Down
24 changes: 15 additions & 9 deletions packages/cursorless-engine/src/actions/CallbackAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { EditableTextEditor, FlashStyle, TextEditor } from "@cursorless/common";
import { flatten } from "lodash-es";
import { selectionToStoredTarget } from "../core/commandRunner/selectionToStoredTarget";
import { RangeUpdater } from "../core/updateSelections/RangeUpdater";
import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections";
import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections";
import { ide } from "../singletons/ide.singleton";
import { Target } from "../typings/target.types";
import {
Expand Down Expand Up @@ -97,18 +97,24 @@ export class CallbackAction {
});
}

const [updatedOriginalSelections, updatedTargetSelections] =
await callFunctionAndUpdateSelections(
this.rangeUpdater,
() => options.callback(editableEditor, targets),
editor.document,
[originalSelections, targetSelections],
);
const {
originalSelections: updatedOriginalSelections,
targetSelections: updatedTargetSelections,
} = await performEditsAndUpdateSelections({
rangeUpdater: this.rangeUpdater,
editor: editableEditor,
callback: () => options.callback(editableEditor, targets),
preserveEditorSelections: true,
selections: {
originalSelections,
targetSelections,
},
});

// Reset original selections
if (options.setSelection && options.restoreSelection) {
// NB: We don't focus the editor here because we'll do that at the
// very end. This code can run on multiple editors in the course of
// very end. This code can run on mul:truetiple editors in the course of
// one command, so we want to avoid focusing the editor multiple
// times.
await editableEditor.setSelections(updatedOriginalSelections);
Expand Down
59 changes: 26 additions & 33 deletions packages/cursorless-engine/src/actions/EditNew/runEditTargets.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import {
EditableTextEditor,
RangeExpansionBehavior,
Selection,
} from "@cursorless/common";
import { EditableTextEditor, RangeExpansionBehavior } from "@cursorless/common";
import { zip } from "lodash-es";
import { RangeUpdater } from "../../core/updateSelections/RangeUpdater";
import { performEditsAndUpdateSelectionsWithBehavior } from "../../core/updateSelections/updateSelections";
import { performEditsAndUpdateSelections } from "../../core/updateSelections/updateSelections";
import { EditDestination, State } from "./EditNew.types";

/**
Expand Down Expand Up @@ -46,10 +42,6 @@ export async function runEditTargets(
destination.destination.constructChangeEdit(""),
);

const thatSelections = {
selections: state.thatRanges.map((r) => r.toSelection(false)),
};

// We need to remove undefined cursor locations. Note that these undefined
// locations will be the locations where our edit targets will go. The only
// cursor positions defined at this point will have come from command targets
Expand All @@ -59,44 +51,45 @@ export async function runEditTargets(
.filter(({ range }) => range != null);

const cursorIndices = cursorInfos.map(({ index }) => index);
const cursorRanges = cursorInfos.map(({ range }) => range!);
const editRanges = edits.map((edit) => edit.range);

const cursorSelections = {
selections: cursorInfos.map(({ range }) => range!.toSelection(false)),
};

const editSelections = {
selections: edits.map((edit) => edit.range.toSelection(false)),
rangeBehavior: RangeExpansionBehavior.openOpen,
};

const [
updatedThatSelections,
updatedCursorSelections,
updatedEditSelections,
]: Selection[][] = await performEditsAndUpdateSelectionsWithBehavior(
const {
thatRanges: updatedThatRanges,
cursorRanges: updatedCursorRanges,
editRanges: updatedEditRanges,
} = await performEditsAndUpdateSelections({
rangeUpdater,
editor,
edits,
[thatSelections, cursorSelections, editSelections],
);
preserveEditorSelections: true,
selections: {
thatRanges: state.thatRanges,
cursorRanges,
editRanges: {
selections: editRanges,
behavior: RangeExpansionBehavior.openOpen,
},
},
});

const updatedCursorRanges = [...state.cursorRanges];
const finalCursorRanges = [...state.cursorRanges];

// Update the cursor positions for the command targets
zip(cursorIndices, updatedCursorSelections).forEach(([index, selection]) => {
updatedCursorRanges[index!] = selection;
zip(cursorIndices, updatedCursorRanges).forEach(([index, range]) => {
finalCursorRanges[index!] = range;
});

// Add cursor positions for our edit targets.
destinations.forEach((delimiterTarget, index) => {
const edit = edits[index];
const range = edit.updateRange(updatedEditSelections[index]);
updatedCursorRanges[delimiterTarget.index] = range;
const range = edit.updateRange(updatedEditRanges[index]);
finalCursorRanges[delimiterTarget.index] = range;
});

return {
destinations: state.destinations,
thatRanges: updatedThatSelections,
cursorRanges: updatedCursorRanges,
thatRanges: updatedThatRanges,
cursorRanges: finalCursorRanges,
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommandCapabilities, EditableTextEditor } from "@cursorless/common";
import { RangeUpdater } from "../../core/updateSelections/RangeUpdater";
import { callFunctionAndUpdateRanges } from "../../core/updateSelections/updateSelections";
import { performEditsAndUpdateSelections } from "../../core/updateSelections/updateSelections";
import { EditDestination, State } from "./EditNew.types";

/**
Expand Down Expand Up @@ -39,27 +39,33 @@ export async function runInsertLineAfterTargets(
const contentRanges = destinations.map(
({ destination }) => destination.contentRange,
);
const targetRanges = state.destinations.map(
({ contentRange }) => contentRange,
);

const callback = async () => {
if (acceptsLocation) {
await editor.insertLineAfter(contentRanges);
} else {
await editor.setSelections(
contentRanges.map((range) => range.toSelection(false)),
);
await editor.focus();
await editor.insertLineAfter();
}
};

const [updatedTargetRanges, updatedThatRanges] =
await callFunctionAndUpdateRanges(
const { targetRanges: updatedTargetRanges, thatRanges: updatedThatRanges } =
await performEditsAndUpdateSelections({
rangeUpdater,
async () => {
if (acceptsLocation) {
await editor.insertLineAfter(contentRanges);
} else {
await editor.setSelections(
contentRanges.map((range) => range.toSelection(false)),
);
await editor.focus();
await editor.insertLineAfter();
}
editor,
callback,
preserveEditorSelections: true,
selections: {
targetRanges,
thatRanges: state.thatRanges,
},
editor.document,
[
state.destinations.map(({ contentRange }) => contentRange),
state.thatRanges,
],
);
});

// For each of the given command targets, the cursor will go where it ended
// up after running the command. We add it to the state so that any
Expand Down
Loading
Loading