Skip to content

Commit

Permalink
Begin to migrate Paste and Delete to transformation style.
Browse files Browse the repository at this point in the history
  • Loading branch information
johnfn committed Oct 4, 2016
1 parent 21071b7 commit 3dad7ca
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 64 deletions.
61 changes: 41 additions & 20 deletions src/actions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1233,8 +1233,7 @@ export class DeleteOperator extends BaseOperator {
Register.put(text, vimState);
}

await TextEditor.delete(new vscode.Range(start, end));

let diff = new PositionDiff(0, 0);
let resultingPosition: Position;

if (currentMode === ModeName.Visual) {
Expand All @@ -1243,23 +1242,34 @@ export class DeleteOperator extends BaseOperator {

if (start.character > TextEditor.getLineAt(start).text.length) {
resultingPosition = start.getLeft();
diff = new PositionDiff(0, -1);
} else {
resultingPosition = start;
}

if (registerMode === RegisterMode.LineWise) {
resultingPosition = resultingPosition.getLineBegin();
diff = PositionDiff.NewBOLDiff();
}

vimState.recordedState.transformations.push({
type : "deleteRange",
range : new Range(start, end),
diff : diff,
});

return resultingPosition;
}

public async run(vimState: VimState, start: Position, end: Position, yank = true): Promise<VimState> {
const result = await this.delete(start, end, vimState.currentMode, vimState.effectiveRegisterMode(), vimState, yank);
await this.delete(start, end, vimState.currentMode, vimState.effectiveRegisterMode(), vimState, yank);

vimState.currentMode = ModeName.Normal;
vimState.cursorPosition = result;
vimState.cursorStartPosition = result;

/*
vimState.cursorPosition = result;
vimState.cursorStartPosition = result;
*/

return vimState;
}
Expand Down Expand Up @@ -1505,8 +1515,13 @@ export class PutCommand extends BaseCommand {
text = register.text as string;
}

let textToAdd: string;
let whereToAddText: Position;
let diff = new PositionDiff(0, 0);

if (register.registerMode === RegisterMode.CharacterWise) {
await TextEditor.insertAt(text, dest);
textToAdd = text;
whereToAddText = dest;
} else {
if (adjustIndent) {
// Adjust indent to current line
Expand All @@ -1522,25 +1537,34 @@ export class PutCommand extends BaseCommand {
}

if (after) {
await TextEditor.insertAt(text + "\n", dest.getLineBegin());
textToAdd = text + "\n";
whereToAddText = dest.getLineBegin();
} else {
await TextEditor.insertAt("\n" + text, dest.getLineEnd());
textToAdd = "\n" + text;
whereToAddText = dest.getLineEnd();
}
}

// More vim weirdness: If the thing you're pasting has a newline, the cursor
// stays in the same place. Otherwise, it moves to the end of what you pasted.

if (register.registerMode === RegisterMode.LineWise) {
vimState.cursorPosition = new Position(dest.line + 1, 0);
diff = new PositionDiff(1, 0);
} else {
/*
if (text.indexOf("\n") === -1) {
vimState.cursorPosition = new Position(dest.line, Math.max(dest.character + text.length - 1, 0));
} else {
vimState.cursorPosition = dest;
diff = new PositionDiff(0, text.length);
}
*/
}

vimState.recordedState.transformations.push({
type : "insertText",
text : textToAdd,
position: whereToAddText,
diff : diff,
});

vimState.currentRegisterMode = register.registerMode;
return vimState;
}
Expand Down Expand Up @@ -1578,13 +1602,7 @@ export class PutCommand extends BaseCommand {
}

public async execCount(position: Position, vimState: VimState): Promise<VimState> {
const result = await super.execCount(position, vimState);

if (vimState.effectiveRegisterMode() === RegisterMode.LineWise) {
result.cursorPosition = new Position(position.line + 1, 0).getFirstLineNonBlankChar();
}

return result;
return await super.execCount(position, vimState);
}
}

Expand Down Expand Up @@ -1664,7 +1682,10 @@ export class PutCommandVisual extends BaseCommand {
public async exec(position: Position, vimState: VimState, after: boolean = false): Promise<VimState> {
const result = await new DeleteOperator().run(vimState, vimState.cursorStartPosition, vimState.cursorPosition, false);

return await new PutCommand().exec(result.cursorPosition, result, true);
// Our two transformations are overlapping, and VSCode has problems with that.
vimState.recordedState.dontParallelizeTransformations = true;

return await new PutCommand().exec(vimState.cursorStartPosition, result, true);
}

// TODO - execWithCount
Expand Down
116 changes: 80 additions & 36 deletions src/mode/modeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,12 @@ export class RecordedState {
*/
public transformations: Transformation[] = [];

/**
* This turns off transformations running in parallel. It's necessary when
* transformations overlap.
*/
public dontParallelizeTransformations = false;

/**
* The operator (e.g. d, y, >) the user wants to run, if there is one.
*/
Expand Down Expand Up @@ -299,7 +305,7 @@ export class RecordedState {

res.actionKeys = this.actionKeys.slice(0);
res.actionsRun = this.actionsRun.slice(0);
res.hasRunOperator = this.hasRunOperator;
res.hasRunOperator = this.hasRunOperator;

return res;
}
Expand Down Expand Up @@ -916,20 +922,24 @@ export class ModeHandler implements vscode.Disposable {
));
}

