Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the kill commands to kill and yank the rect-marked regions #1817

Merged
merged 16 commits into from
Jan 19, 2024
Merged
12 changes: 12 additions & 0 deletions src/commands/helpers/eol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as vscode from "vscode";

export function getEolChar(eol: vscode.EndOfLine): string {
switch (eol) {
case vscode.EndOfLine.CRLF:
return "\r\n";
case vscode.EndOfLine.LF:
return "\n";
default:
return "\n";
}
}
52 changes: 31 additions & 21 deletions src/commands/kill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { WordCharacterClassifier, getMapForWordSeparators } from "vs/editor/comm
import { findNextWordEnd, findPreviousWordStart } from "./helpers/wordOperations";
import { revealPrimaryActive } from "./helpers/reveal";
import { getNonEmptySelections, makeSelectionsEmpty } from "./helpers/selection";
import { MessageManager } from "../message";

function getWordSeparators(): WordCharacterClassifier {
// Ref: https://github.com/VSCodeVim/Vim/blob/91ca71f8607458c0558f9aff61e230c6917d4b51/src/configuration/configuration.ts#L155
Expand Down Expand Up @@ -59,7 +60,7 @@ export class KillWord extends KillYankCommand {
const killRanges = textEditor.selections
.map((selection) => findNextKillWordRange(textEditor.document, selection.active, repeat))
.filter(<T>(maybeRange: T | undefined): maybeRange is T => maybeRange != null);
await this.killYanker.kill(killRanges);
await this.killYanker.kill(killRanges, false);
revealPrimaryActive(textEditor);
}
}
Expand Down Expand Up @@ -96,7 +97,7 @@ export class BackwardKillWord extends KillYankCommand {
const killRanges = textEditor.selections
.map((selection) => findPreviousKillWordRange(textEditor.document, selection.active, repeat))
.filter(<T>(maybeRange: T | undefined): maybeRange is T => maybeRange != null);
await this.killYanker.kill(killRanges, AppendDirection.Backward);
await this.killYanker.kill(killRanges, false, AppendDirection.Backward);
revealPrimaryActive(textEditor);
}
}
Expand All @@ -110,8 +111,17 @@ export class KillLine extends KillYankCommand {
this.emacsController.exitMarkMode();
makeSelectionsEmpty(textEditor);

const ranges = textEditor.selections.map((selection) => {
const cursor = selection.active;
const endOfDoc = textEditor.document.lineAt(textEditor.document.lineCount - 1).range.end;

const actives = textEditor.selections.map((selection) => selection.active);
const nonEndActives = actives.filter((active) => !active.isEqual(endOfDoc));

if (nonEndActives.length === 0) {
MessageManager.showMessage("End of buffer");
return Promise.resolve();
}

const ranges = nonEndActives.map((cursor) => {
const lineAtCursor = textEditor.document.lineAt(cursor.line);

if (prefixArgument !== undefined) {
Expand All @@ -132,7 +142,8 @@ export class KillLine extends KillYankCommand {
return new Range(cursor, lineEnd);
}
});
return this.killYanker.kill(ranges).then(() => revealPrimaryActive(textEditor));

return this.killYanker.kill(ranges, false).then(() => revealPrimaryActive(textEditor));
}
}

Expand All @@ -148,31 +159,25 @@ export class KillWholeLine extends KillYankCommand {
// From the beginning of the line to the beginning of the next line
new Range(new Position(selection.active.line, 0), new Position(selection.active.line + 1, 0)),
);
return this.killYanker.kill(ranges).then(() => revealPrimaryActive(textEditor));
return this.killYanker.kill(ranges, false).then(() => revealPrimaryActive(textEditor));
}
}

export class KillRegion extends KillYankCommand {
public readonly id = "killRegion";

public async run(textEditor: TextEditor, isInMarkMode: boolean, prefixArgument: number | undefined): Promise<void> {
const selectionsAfterRectDisabled =
this.emacsController.inRectMarkMode &&
this.emacsController.nativeSelections.map((selection) => {
const newLine = selection.active.line;
const newChar = Math.min(selection.active.character, selection.anchor.character);
return new vscode.Selection(newLine, newChar, newLine, newChar);
});

const ranges = getNonEmptySelections(textEditor);
await this.killYanker.kill(ranges);
if (selectionsAfterRectDisabled) {
textEditor.selections = selectionsAfterRectDisabled;
if (this.emacsController.inRectMarkMode) {
const ranges = this.emacsController.nativeSelections;
await this.killYanker.kill(ranges, true);
} else {
const ranges = getNonEmptySelections(textEditor);
await this.killYanker.kill(ranges, false);
}

revealPrimaryActive(textEditor);

this.emacsController.exitMarkMode();
this.killYanker.cancelKillAppend();
}
}

Expand All @@ -181,8 +186,13 @@ export class CopyRegion extends KillYankCommand {
public readonly id = "copyRegion";

public async run(textEditor: TextEditor, isInMarkMode: boolean, prefixArgument: number | undefined): Promise<void> {
const ranges = getNonEmptySelections(textEditor);
await this.killYanker.copy(ranges);
if (this.emacsController.inRectMarkMode) {
const ranges = this.emacsController.nativeSelections;
await this.killYanker.copy(ranges, true);
} else {
const ranges = getNonEmptySelections(textEditor);
await this.killYanker.copy(ranges, false);
}
this.emacsController.exitMarkMode();
this.killYanker.cancelKillAppend();
makeSelectionsEmpty(textEditor);
Expand Down
9 changes: 6 additions & 3 deletions src/commands/paredit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export class KillSexp extends KillYankCommand {
return new Range(selection.anchor, newActivePosition);
});

await this.killYanker.kill(killRanges);
await this.killYanker.kill(killRanges, false);

revealPrimaryActive(textEditor);
}
Expand All @@ -160,7 +160,7 @@ export class BackwardKillSexp extends KillYankCommand {
return new Range(selection.anchor, newActivePosition);
});

