-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #144 from johnfn/visual-mode
Visual Mode + Rudimentary Operators
- Loading branch information
Showing
16 changed files
with
429 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
out | ||
node_modules | ||
typings | ||
*.swp | ||
*.sw? |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
"use strict"; | ||
|
||
import * as _ from 'lodash'; | ||
|
||
import { ModeName, Mode } from './mode'; | ||
import { Motion} from './../motion/motion'; | ||
import { Position } from './../motion/position'; | ||
import { Operator } from './../operator/operator'; | ||
import { DeleteOperator } from './../operator/delete'; | ||
import { ModeHandler } from './modeHandler.ts'; | ||
import { ChangeOperator } from './../operator/change'; | ||
|
||
export class VisualMode extends Mode { | ||
/** | ||
* The part of the selection that stays in the same place when motions are applied. | ||
*/ | ||
private _selectionStart: Position; | ||
|
||
/** | ||
* The part of the selection that moves. | ||
*/ | ||
private _selectionStop : Position; | ||
private _modeHandler : ModeHandler; | ||
|
||
private _keysToOperators: { [key: string]: Operator }; | ||
|
||
constructor(motion: Motion, modeHandler: ModeHandler) { | ||
super(ModeName.Visual, motion); | ||
|
||
this._modeHandler = modeHandler; | ||
this._keysToOperators = { | ||
// TODO: use DeleteOperator.key() | ||
|
||
// TODO: Don't pass in mode handler to DeleteOperators, | ||
// simply allow the operators to say what mode they transition into. | ||
'd': new DeleteOperator(modeHandler), | ||
'x': new DeleteOperator(modeHandler), | ||
'c': new ChangeOperator(modeHandler) | ||
}; | ||
} | ||
|
||
shouldBeActivated(key: string, currentMode: ModeName): boolean { | ||
return key === "v"; | ||
} | ||
|
||
async handleActivation(key: string): Promise<void> { | ||
this._selectionStart = this.motion.position; | ||
this._selectionStop = this._selectionStart; | ||
|
||
this.motion.select(this._selectionStart, this._selectionStop); | ||
} | ||
|
||
handleDeactivation(): void { | ||
super.handleDeactivation(); | ||
|
||
this.motion.moveTo(this._selectionStop.line, this._selectionStop.character); | ||
} | ||
|
||
/** | ||
* TODO: | ||
* | ||
* Eventually, the following functions should be moved into a unified | ||
* key handler and dispatcher thing. | ||
*/ | ||
|
||
private async _handleMotion(): Promise<boolean> { | ||
let keyHandled = false; | ||
let keysPressed: string; | ||
|
||
for (let window = this.keyHistory.length; window > 0; window--) { | ||
keysPressed = _.takeRight(this.keyHistory, window).join(''); | ||
if (this.keyToNewPosition[keysPressed] !== undefined) { | ||
keyHandled = true; | ||
break; | ||
} | ||
} | ||
|
||
if (keyHandled) { | ||
this._selectionStop = await this.keyToNewPosition[keysPressed](this._selectionStop); | ||
|
||
this.motion.moveTo(this._selectionStart.line, this._selectionStart.character); | ||
|
||
/** | ||
* Always select the letter that we started visual mode on, no matter | ||
* if we are in front or behind it. Imagine that we started visual mode | ||
* with some text like this: | ||
* | ||
* abc|def | ||
* | ||
* (The | represents the cursor.) If we now press w, we'll select def, | ||
* but if we hit b we expect to select abcd, so we need to getRight() on the | ||
* start of the selection when it precedes where we started visual mode. | ||
*/ | ||
|
||
// TODO this could be abstracted out | ||
if (this._selectionStart.compareTo(this._selectionStop) <= 0) { | ||
this.motion.select(this._selectionStart, this._selectionStop); | ||
} else { | ||
this.motion.select(this._selectionStart.getRight(), this._selectionStop); | ||
} | ||
|
||
this.keyHistory = []; | ||
} | ||
|
||
return keyHandled; | ||
} | ||
|
||
private async _handleOperator(): Promise<boolean> { | ||
let keysPressed: string; | ||
let operator: Operator; | ||
|
||
for (let window = this.keyHistory.length; window > 0; window--) { | ||
keysPressed = _.takeRight(this.keyHistory, window).join(''); | ||
if (this._keysToOperators[keysPressed] !== undefined) { | ||
operator = this._keysToOperators[keysPressed]; | ||
break; | ||
} | ||
} | ||
|
||
if (operator) { | ||
if (this._selectionStart.compareTo(this._selectionStop) <= 0) { | ||
await operator.run(this._selectionStart, this._selectionStop.getRight()); | ||
} else { | ||
await operator.run(this._selectionStart.getRight(), this._selectionStop); | ||
} | ||
} | ||
|
||
return !!operator; | ||
} | ||
|
||
async handleKeyEvent(key: string): Promise<void> { | ||
this.keyHistory.push(key); | ||
|
||
const wasMotion = await this._handleMotion(); | ||
|
||
if (!wasMotion) { | ||
await this._handleOperator(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.