// Keep track of all cursors (in the case of multi-cursor).
if (vimState.recordedState.transformations.length > 0) {
await this.executeCommand(vimState);
} else {
// Keep track of all cursors (in the case of multi-cursor).

resultVimState.allCursors = resultingCursors;
resultVimState.allCursors = resultingCursors;

const selections: vscode.Selection[] = [];
const selections: vscode.Selection[] = [];

for (const cursor of vimState.allCursors) {
selections.push(new vscode.Selection(
cursor.start,
cursor.stop,
));
}
for (const cursor of vimState.allCursors) {
selections.push(new vscode.Selection(
cursor.start,
cursor.stop,
));
}

vscode.window.activeTextEditor.selections = selections;
vscode.window.activeTextEditor.selections = selections;
}

return resultVimState;
}
Expand All @@ -948,34 +958,68 @@ export class ModeHandler implements vscode.Disposable {

let accumulatedPositionDifferences: PositionDiff[] = [];

// batch all text operations together as a single operation
// (this is primarily necessary for multi-cursor mode, since most
// actions will trigger at most one text operation).
await vscode.window.activeTextEditor.edit(edit => {
if (vimState.recordedState.dontParallelizeTransformations) {
// This is the rare case.

for (const command of textTransformations) {
switch (command.type) {
case "insertText":
edit.insert(command.position, command.text);
break;

case "replaceText":
edit.replace(new vscode.Selection(command.end, command.start), command.text);
break;

case "deleteText":
edit.delete(new vscode.Range(command.position, command.position.getLeftThroughLineBreaks()));
break;

case "deleteRange":
edit.delete(new vscode.Selection(command.range.start, command.range.stop));
break;
}
await vscode.window.activeTextEditor.edit(edit => {
switch (command.type) {
case "insertText":
edit.insert(command.position, command.text);
break;

case "replaceText":
edit.replace(new vscode.Selection(command.end, command.start), command.text);
break;

case "deleteText":
edit.delete(new vscode.Range(command.position, command.position.getLeftThroughLineBreaks()));
break;

case "deleteRange":
edit.delete(new vscode.Selection(command.range.start, command.range.stop));
break;
}

if (command.diff) {
accumulatedPositionDifferences.push(command.diff);
}
});
};
} else {
// This is the common case!

if (command.diff) {
accumulatedPositionDifferences.push(command.diff);
/**
* batch all text operations together as a single operation
* (this is primarily necessary for multi-cursor mode, since most
* actions will trigger at most one text operation).
*/
await vscode.window.activeTextEditor.edit(edit => {
for (const command of textTransformations) {
switch (command.type) {
case "insertText":
edit.insert(command.position, command.text);
break;

case "replaceText":
edit.replace(new vscode.Selection(command.end, command.start), command.text);
break;

case "deleteText":
edit.delete(new vscode.Range(command.position, command.position.getLeftThroughLineBreaks()));
break;

case "deleteRange":
edit.delete(new vscode.Selection(command.range.start, command.range.stop));
break;
}

if (command.diff) {
accumulatedPositionDifferences.push(command.diff);
}
}
}
});
});
}

for (const command of otherTransformations) {
switch (command.type) {
Expand Down
89 changes: 81 additions & 8 deletions src/motion/position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,92 @@ import { Configuration } from "./../configuration/configuration";

/**
* Represents a difference between two positions. Add it to a position
* to get another position.
* to get another position. Create it with the factory methods:
*
* - NewDiff
* - NewBOLDiff
*/
export class PositionDiff {
public line: number;
public character: number;
private _line: number;
private _character: number;
private _isBOLDiff: boolean;

constructor(line: number, character: number) {
this.line = line;
this.character = character;
this._line = line;
this._character = character;
}

public add(other: PositionDiff) {
/**
* Creates a new PositionDiff that always brings the cursor to the beginning of the line
* when applied to a position.
*/
public static NewBOLDiff(): PositionDiff {
const result = new PositionDiff(0, 0);

result._isBOLDiff = true;
return result;
}

/**
* Add this PositionDiff to another PositionDiff.
*/
public addDiff(other: PositionDiff) {
if (this._isBOLDiff || other._isBOLDiff) {
throw new Error("johnfn hasn't done this case yet and doesnt want to");
}

return new PositionDiff(
this.line + other.line,
this.character + other.character
this._line + other._line,
this._character + other._character
);
}

/**
* Adds a Position to this PositionDiff, returning a new PositionDiff.
*/
public addPosition(other: Position, { boundsCheck = true } = { } ): Position {
let resultChar = this.isBOLDiff() ? 0 : this.character + other.character;
let resultLine = this.line + other.line;

if (boundsCheck) {
if (resultChar < 0) { resultChar = 0; }
if (resultLine < 0) { resultLine = 0; }
}

return new Position(
resultLine,
resultChar
);
}

/**
* Difference in lines.
*/
public get line(): number {
return this._line;
}

/**
* Difference in characters.
*/
public get character(): number {
return this._character;
}

/**
* Does this diff move the position to the beginning of the line?
*/
public isBOLDiff(): boolean {
return this._isBOLDiff;
}

public toString(): string {
if (this._isBOLDiff) {
return `[ Diff: BOL ]`;
}

return `[ Diff: ${ this._line } ${ this._character } ]`;
}
}

export class Position extends vscode.Position {
Expand Down Expand Up @@ -208,6 +277,10 @@ export class Position extends vscode.Position {
if (resultLine < 0) { resultLine = 0; }
}

if (other.isBOLDiff()) {
resultChar = 0;
}

return new Position(
resultLine,
resultChar
Expand Down

0 comments on commit 3dad7ca

Please sign in to comment.