await this.killYanker.kill(killRanges, AppendDirection.Backward);
await this.killYanker.kill(killRanges, false, AppendDirection.Backward);

revealPrimaryActive(textEditor);
}
Expand Down Expand Up @@ -204,7 +204,10 @@ export class PareditKill extends KillYankCommand {
return new Range(selection.anchor, newActivePosition);
});

await this.killYanker.kill(killRanges.filter((range) => !range.isEmpty));
await this.killYanker.kill(
killRanges.filter((range) => !range.isEmpty),
false,
);

revealPrimaryActive(textEditor);
}
Expand Down
12 changes: 1 addition & 11 deletions src/commands/rectangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IEmacsController } from "../emulator";
import { getNonEmptySelections, makeSelectionsEmpty } from "./helpers/selection";
import { convertSelectionToRectSelections } from "../rectangle";
import { revealPrimaryActive } from "./helpers/reveal";
import { getEolChar } from "./helpers/eol";
import { KillRing } from "../kill-yank/kill-ring";
import { Minibuffer } from "src/minibuffer";

Expand Down Expand Up @@ -126,17 +127,6 @@ export class KillRectangle extends EditRectangle {
protected copy = true;
}

const getEolChar = (eol: vscode.EndOfLine): string | undefined => {
switch (eol) {
case vscode.EndOfLine.CRLF:
return "\r\n";
case vscode.EndOfLine.LF:
return "\n";
default:
return "\n";
}
};

export class YankRectangle extends RectangleKillYankCommand {
public readonly id = "yankRectangle";

Expand Down
14 changes: 9 additions & 5 deletions src/emulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { PromiseDelegate } from "./promise-delegate";
import { delay, type Unreliable } from "./utils";

export interface IEmacsController {
readonly textEditor: TextEditor;

runCommand(commandName: string): void | Thenable<unknown>;

enterMarkMode(pushMark?: boolean): void;
Expand All @@ -39,7 +41,10 @@ export interface IEmacsController {
}

export class EmacsEmulator implements IEmacsController, vscode.Disposable {
private textEditor: TextEditor;
private _textEditor: TextEditor;
public get textEditor(): TextEditor {
return this._textEditor;
}

private commandRegistry: EmacsCommandRegistry;

Expand Down Expand Up @@ -123,7 +128,7 @@ export class EmacsEmulator implements IEmacsController, vscode.Disposable {
minibuffer: Minibuffer = new InputBoxMinibuffer(),
textRegister: Map<string, string> = new Map(),
) {
this.textEditor = textEditor;
this._textEditor = textEditor;
this.setNativeSelections(this.rectMode ? [] : textEditor.selections); // TODO: `[]` is workaround.

this.markRing = new MarkRing(Configuration.instance.markRingMax);
Expand Down Expand Up @@ -180,7 +185,7 @@ export class EmacsEmulator implements IEmacsController, vscode.Disposable {
this.commandRegistry.register(new FindCommands.IsearchAbort(this, searchState));
this.commandRegistry.register(new FindCommands.IsearchExit(this, searchState));

const killYanker = new KillYanker(textEditor, killRing, minibuffer);
const killYanker = new KillYanker(this, killRing, minibuffer);
this.commandRegistry.register(new KillCommands.KillWord(this, killYanker));
this.commandRegistry.register(new KillCommands.BackwardKillWord(this, killYanker));
this.commandRegistry.register(new KillCommands.KillLine(this, killYanker));
Expand Down Expand Up @@ -230,8 +235,7 @@ export class EmacsEmulator implements IEmacsController, vscode.Disposable {
}

public setTextEditor(textEditor: TextEditor): void {
this.textEditor = textEditor;
this.killYanker.setTextEditor(textEditor);
this._textEditor = textEditor;
}

/**
Expand Down
Loading