mirror of
https://github.com/cursorless-dev/cursorless.git
synced 2024-10-05 05:17:38 +03:00
Added action duplicate (#134)
* started working on action for line duplication * unifi ranges * added comments * clean up * clean up * clean up * calculate newmark * Various cleanup Co-authored-by: Pokey Rule <pokey.rule@gmail.com>
This commit is contained in:
parent
7b24e21d5d
commit
184ea2ae3a
@ -240,6 +240,8 @@ export type ActionType =
|
||||
| "commentLines"
|
||||
| "copy"
|
||||
| "cut"
|
||||
| "copyLinesDown"
|
||||
| "copyLinesUp"
|
||||
| "delete"
|
||||
| "extractVariable"
|
||||
| "editNewLineAbove"
|
||||
|
85
src/actions/CopyLines.ts
Normal file
85
src/actions/CopyLines.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import {
|
||||
Action,
|
||||
ActionPreferences,
|
||||
ActionReturnValue,
|
||||
Graph,
|
||||
TypedSelection,
|
||||
} from "../Types";
|
||||
import { Range, TextEditor } from "vscode";
|
||||
import { performEditsAndUpdateSelections } from "../updateSelections";
|
||||
import displayPendingEditDecorations from "../editDisplayUtils";
|
||||
import { runOnTargetsForEachEditor } from "../targetUtils";
|
||||
import { flatten } from "lodash";
|
||||
import unifyRanges from "../unifyRanges";
|
||||
import expandToContainingLine from "./expandToContainingLine";
|
||||
|
||||
class CopyLines implements Action {
|
||||
targetPreferences: ActionPreferences[] = [{ insideOutsideType: "inside" }];
|
||||
|
||||
constructor(private graph: Graph, private isUp: boolean) {
|
||||
this.run = this.run.bind(this);
|
||||
}
|
||||
|
||||
private getRanges(editor: TextEditor, targets: TypedSelection[]) {
|
||||
const ranges = targets.map((target) =>
|
||||
expandToContainingLine(editor, target.selection.selection)
|
||||
);
|
||||
|
||||
return unifyRanges(ranges);
|
||||
}
|
||||
|
||||
private getEdits(editor: TextEditor, ranges: Range[]) {
|
||||
return ranges.map((range) => {
|
||||
let text = editor.document.getText(range);
|
||||
text = this.isUp ? `${text}\n` : `\n${text}`;
|
||||
const newRange = this.isUp
|
||||
? new Range(range.start, range.start)
|
||||
: new Range(range.end, range.end);
|
||||
return {
|
||||
editor,
|
||||
range: newRange,
|
||||
text,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async run([targets]: [TypedSelection[]]): Promise<ActionReturnValue> {
|
||||
await displayPendingEditDecorations(
|
||||
targets,
|
||||
this.graph.editStyles.referenced,
|
||||
this.graph.editStyles.referencedLine
|
||||
);
|
||||
|
||||
const thatMark = flatten(
|
||||
await runOnTargetsForEachEditor(targets, async (editor, targets) => {
|
||||
const ranges = this.getRanges(editor, targets);
|
||||
const edits = this.getEdits(editor, ranges);
|
||||
|
||||
const [updatedSelections] = await performEditsAndUpdateSelections(
|
||||
editor,
|
||||
edits,
|
||||
[targets.map((target) => target.selection.selection)]
|
||||
);
|
||||
|
||||
return updatedSelections.map((selection) => ({
|
||||
editor,
|
||||
selection,
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
return { returnValue: null, thatMark };
|
||||
}
|
||||
}
|
||||
|
||||
export class CopyLinesUp extends CopyLines {
|
||||
constructor(graph: Graph) {
|
||||
super(graph, false);
|
||||
}
|
||||
}
|
||||
|
||||
export class CopyLinesDown extends CopyLines {
|
||||
constructor(graph: Graph) {
|
||||
super(graph, true);
|
||||
}
|
||||
}
|
10
src/actions/expandToContainingLine.ts
Normal file
10
src/actions/expandToContainingLine.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Range, TextEditor } from "vscode";
|
||||
|
||||
export default function expandToContainingLine(
|
||||
editor: TextEditor,
|
||||
range: Range
|
||||
) {
|
||||
const start = range.start.with({ character: 0 });
|
||||
const end = editor.document.lineAt(range.end).range.end;
|
||||
return new Range(start, end);
|
||||
}
|
@ -24,6 +24,7 @@ import {
|
||||
} from "./InsertEmptyLines";
|
||||
import GetText from "./GetText";
|
||||
import { FindInFiles } from "./Find";
|
||||
import { CopyLinesUp, CopyLinesDown } from "./CopyLines";
|
||||
import SetBreakpoint from "./SetBreakpoint";
|
||||
|
||||
class Actions implements ActionRecord {
|
||||
@ -38,6 +39,8 @@ class Actions implements ActionRecord {
|
||||
clear = new Clear(this.graph);
|
||||
commentLines = new CommentLines(this.graph);
|
||||
copy = new Copy(this.graph);
|
||||
copyLinesDown = new CopyLinesDown(this.graph);
|
||||
copyLinesUp = new CopyLinesUp(this.graph);
|
||||
cut = new Cut(this.graph);
|
||||
delete = new Delete(this.graph);
|
||||
extractVariable = new ExtractVariable(this.graph);
|
||||
|
28
src/unifyRanges.ts
Normal file
28
src/unifyRanges.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { Range } from "vscode";
|
||||
|
||||
/** Unifies overlapping/intersecting ranges */
|
||||
export default function unifyRanges(ranges: Range[]): Range[] {
|
||||
let run = true;
|
||||
while (run) {
|
||||
[ranges, run] = onePass(ranges);
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
function onePass(ranges: Range[]): [Range[], boolean] {
|
||||
const result: Range[] = [];
|
||||
let madeChanges = false;
|
||||
ranges.forEach((range) => {
|
||||
const index = result.findIndex((r) => r.intersection(range) != null);
|
||||
// Update existing intersecting range
|
||||
if (index > -1) {
|
||||
result[index] = result[index].union(range);
|
||||
madeChanges = true;
|
||||
}
|
||||
// Add new range
|
||||
else {
|
||||
result.push(range);
|
||||
}
|
||||
});
|
||||
return [result, madeChanges];
|
||||
}
|
@ -64,13 +64,15 @@ function updateSelectionInfoMatrix(
|
||||
|
||||
selectionInfoMatrix.forEach((selectionInfos) => {
|
||||
selectionInfos.forEach((selectionInfo) => {
|
||||
// Change is before selection. Move entire selection.
|
||||
if (change.range.start.isBefore(selectionInfo.range.start)) {
|
||||
selectionInfo.startOffset += offsetDelta;
|
||||
// Change is selection. Move just end to match.
|
||||
if (change.range.isEqual(selectionInfo.range)) {
|
||||
selectionInfo.endOffset += offsetDelta;
|
||||
}
|
||||
// Change is selection. Move just end to match.
|
||||
else if (change.range.isEqual(selectionInfo.range)) {
|
||||
// Change is before selection. Move entire selection.
|
||||
else if (
|
||||
change.range.start.isBeforeOrEqual(selectionInfo.range.start)
|
||||
) {
|
||||
selectionInfo.startOffset += offsetDelta;
|
||||
selectionInfo.endOffset += offsetDelta;
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user