Skip to content

Commit

Permalink
Merge pull request #174 from aioutecism/feature/motion-paragraph
Browse files Browse the repository at this point in the history
Support paragraph motions `{`, `}`
  • Loading branch information
aioutecism committed Apr 13, 2017
2 parents 29c7d7c + ee37359 commit 96f7c4d
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/Actions/Register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export class ActionRegister {
}
else if (stash.lineCount > 1) {
return ActionMoveCursor.byMotions({motions: [
MotionDirection.previous({n: textToPut.length - args.n!}),
MotionDirection.prev({n: textToPut.length - args.n!}),
]});
}
else {
Expand Down
10 changes: 5 additions & 5 deletions src/Dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ export class Dispatcher {
}

private switchMode(id: ModeID): void {
const previousMode = this._currentMode;
const lastMode = this._currentMode;

if (previousMode) {
previousMode.exit();
if (lastMode) {
lastMode.exit();
}

this._currentMode = this.modes[id];
Expand All @@ -88,8 +88,8 @@ export class Dispatcher {
commands.executeCommand('setContext', 'amVim.mode', this._currentMode.name);

// For use in repeat command
if (previousMode) {
this._currentMode.onDidRecordFinish(previousMode.recordedCommandMaps, previousMode.id);
if (lastMode) {
this._currentMode.onDidRecordFinish(lastMode.recordedCommandMaps, lastMode.id);
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/Mappers/SpecialKeys/Motion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {MotionWord} from '../../Motions/Word';
import {MotionMatch} from '../../Motions/Match';
import {MotionMatchPair} from '../../Motions/MatchPair';
import {MotionLine} from '../../Motions/Line';
import {MotionParagraph} from '../../Motions/Paragraph';
import {MotionDocument} from '../../Motions/Document';

interface MotionGenerator {
Expand Down Expand Up @@ -53,18 +54,21 @@ export class SpecialKeyMotion extends GenericMapper implements SpecialKeyCommon
{ keys: '0', motionGenerators: [MotionLine.start] },
{ keys: '$', motionGenerators: [MotionLine.end] },

{ keys: '-', motionGenerators: [MotionCharacter.up, MotionLine.firstNonBlank] },
{ keys: '+', motionGenerators: [MotionCharacter.down, MotionLine.firstNonBlank] },
{ keys: '-', motionGenerators: [MotionCharacter.up, MotionLine.firstNonBlank] },
{ keys: '+', motionGenerators: [MotionCharacter.down, MotionLine.firstNonBlank] },
{ keys: '_', motionGenerators: [
(args: {n?: number}) => MotionCharacter.down({ n: (args.n === undefined ? 0 : args.n - 1) }),
MotionLine.firstNonBlank
] },

{ keys: '{', motionGenerators: [MotionParagraph.prev] },
{ keys: '}', motionGenerators: [MotionParagraph.next] },

{ keys: 'g g', motionGenerators: [MotionDocument.toLineOrFirst, MotionLine.firstNonBlank] },
{ keys: 'G', motionGenerators: [MotionDocument.toLineOrLast, MotionLine.firstNonBlank] },

{ keys: 'space', motionGenerators: [MotionDirection.next] },
{ keys: 'backspace', motionGenerators: [MotionDirection.previous] },
{ keys: 'backspace', motionGenerators: [MotionDirection.prev] },
];

constructor() {
Expand Down
2 changes: 1 addition & 1 deletion src/Modes/Mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export abstract class Mode {
/**
* Override this to do something after recording ends.
*/
onDidRecordFinish(recordedCommandMaps: CommandMap[], previousModeID: ModeID): void {}
onDidRecordFinish(recordedCommandMaps: CommandMap[], lastModeID: ModeID): void {}

protected execute(): void {
if (this.executing) {
Expand Down
4 changes: 2 additions & 2 deletions src/Modes/Normal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,12 @@ export class ModeNormal extends Mode {
return Promise.resolve(true);
}

onDidRecordFinish(recordedCommandMaps: CommandMap[], previousModeID: ModeID): void {
onDidRecordFinish(recordedCommandMaps: CommandMap[], lastModeID: ModeID): void {
if (! recordedCommandMaps || recordedCommandMaps.length === 0) {
return;
}

if (previousModeID === ModeID.INSERT) {
if (lastModeID === ModeID.INSERT) {
recordedCommandMaps.forEach(map => map.isRepeating = true);

if (this._recordedCommandMaps === undefined) {
Expand Down
14 changes: 7 additions & 7 deletions src/Motions/Direction.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {window, Position} from 'vscode';
import {Motion} from './Motion';

enum Direction {Previous, Next}
enum Direction {Prev, Next}

export class MotionDirection extends Motion {

Expand All @@ -17,17 +17,17 @@ export class MotionDirection extends Motion {
this.n = args.n;
}

static previous(args: {n?: number} = {}): Motion {
static prev(args: {n?: number} = {}): Motion {
return new MotionDirection({
direction: Direction.Previous,
n: args.n
direction: Direction.Prev,
n: args.n,
});
}

static next(args: {n?: number} = {}): Motion {
return new MotionDirection({
direction: Direction.Next,
n: args.n
n: args.n,
});
}

Expand All @@ -36,7 +36,7 @@ export class MotionDirection extends Motion {

const activeTextEditor = window.activeTextEditor;

if (! activeTextEditor || this.direction === undefined) {
if (! activeTextEditor || this.direction === undefined || this.n === undefined) {
return from;
}

Expand All @@ -50,7 +50,7 @@ export class MotionDirection extends Motion {
return _lengthByLine[line];
};

const offset = this.direction === Direction.Previous ? -1 : +1;
const offset = this.direction === Direction.Prev ? -1 : +1;
let toLine = from.line;
let toCharacter = from.character;

Expand Down
128 changes: 128 additions & 0 deletions src/Motions/Paragraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import {window, TextDocument, Position} from 'vscode';
import {Motion} from './Motion';

enum Direction {Prev, Next}

export class MotionParagraph extends Motion {

private direction: Direction;
private n: number;

constructor(args: {direction: Direction, n?: number}) {
args.n = args.n === undefined ? 1 : args.n;

super();

this.direction = args.direction;
this.n = args.n;
}

static prev(args: {n?: number}): Motion {
return new MotionParagraph({
direction: Direction.Prev,
n: args.n,
});
}

static next(args: {n?: number}): Motion {
return new MotionParagraph({
direction: Direction.Next,
n: args.n,
});
}

apply(from: Position): Position {
from = super.apply(from);

const activeTextEditor = window.activeTextEditor;

if (! activeTextEditor || this.direction === undefined || this.n === undefined) {
return from;
}

const document = activeTextEditor.document;

for (let i = 0; i < this.n; i++) {
const result = this.applyOnce(document, from);

from = result.to;

if (result.shouldStop) {
break;
}
}

return from;
}

private applyOnce(
document: TextDocument,
from: Position,
): {
to: Position,
shouldStop: boolean,
} {
let toLine: number | undefined = undefined;
let toCharacter = 0;
let shouldStop = false;

// Skip first group of empty lines if currently on empty line.
let shouldSkip = MotionParagraph.isLineEmpty(document, from.line);

if (this.direction === Direction.Prev) {
for (let i = from.line - 1; i >= 0; i--) {
const isLineEmpty = MotionParagraph.isLineEmpty(document, i);

if (shouldSkip) {
if (!isLineEmpty) {
shouldSkip = false;
}
continue;
}

if (isLineEmpty) {
toLine = i;
break;
}
}

if (toLine === undefined) {
shouldStop = true;
toLine = 0;
}
}
else {
for (let i = from.line + 1; i < document.lineCount; i++) {
const isLineEmpty = MotionParagraph.isLineEmpty(document, i);

if (shouldSkip) {
if (!isLineEmpty) {
shouldSkip = false;
}
continue;
}

if (isLineEmpty) {
toLine = i;
break;
}
}

if (toLine === undefined) {
shouldStop = true;
toLine = document.lineCount - 1;
toCharacter = document.lineAt(toLine).text.length;
}
}

return {
to: new Position(toLine, toCharacter),
shouldStop: shouldStop,
};
}

private static isLineEmpty(document: TextDocument, line: number): boolean {
return document.lineAt(line).text === '';
}

}
34 changes: 17 additions & 17 deletions src/Motions/Word.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {window, TextDocument, Position} from 'vscode';
import {Motion} from './Motion';
import {WordCharacterKind, UtilWord} from '../Utils/Word';

enum MotionWordDirection {Previous, Next}
enum MotionWordDirection {Prev, Next}
enum MotionWordMatchKind {Start, End, Both}

export class MotionWord extends Motion {
Expand Down Expand Up @@ -47,7 +47,7 @@ export class MotionWord extends Motion {
useBlankSeparatedStyle?: boolean,
} = {}): Motion {
const obj = new MotionWord(args);
obj.direction = MotionWordDirection.Previous;
obj.direction = MotionWordDirection.Prev;
obj.matchKind = MotionWordMatchKind.Start;
return obj;
}
Expand All @@ -57,7 +57,7 @@ export class MotionWord extends Motion {
useBlankSeparatedStyle?: boolean,
} = {}): Motion {
const obj = new MotionWord(args);
obj.direction = MotionWordDirection.Previous;
obj.direction = MotionWordDirection.Prev;
obj.matchKind = MotionWordMatchKind.End;
return obj;
}
Expand Down Expand Up @@ -112,7 +112,7 @@ export class MotionWord extends Motion {
return from;
}

applyOnce(
private applyOnce(
document: TextDocument,
from: Position,
matchKind: MotionWordMatchKind,
Expand All @@ -125,8 +125,8 @@ export class MotionWord extends Motion {
shouldStop: boolean,
} {
let line = from.line;
let previousPosition: Position | undefined;
let previousCharacterKind: WordCharacterKind | undefined;
let lastPosition: Position | undefined;
let lastCharacterKind: WordCharacterKind | undefined;

if (this.direction === MotionWordDirection.Next) {
while (line < document.lineCount) {
Expand All @@ -137,15 +137,15 @@ export class MotionWord extends Motion {
const currentCharacterKind = UtilWord.getCharacterKind(
text.charCodeAt(character), this.useBlankSeparatedStyle);

if (previousPosition !== undefined && previousCharacterKind !== currentCharacterKind) {
if (lastPosition !== undefined && lastCharacterKind !== currentCharacterKind) {
let startPosition: Position | undefined;
let endPosition: Position | undefined;

if (currentCharacterKind !== WordCharacterKind.Blank) {
startPosition = new Position(line, character);
}
if (previousCharacterKind !== WordCharacterKind.Blank) {
endPosition = previousPosition;
if (lastCharacterKind !== WordCharacterKind.Blank) {
endPosition = lastPosition;
if (endPosition.isEqual(from)) {
endPosition = undefined;
}
Expand Down Expand Up @@ -188,8 +188,8 @@ export class MotionWord extends Motion {
}
}

previousPosition = new Position(line, character);
previousCharacterKind = currentCharacterKind;
lastPosition = new Position(line, character);
lastCharacterKind = currentCharacterKind;
character++;
}

Expand All @@ -209,7 +209,7 @@ export class MotionWord extends Motion {
shouldStop: true,
};
}
else if (this.direction === MotionWordDirection.Previous) {
else if (this.direction === MotionWordDirection.Prev) {
while (line >= 0) {
const text = document.lineAt(line).text + '\n';
let character = line === from.line ? from.character : text.length - 1;
Expand All @@ -218,12 +218,12 @@ export class MotionWord extends Motion {
const currentCharacterKind = UtilWord.getCharacterKind(
text.charCodeAt(character), this.useBlankSeparatedStyle);

if (previousPosition !== undefined && previousCharacterKind !== currentCharacterKind) {
if (lastPosition !== undefined && lastCharacterKind !== currentCharacterKind) {
let startPosition: Position | undefined;
let endPosition: Position | undefined;

if (previousCharacterKind !== WordCharacterKind.Blank) {
startPosition = previousPosition;
if (lastCharacterKind !== WordCharacterKind.Blank) {
startPosition = lastPosition;
if (startPosition.isEqual(from)) {
startPosition = undefined;
}
Expand Down Expand Up @@ -264,8 +264,8 @@ export class MotionWord extends Motion {
}
}

previousPosition = new Position(line, character);
previousCharacterKind = currentCharacterKind;
lastPosition = new Position(line, character);
lastCharacterKind = currentCharacterKind;
character--;
}

Expand Down
Loading

0 comments on commit 96f7c4d

Please sign in to comment.