diff --git a/botanjs/src/Components/Vim/Actions/DELETE.js b/botanjs/src/Components/Vim/Actions/DELETE.js new file mode 100644 index 0000000..113a417 --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/DELETE.js @@ -0,0 +1,32 @@ +(function(){ + var ns = __namespace( "Components.Vim.Actions" ); + + var Mesg = __import( "Components.Vim.Message" ); + + /** @type {Components.Vim.Cursor.IAction} */ + var DELETE = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + }; + + DELETE.prototype.allowMovement = true; + + DELETE.prototype.dispose = function() + { + + }; + + DELETE.prototype.handler = function( e ) + { + e.preventDefault(); + + }; + + DELETE.prototype.getMessage = function() + { + return " DELETE COMMAND"; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "DELETE", DELETE ); +})(); diff --git a/botanjs/src/Components/Vim/Actions/VISUAL.js b/botanjs/src/Components/Vim/Actions/VISUAL.js index 752eaec..dad2fbb 100644 --- a/botanjs/src/Components/Vim/Actions/VISUAL.js +++ b/botanjs/src/Components/Vim/Actions/VISUAL.js @@ -1,12 +1,17 @@ (function(){ var ns = __namespace( "Components.Vim.Actions" ); - /** @type {Components.Vim.State.Stack} */ - var Stack = __import( "Components.Vim.State.Stack" ); /** @type {System.Debug} */ - var debug = __import( "System.Debug" ); + var debug = __import( "System.Debug" ); var Mesg = __import( "Components.Vim.Message" ); + /** @type {Components.Vim.Controls} */ + var Controls = __import( "Components.Vim.Controls" ); + + /** @type {Components.Vim.Cursor.IAction} */ + var YANK = ns[ NS_INVOKE ]( "YANK" ); + /** @type {Components.Vim.Cursor.IAction} */ + var DELETE = ns[ NS_INVOKE ]( "DELETE" ); /** @type {Components.Vim.Cursor.IAction} */ var VISUAL = function( Cursor ) @@ -16,6 +21,8 @@ this.__startaP = Cursor.aPos; this.__start = Cursor.PStart; this.__selStart = Cursor.PStart; + this.__msg = Mesg( "VISUAL" ); + this.__leaveMesg = ""; Cursor.blink = false; }; @@ -24,17 +31,38 @@ VISUAL.prototype.dispose = function() { + this.__msg = this.__leaveMesg; this.__cursor.blink = true; this.__cursor.PStart = this.__selStart; this.__cursor.PEnd = this.__selStart + 1; }; - - VISUAL.prototype.handler = function( e ) + VISUAL.prototype.handler = function( e, done ) { e.preventDefault(); - if( [ 16, 17, 18 ].indexOf( e.keyCode ) != -1 ) return; + if( Controls.ModKeys( e ) ) return; + + var Action = null; + switch( true ) + { + case Controls.KMap( e, "y" ): + Action = new YANK( this.__cursor ); + break; + case Controls.KMap( e, "d" ): + Action = new DELETE( this.__cursor ); + break; + } + + if( Action ) + { + Action.handler( e ); + this.__leaveMesg = Action.getMessage(); + Action.dispose(); + + return true; + } + var cur = this.__cursor; var prevPos = this.__start; var newPos = cur.PStart; @@ -58,9 +86,7 @@ VISUAL.prototype.getMessage = function() { - var msg = Mesg( "VISUAL" ); - - return msg; + return this.__msg; }; ns[ NS_EXPORT ]( EX_CLASS, "VISUAL", VISUAL ); diff --git a/botanjs/src/Components/Vim/Actions/YANK.js b/botanjs/src/Components/Vim/Actions/YANK.js new file mode 100644 index 0000000..ba987d7 --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/YANK.js @@ -0,0 +1,32 @@ +(function(){ + var ns = __namespace( "Components.Vim.Actions" ); + + var Mesg = __import( "Components.Vim.Message" ); + + /** @type {Components.Vim.Cursor.IAction} */ + var YANK = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + }; + + YANK.prototype.allowMovement = true; + + YANK.prototype.dispose = function() + { + + }; + + YANK.prototype.handler = function( e ) + { + e.preventDefault(); + + }; + + YANK.prototype.getMessage = function() + { + return " YANK COMMAND"; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "YANK", YANK ); +})(); diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index f55181b..918cc41 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -1,6 +1,7 @@ (function(){ var ns = __namespace( "Components.Vim" ); + /** @type {System.Debug} */ var debug = __import( "System.Debug" ); var beep = ns[ NS_INVOKE ]( "Beep" ); @@ -29,6 +30,81 @@ var F6 = 117; var F7 = 118; var F8 = 119; var F9 = 120; var F10 = 121; var F11 = 122; var F12 = 123; + var __maps = {}; + var Map = function( str ) + { + if( __maps[ str ] ) return __maps[ str ]; + + // C-Left, A-Up ... + var Code = str.split( "-" ); + var sCode = Code[0]; + + var Mod = 0; + if( Code.length == 2 ) + { + var m = true; + switch( Code[0] ) + { + case "C": Mod = CTRL; break; + case "A": Mod = ALT; break; + case "S": Mod = SHIFT; break; + default: + m = false; + } + + if( m ) + { + sCode = Code[1]; + } + } + + var kCode; + switch( sCode ) + { + case "A": Mod = SHIFT; case "a": kCode = Mod + A; break; + case "B": Mod = SHIFT; case "b": kCode = Mod + B; break; + case "C": Mod = SHIFT; case "c": kCode = Mod + C; break; + case "D": Mod = SHIFT; case "d": kCode = Mod + D; break; + case "E": Mod = SHIFT; case "e": kCode = Mod + E; break; + case "F": Mod = SHIFT; case "f": kCode = Mod + F; break; + case "G": Mod = SHIFT; case "g": kCode = Mod + G; break; + case "H": Mod = SHIFT; case "h": kCode = Mod + H; break; + case "I": Mod = SHIFT; case "i": kCode = Mod + I; break; + case "J": Mod = SHIFT; case "j": kCode = Mod + J; break; + case "K": Mod = SHIFT; case "k": kCode = Mod + K; break; + case "L": Mod = SHIFT; case "l": kCode = Mod + L; break; + case "M": Mod = SHIFT; case "m": kCode = Mod + M; break; + case "N": Mod = SHIFT; case "n": kCode = Mod + N; break; + case "O": Mod = SHIFT; case "o": kCode = Mod + O; break; + case "P": Mod = SHIFT; case "p": kCode = Mod + P; break; + case "Q": Mod = SHIFT; case "q": kCode = Mod + Q; break; + case "R": Mod = SHIFT; case "r": kCode = Mod + R; break; + case "S": Mod = SHIFT; case "s": kCode = Mod + S; break; + case "T": Mod = SHIFT; case "t": kCode = Mod + T; break; + case "U": Mod = SHIFT; case "u": kCode = Mod + U; break; + case "V": Mod = SHIFT; case "v": kCode = Mod + V; break; + case "W": Mod = SHIFT; case "w": kCode = Mod + W; break; + case "X": Mod = SHIFT; case "x": kCode = Mod + X; break; + case "Y": Mod = SHIFT; case "y": kCode = Mod + Y; break; + case "Z": Mod = SHIFT; case "z": kCode = Mod + Z; break; + + case "!": Mod = SHIFT; case "1": kCode = Mod + _1; break; + case "@": Mod = SHIFT; case "2": kCode = Mod + _2; break; + case "#": Mod = SHIFT; case "3": kCode = Mod + _3; break; + case "$": Mod = SHIFT; case "4": kCode = Mod + _4; break; + case "%": Mod = SHIFT; case "5": kCode = Mod + _5; break; + case "^": Mod = SHIFT; case "6": kCode = Mod + _6; break; + case "&": Mod = SHIFT; case "7": kCode = Mod + _7; break; + case "*": Mod = SHIFT; case "8": kCode = Mod + _8; break; + case "(": Mod = SHIFT; case "9": kCode = Mod + _9; break; + case ")": Mod = SHIFT; case "0": kCode = Mod + _0; break; + default: + throw new Error( "No such keys: " + str ); + } + + return __maps[ str ] = kCode; + }; + var Controls = function( vimArea ) { /** @type {Components.Vim.VimArea} */ @@ -249,7 +325,10 @@ if( ccur.action.allowMovement ) this.__cursorCommand( e, kCode ); - ccur.action.handler( e ); + if( ccur.action.handler( e ) ) + { + ccur.closeAction(); + } } return; } @@ -260,5 +339,20 @@ if( this.__actionCommand( e, kCode ) ) return; }; + __static_method( Controls, "ModKeys", function( e ) + { + var c = e.keyCode; + return c == KEY_SHIFT || c == KEY_CTRL || c == KEY_ALT; + } ); + + __static_method( Controls, "KMap", function( e, map ) + { + var kCode = e.keyCode + + ( e.shiftKey || e.getModifierState( "CapsLock" ) ? SHIFT : 0 ) + + ( e.ctrlKey ? CTRL : 0 ); + + return kCode == Map( map ); + } ); + ns[ NS_EXPORT ]( EX_CLASS, "Controls", Controls ); })(); diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js index 51377a5..0481f30 100644 --- a/botanjs/src/Components/Vim/Cursor.js +++ b/botanjs/src/Components/Vim/Cursor.js @@ -82,6 +82,9 @@ this.blink = true; }; + // Set by VimArea + Cursor.prototype.Vim; + // Can only be 1, -1 // 0 will be treated as undefined Cursor.prototype.moveX = function( d, penentrate, phantomSpace ) @@ -259,6 +262,8 @@ this.updatePosition(); }; + // Open an action handler + // i.e. YANK, VISUAL, INSERT, UNDO, etc. Cursor.prototype.openAction = function( name ) { if( this.action ) this.action.dispose(); @@ -272,12 +277,13 @@ { if( !this.action ) return; this.action.dispose(); + this.__pulseMsg = this.action.getMessage(); this.action = null; - this.__pulseMsg = null; this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); }; + // Open, Run, then close an action Cursor.prototype.openRunAction = function( name, e ) { /** @type {Components.Vim.IAction} */ diff --git a/botanjs/src/Components/Vim/State/Registers.js b/botanjs/src/Components/Vim/State/Registers.js new file mode 100644 index 0000000..220fe70 --- /dev/null +++ b/botanjs/src/Components/Vim/State/Registers.js @@ -0,0 +1,50 @@ +(function(){ +/* From Vim, :help registers + There are ten types of registers: + 1. The unnamed register "" + 2. 10 numbered registers "0 to "9 + 3. The small delete register "- + 4. 26 named registers "a to "z or "A to "Z + 5. three read-only registers ":, "., "% + 6. alternate buffer register "# + 7. the expression register "= + 8. The selection and drop registers "*, "+ and "~ + 9. The black hole register "_ + 10. Last search pattern register "/ + i.e. 0123456789-abcdefghijklmnopqrstuvwxyz:.%$=*+~_/ +*/ + var ns = __namespace( "Components.Vim.State" ); + + var Registers = function() + { + this.__registers = {}; + }; + + Registers.prototype.unnamed = function( str ) + { + this.__registers[ "\"" ] = str; + }; + + Registers.prototype.yank = function( str ) + { + this.unnamed( str ); + this.__registers[ 0 ] = str; + }; + + Registers.prototype.change = function( str ) + { + this.unnamed( str ); + var r = this.__registers; + for( var i = 9; 1 < i; i -- ) + { + if( r[ i - 1 ] != undefined ) + { + r[ i ] = r[ i - 1 ]; + } + } + + r[ 1 ] = str; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "Registers", Registers ); +})(); diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index 8ecb7a9..d02bdf4 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -10,6 +10,9 @@ /** @type {System.Debug} */ var debug = __import( "System.Debug" ); + /** @type {Components.Vim.State.Registers} */ + var Registers = __import( "Components.Vim.State.Registers" ); + /** @type {Components.Vim.LineFeeder} */ var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" ); /** @type {Components.Vim.StatusBar} */ @@ -18,6 +21,8 @@ var VimControls = ns[ NS_INVOKE ]( "Controls" ); var mesg = ns[ NS_INVOKE ]( "Message" ); + var Insts = []; + var KeyHandler = function( sender, handler ) { return function( e ) @@ -58,6 +63,9 @@ // Init this.VisualizeVimFrame( element.value ); + + // Push this instance + Insts.push( this ); }; VimArea.prototype.select = function( sel ) @@ -86,6 +94,7 @@ // Content feeder var cfeeder = new LineFeeder( cRange, c ); + // Feed the contents to content feeder // This "\n" fixes the last line "\n" not displaying // it will be trimmed after saving cfeeder.init( content + "\n" ); @@ -94,19 +103,15 @@ sfeeder = new LineFeeder( r, c ); sfeeder.setRender( false ); - // XXX: Placeholder + // Set the Vim instance + cfeeder.cursor.Vim = this; + sfeeder.cursor.Vim = this; + + // Set the stamps var statusBar = new StatusBar( c ); - statusBar.stamp( -18, function(){ - return cfeeder.lineStat; - }); - - statusBar.stamp( -3, function(){ - return mesg( cfeeder.docPos ); - } ); - - statusBar.stamp( 0, function(){ - return cfeeder.cursor.message; - } ); + statusBar.stamp( -18, function(){ return cfeeder.lineStat; } ); + statusBar.stamp( -3, function(){ return mesg( cfeeder.docPos ); } ); + statusBar.stamp( 0, function(){ return cfeeder.cursor.message; } ); sfeeder.init( statusBar.statusText ); @@ -128,6 +133,7 @@ this.contentFeeder = cfeeder; this.statusFeeder = sfeeder; this.statusBar = statusBar; + this.registers = new Registers(); this.__cursor = cfeeder.cursor; @@ -148,6 +154,10 @@ ); }; + __readOnly( VimArea, "Instances", function() { + return Insts.slice(); + } ); + __readOnly( VimArea.prototype, "content", function() { return this.contentFeeder.content.slice( 0, -1 ); } ); diff --git a/botanjs/src/externs/Components.Vim.Controls.js b/botanjs/src/externs/Components.Vim.Controls.js new file mode 100644 index 0000000..6fec2e7 --- /dev/null +++ b/botanjs/src/externs/Components.Vim.Controls.js @@ -0,0 +1,7 @@ +/** @constructor */ +Components.Vim.Controls = function(){}; + +/** @type Function */ +Components.Vim.Controls.ModKeys; +/** @type Function */ +Components.Vim.Controls.KMap; diff --git a/botanjs/src/externs/Components.Vim.Cursor.js b/botanjs/src/externs/Components.Vim.Cursor.js index 0873383..76fef9d 100644 --- a/botanjs/src/externs/Components.Vim.Cursor.js +++ b/botanjs/src/externs/Components.Vim.Cursor.js @@ -1,6 +1,8 @@ /** @constructor */ Components.Vim.Cursor = function(){}; +/** @type {Components.Vim.VimArea} */ +Components.Vim.Cursor.Vim; /** @type {Components.Vim.LineFeeder} */ Components.Vim.Cursor.feeder; /** @type {Components.Vim.IAction} */ diff --git a/botanjs/src/externs/Components.Vim.State.Recorder.js b/botanjs/src/externs/Components.Vim.State.Recorder.js index 0303938..b39cbf9 100644 --- a/botanjs/src/externs/Components.Vim.State.Recorder.js +++ b/botanjs/src/externs/Components.Vim.State.Recorder.js @@ -2,8 +2,8 @@ Components.Vim.State.Recorder = function(){}; /** @type Function */ -Components.Vim.State.undo; +Components.Vim.State.Recorder.undo; /** @type Function */ -Components.Vim.State.redo; +Components.Vim.State.Recorder.redo; /** @type Function */ -Components.Vim.State.record; +Components.Vim.State.Recorder.record; diff --git a/botanjs/src/externs/Components.Vim.State.Registers.js b/botanjs/src/externs/Components.Vim.State.Registers.js new file mode 100644 index 0000000..75b9c13 --- /dev/null +++ b/botanjs/src/externs/Components.Vim.State.Registers.js @@ -0,0 +1,9 @@ +/** @constructor */ +Components.Vim.State.Registers = function(){}; + +/** @type Function */ +Components.Vim.State.Registers.change; +/** @type Function */ +Components.Vim.State.Registers.yank; +/** @type Function */ +Components.Vim.State.Registers.unnamed; diff --git a/botanjs/src/externs/Components.Vim.VimArea.js b/botanjs/src/externs/Components.Vim.VimArea.js index e71c020..982acda 100644 --- a/botanjs/src/externs/Components.Vim.VimArea.js +++ b/botanjs/src/externs/Components.Vim.VimArea.js @@ -12,3 +12,5 @@ Components.Vim.VimArea.statusBar; Components.Vim.VimArea.rows; /** @type {Number} */ Components.Vim.VimArea.cols; +/** @type {Array} */ +Components.Vim.VimArea.Instances;