From e52c312af5f72ab345105ac17d636a87c5a5bbb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Tue, 22 Mar 2016 02:08:07 +0800 Subject: [PATCH] added g8, v ( hightlight only ) Some structural changes on VimControls --- botanjs/src/Components/Vim/Actions/INSERT.js | 5 +- .../src/Components/Vim/Actions/PRINT_HEX.js | 52 ++++ botanjs/src/Components/Vim/Actions/VISUAL.js | 67 +++++ botanjs/src/Components/Vim/Controls.js | 283 ++++++++++-------- botanjs/src/Components/Vim/Cursor.js | 15 +- botanjs/src/Components/Vim/VimArea.js | 14 +- botanjs/src/externs/Components.Vim.Cursor.js | 6 +- botanjs/src/externs/Components.Vim.IAction.js | 3 + 8 files changed, 307 insertions(+), 138 deletions(-) create mode 100644 botanjs/src/Components/Vim/Actions/PRINT_HEX.js create mode 100644 botanjs/src/Components/Vim/Actions/VISUAL.js diff --git a/botanjs/src/Components/Vim/Actions/INSERT.js b/botanjs/src/Components/Vim/Actions/INSERT.js index e6d4615..a199a5f 100644 --- a/botanjs/src/Components/Vim/Actions/INSERT.js +++ b/botanjs/src/Components/Vim/Actions/INSERT.js @@ -33,6 +33,8 @@ this.__rec( "", true ); }; + INSERT.prototype.allowMovement = false; + INSERT.prototype.__saveCur = function() { var c = this.__cursor; @@ -80,7 +82,8 @@ insertLength = contentUndo.length; contentUndo = contentRedo; - cur.P = st.p; + cur.PStart = st.p; + cur.PEnd = st.p + 1; cur.X = st.x; cur.Y = st.y; feeder.panX = st.px; diff --git a/botanjs/src/Components/Vim/Actions/PRINT_HEX.js b/botanjs/src/Components/Vim/Actions/PRINT_HEX.js new file mode 100644 index 0000000..c3efbbb --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/PRINT_HEX.js @@ -0,0 +1,52 @@ +(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" ); + + /** @type {Components.Vim.Cursor.IAction} */ + var PRINT_HEX = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + }; + + PRINT_HEX.prototype.dispose = function() + { + }; + + PRINT_HEX.prototype.handler = function( e ) + { + e.preventDefault(); + var str = unescape( encodeURIComponent( this.__cursor.feeder.content[ this.__cursor.aPos ] ) ); + var l = str.length; + var msg = []; + for( var i = 0; i < l; i ++ ) + { + msg[i] = str[i] == "\n" + ? "a" + : str.charCodeAt( i ).toString( 16 ) + ; + + if( msg[i].length == 1 ) + { + msg[i] = "0" + msg[i]; + } + else if( msg[i].length == 0 ) + { + msg[i] = "00"; + } + } + + this.__msg = msg.join( " " ); + }; + + PRINT_HEX.prototype.getMessage = function() + { + return this.__msg; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "PRINT_HEX", PRINT_HEX ); +})(); diff --git a/botanjs/src/Components/Vim/Actions/VISUAL.js b/botanjs/src/Components/Vim/Actions/VISUAL.js new file mode 100644 index 0000000..752eaec --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/VISUAL.js @@ -0,0 +1,67 @@ +(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 Mesg = __import( "Components.Vim.Message" ); + + /** @type {Components.Vim.Cursor.IAction} */ + var VISUAL = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + this.__startaP = Cursor.aPos; + this.__start = Cursor.PStart; + this.__selStart = Cursor.PStart; + + Cursor.blink = false; + }; + + VISUAL.prototype.allowMovement = true; + + VISUAL.prototype.dispose = function() + { + this.__cursor.blink = true; + this.__cursor.PStart = this.__selStart; + this.__cursor.PEnd = this.__selStart + 1; + }; + + + VISUAL.prototype.handler = function( e ) + { + e.preventDefault(); + + if( [ 16, 17, 18 ].indexOf( e.keyCode ) != -1 ) return; + var cur = this.__cursor; + var prevPos = this.__start; + var newPos = cur.PStart; + + var posDiff = newPos - prevPos; + if( 0 <= posDiff ) + { + this.__selStart = newPos; + newPos = newPos + 1; + } + else if( posDiff < 0 ) + { + prevPos += posDiff; + newPos = this.__start + 1; + this.__selStart = prevPos; + } + + cur.PStart = prevPos; + cur.PEnd = newPos; + }; + + VISUAL.prototype.getMessage = function() + { + var msg = Mesg( "VISUAL" ); + + return msg; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "VISUAL", VISUAL ); +})(); diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index 7f37de7..f55181b 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -7,6 +7,10 @@ var SHIFT = 1 << 9; var CTRL = 1 << 10; + var KEY_SHIFT = 16; + var KEY_CTRL = 17; + var KEY_ALT = 18; + var BACKSPACE = 8; var _0 = 48; var _1 = 49; var _2 = 50; var _3 = 51; var _4 = 52; @@ -29,132 +33,62 @@ { /** @type {Components.Vim.VimArea} */ this.__vimArea = vimArea - this.__keyChains = []; + + this.__cfeeder = vimArea.contentFeeder; + this.__sfeeder = vimArea.statusFeeder; + + this.__ccur = this.__cfeeder.cursor; }; - Controls.prototype.__comboG = function( keyCode ) + Controls.prototype.__comp = function( kCode, handler ) { - var keyON = this.__keyChains[ 0 ] == G; - if( keyON ) + if( handler ) { - var cursor = this.__vimArea.contentFeeder.cursor; - switch( keyCode ) - { - case G: - cursor.moveY( -Number.MAX_VALUE ); - cursor.moveX( -Number.MAX_VALUE, true ); - this.__keyChains = []; - return true; - default: - this.__keyChains = []; - beep(); - return true; - } - } - else if( keyCode == G ) - { - this.__keyChains[ 0 ] = G; + if( !this.__compReg ) this.__compReg = []; + this.__compReg.push({ + keys: Array.prototype.slice.call( arguments, 2 ) + , handler: handler + , i: 0 + }); return true; } + for( var i = 0; i < this.__compReg.length; i ++ ) + { + var compReg = this.__compReg[i]; + var keys = compReg.keys; + + if( keys[ compReg.i ++ ] == kCode ) + { + if( compReg.i == keys.length ) + { + compReg.handler(); + compReg = null; + this.__cMovement = false; + } + + return true; + } + } + + if( this.__compReg ) beep(); + this.__compReg = null; + this.__cMovement = false; return false; }; - Controls.prototype.__comboT = function( e ) { return false; }; - Controls.prototype.__comboD = function( e ) { return false; }; - - // < - Controls.prototype.__comboLeftShift = function( e ) { return false; }; - - // > - Controls.prototype.__comboRightShift = function( e ) { return false; }; - - Controls.prototype.__comboKey = function( e ) + Controls.prototype.__actionCommand = function( e, kCode ) { - return this.__comboG( e ) - || this.__comboD( e ) - || this.__comboT( e ) - || this.__comboLeftShift( e ) - || this.__comboRightShift( e ); - }; - - Controls.prototype.handler = function( sender, e ) - { - // Neve capture these keys - if( e.altKey - // F2 - F12 - || ( F1 < e.keyCode && e.keyCode < 124 ) - ) return; - - var vArea = this.__vimArea; - // Action Mode handled by the actions themselves - var cfeeder = vArea.contentFeeder; - - // Esc OR Ctrl + c - var Escape = e.keyCode == ESC || ( e.ctrlKey && e.keyCode == C ); - - // Clear the keychains in combo commands - if( Escape && this.__keyChains.length ) - { - this.__keyChains = []; - beep(); - return; - } - - if( cfeeder.cursor.action ) - { - if( Escape ) - { - e.preventDefault(); - cfeeder.cursor.closeAction(); - } - else - { - cfeeder.cursor.action.handler( e ); - } - return; - } - - e.preventDefault(); - var kCode = e.keyCode - + ( e.shiftKey || e.getModifierState( "CapsLock" ) ? SHIFT : 0 ) - + ( e.ctrlKey ? CTRL : 0 ); - - // Handles long commands - - if( this.__comboKey( kCode ) ) return; - - var cfeeder = vArea.contentFeeder; - var sfeeder = vArea.statusFeeder; - - var ccur = cfeeder.cursor; - - var cMoveX = function( a, b, c ) - { - var x = ccur.X; - ccur.moveX( a, b, c ); - if( ccur.X == x ) beep(); - }; - - var cMoveY = function( a ) - { - var y = ccur.Y + cfeeder.panY; - ccur.moveY( a ); - if( y == ( ccur.Y + cfeeder.panY ) ) - { - if( 0 < a && !cfeeder.EOF ) return; - beep(); - } - }; - var ActionHandled = true; - // Action Commands + var ccur = this.__ccur; + + // Action Command switch( kCode ) { case SHIFT + A: // Append at the line end ccur.lineEnd(); case A: // Append - cMoveX( 1, true, true ); + this.__cMoveX( 1, true, true ); case I: // Insert ccur.openAction( "INSERT" ); break; @@ -177,22 +111,67 @@ case SHIFT + K: // Find the manual entry break; + case V: // Visual + ccur.openAction( "VISUAL" ); + break; + case SHIFT + V: // Visual line + ccur.openAction( "VISUAL_LINE" ); + break; + case F1: // F1, help break; default: ActionHandled = false; } - if( ActionHandled ) return; + return ActionHandled; + }; - // Cursor Commands + Controls.prototype.__cMoveX = function( a, b, c ) + { + var ccur = this.__ccur; + + var x = ccur.X; + ccur.moveX( a, b, c ); + if( ccur.X == x ) beep(); + }; + + Controls.prototype.__cMoveY = function( a ) + { + var ccur = this.__ccur; + var cfeeder = this.__cfeeder; + + var y = ccur.Y + cfeeder.panY; + ccur.moveY( a ); + if( y == ( ccur.Y + cfeeder.panY ) ) + { + if( 0 < a && !cfeeder.EOF ) return; + beep(); + } + }; + + Controls.prototype.__cursorCommand = function( e, kCode ) + { + if( this.__cMovement && this.__comp ) + { + var k = e.keyCode; + if(!( k == KEY_SHIFT || k == KEY_CTRL || k == KEY_ALT )) + { + this.__comp( kCode ); + return true; + } + } + + var ccur = this.__ccur; + + var cursorHandled = true; switch( kCode ) { - case BACKSPACE: cMoveX( -1, true ); break; // Backspace, go back 1 char, regardless of line - case H: cMoveX( -1 ); break; // Left - case L: cMoveX( 1 ); break; // Right - case K: cMoveY( -1 ); break; // Up - case J: cMoveY( 1 ); break; // Down + case BACKSPACE: this.__cMoveX( -1, true ); break; // Backspace, go back 1 char, regardless of line + case H: this.__cMoveX( -1 ); break; // Left + case L: this.__cMoveX( 1 ); break; // Right + case K: this.__cMoveY( -1 ); break; // Up + case J: this.__cMoveY( 1 ); break; // Down case SHIFT + H: // First line buffer break; @@ -207,24 +186,78 @@ case SHIFT + G: // Goto last line ccur.moveY( Number.MAX_VALUE ); ccur.moveX( Number.MAX_VALUE, true ); - break; + break case SHIFT + _5: // %, Find next item break; + + case G: // Go to top + this.__cMovement = true; + this.__comp( kCode, function(){ + ccur.moveY( -Number.MAX_VALUE ); + ccur.moveX( -Number.MAX_VALUE, true ); + }, G ); + this.__comp( kCode, function(){ + ccur.openRunAction( "PRINT_HEX", e ); + }, _8 ); + break; + + default: + cursorHandled = false; } + return cursorHandled; + }; - // Integrated commands - switch( kCode ) + Controls.prototype.handler = function( sender, e ) + { + // Neve capture these keys + if( e.altKey + // F2 - F12 + || ( F1 < e.keyCode && e.keyCode < 124 ) + ) return; + + // Esc OR Ctrl + c + var Escape = e.keyCode == ESC || ( e.ctrlKey && e.keyCode == C ); + + // Clear composite command + if( Escape && this.__compReg ) { - case V: // Visual - ccur.openAction( "VISUAL" ); - break; - case SHIFT + V: // Visual line - ccur.openAction( "VISUAL_LINE" ); - break; + this.__compReg = null; + this.__cMovement = false; + beep(); + return; } + var cfeeder = this.__cfeeder; + var ccur = this.__ccur; + + var kCode = e.keyCode + + ( e.shiftKey || e.getModifierState( "CapsLock" ) ? SHIFT : 0 ) + + ( e.ctrlKey ? CTRL : 0 ); + + // Action commands are handled by the actions themselves + if( ccur.action ) + { + if( Escape ) + { + e.preventDefault(); + ccur.closeAction(); + } + else + { + if( ccur.action.allowMovement ) + this.__cursorCommand( e, kCode ); + + ccur.action.handler( e ); + } + return; + } + + e.preventDefault(); + + if( this.__cursorCommand( e, kCode ) ) return; + if( this.__actionCommand( e, kCode ) ) return; }; ns[ NS_EXPORT ]( EX_CLASS, "Controls", Controls ); diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js index f4b6d9b..51377a5 100644 --- a/botanjs/src/Components/Vim/Cursor.js +++ b/botanjs/src/Components/Vim/Cursor.js @@ -71,12 +71,15 @@ this.Y = 0; // The resulting position - this.P = 0; + this.PStart = 0; + this.PEnd = 1; // State recorder this.rec = new Recorder(); this.action = null; + + this.blink = true; }; // Can only be 1, -1 @@ -147,7 +150,11 @@ Cursor.prototype.updatePosition = function() { - this.P = this.X + LineOffset( this.feeder.lineBuffers, this.Y ); + var P = this.X + LineOffset( this.feeder.lineBuffers, this.Y ); + this.PStart = P; + this.PEnd = P + 1; + this.__p = P; + this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); }; @@ -383,8 +390,8 @@ __readOnly( Cursor.prototype, "position", function() { return { - start: this.P - , end: this.P + 1 + start: this.PStart + , end: this.PEnd }; } ); diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index 8452fab..8ecb7a9 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -53,12 +53,6 @@ var _self = this; - var controls = new VimControls( this ); - stage.addEventListener( - "KeyDown" - , KeyHandler( this, controls.handler.bind( controls ) ) - ); - stage.addEventListener( "Focus", function() { _self.__active = true; } ); stage.addEventListener( "Blur", function() { _self.__active = false; } ); @@ -141,11 +135,17 @@ Cycle.perma( "VimCursorBlinkCycle" + element.id, function() { _self.select( - ( _self.__blink = !_self.__blink ) + !_self.__cursor.blink || ( _self.__blink = !_self.__blink ) ? _self.__cursor.position : { start: 0, end: 0 } ); }, 600 ); + + var controls = new VimControls( this ); + this.stage.addEventListener( + "KeyDown" + , KeyHandler( this, controls.handler.bind( controls ) ) + ); }; __readOnly( VimArea.prototype, "content", function() { diff --git a/botanjs/src/externs/Components.Vim.Cursor.js b/botanjs/src/externs/Components.Vim.Cursor.js index ec39afc..0873383 100644 --- a/botanjs/src/externs/Components.Vim.Cursor.js +++ b/botanjs/src/externs/Components.Vim.Cursor.js @@ -25,12 +25,16 @@ Components.Vim.Cursor.openRunAction; /** @type Function */ Components.Vim.Cursor.closeAction; +/** @type {Boolean} */ +Components.Vim.Cursor.blink; /** @type {Array} */ Components.Vim.Cursor.lineBuffers; /** @type Number */ Components.Vim.Cursor.pX; /** @type Number */ -Components.Vim.Cursor.P; +Components.Vim.Cursor.PStart; +/** @type Number */ +Components.Vim.Cursor.PEnd; /** @type Number */ Components.Vim.Cursor.aX; /** @type Number */ diff --git a/botanjs/src/externs/Components.Vim.IAction.js b/botanjs/src/externs/Components.Vim.IAction.js index db82c97..22571a7 100644 --- a/botanjs/src/externs/Components.Vim.IAction.js +++ b/botanjs/src/externs/Components.Vim.IAction.js @@ -7,3 +7,6 @@ Components.Vim.IAction.dispose; Components.Vim.IAction.handler; /** @type Function */ Components.Vim.IAction.getMessage; + +/** @type Boolean */ +Components.Vim.IAction.allowMovement;