diff --git a/botanjs/src/Components/Vim/Actions/PUT.js b/botanjs/src/Components/Vim/Actions/PUT.js index 2dbb263..e58c9f9 100644 --- a/botanjs/src/Components/Vim/Actions/PUT.js +++ b/botanjs/src/Components/Vim/Actions/PUT.js @@ -1,8 +1,6 @@ (function(){ var ns = __namespace( "Components.Vim.Actions" ); - var Mesg = __import( "Components.Vim.Message" ); - /** @type {Components.Vim.State.Stator} */ var Stator = __import( "Components.Vim.State.Stator" ); /** @type {Components.Vim.State.Stack} */ diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index 587cda3..e129357 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -3,6 +3,10 @@ /** @type {System.Debug} */ var debug = __import( "System.Debug" ); + + /** @type {Components.Vim.Ex.Search} */ + var ExSearch = __import( "Components.Vim.Ex.Search" ); + var beep = ns[ NS_INVOKE ]( "Beep" ); var SHIFT = 1 << 9; @@ -14,8 +18,12 @@ var KEY_ALT = 18; var BACKSPACE = 8; + var TAB = 9; + var ENTER = 13; var DELETE = 46; + var UP = 38; var DOWN = 40; var LEFT = 37; var RIGHT = 39; + var _0 = 48; var _1 = 49; var _2 = 50; var _3 = 51; var _4 = 52; var _5 = 53; var _6 = 54; var _7 = 55; var _8 = 56; var _9 = 57; @@ -70,6 +78,13 @@ { case "BS": kCode = Mod + BACKSPACE; break; case "Del": kCode = Mod + DELETE; break; + case "Enter": kCode = Mod + ENTER; break; + case "Tab": kCode = Mod + TAB; break; + + case "Up": kCode = Mod + UP; break; + case "Down": kCode = Mod + DOWN; break; + case "Left": kCode = Mod + LEFT; break; + case "Right": kCode = Mod + RIGHT; break; case "A": Mod = SHIFT; case "a": kCode = Mod + A; break; case "B": Mod = SHIFT; case "b": kCode = Mod + B; break; @@ -127,6 +142,10 @@ this.__sfeeder = vimArea.statusFeeder; this.__ccur = this.__cfeeder.cursor; + + // Dived composite command handler + // Has full control of the key input, except Esc + this.__divedCCmd = null; }; Controls.prototype.__composite = function( e, handler ) @@ -183,6 +202,19 @@ case I: // Insert ccur.openAction( "INSERT" ); break; + + case SHIFT + O: // new line before insert + ccur.lineStart(); + ccur.openAction( "INSERT" ); + ccur.action.handler( new InputEvent( e.sender, "Enter" ) ); + ccur.moveY( -1 ); + break; + case O: // new line insert + ccur.lineEnd( true ); + ccur.openAction( "INSERT" ); + ccur.action.handler( new InputEvent( e.sender, "Enter" ) ); + break; + case U: // Undo ccur.openRunAction( "UNDO", e ); break; @@ -205,9 +237,15 @@ ccur.openRunAction( "PUT", e ); break; - case X: // Del - break; case SHIFT + X: // Delete before + if( !this.__cMoveX( -1 ) ) break; + case X: // Del + if( ccur.getLine().content == "" ) + { + beep(); + break; + } + ccur.openRunAction( "DELETE", e, ccur.aPos ); break; case SHIFT + U: // Undo previous changes in oneline break; @@ -240,7 +278,12 @@ var x = ccur.X; ccur.moveX( a, b, c || ccur.pSpace ); - if( ccur.X == x ) beep(); + if( ccur.X == x ) + { + beep(); + return false; + } + return true; }; Controls.prototype.__cMoveY = function( a ) @@ -252,16 +295,18 @@ ccur.moveY( a ); if( y == ( ccur.Y + cfeeder.panY ) ) { - if( 0 < a && !cfeeder.EOF ) return; + if( 0 < a && !cfeeder.EOF ) return true; beep(); } + + return false; }; Controls.prototype.__cursorCommand = function( e ) { var kCode = e.keyCode; - if( this.__cMovement && this.__composite ) + if( this.__cMovement ) { if( !e.ModKeys ) { @@ -396,9 +441,11 @@ }, _8 ); break; - case SLASH: // "/" Seach movement case SLASH: // "/" Seach movement this.__cMovement = true; + + this.__divedCCmd = new ExSearch( ccur ); + this.__divedCCmd.handler( e ); break; default: cursorHandled = false; @@ -420,12 +467,39 @@ ) return; // Clear composite command - if( e.Escape && this.__compositeReg ) + if( e.Escape ) { - this.__compositeReg = null; + var b = false; this.__cMovement = false; - beep(); - return; + + if( this.__compositeReg ) + { + b = true; + this.__compositeReg = null; + } + else if( this.__divedCCmd ) + { + b = true; + this.__divedCCmd.dispose(); + this.__divedCCmd = null; + } + + if( b ) + { + beep(); + return; + } + } + + if( this.__divedCCmd ) + { + if( this.__divedCCmd.handler( e ) ) + { + this.__divedCCmd.dispose(); + this.__cMovement = false; + this.__divedCCmd = null; + } + else return; } var cfeeder = this.__cfeeder; @@ -470,19 +544,30 @@ var InputEvent = function( sender, e ) { - this.__e = e; this.__target = sender; - var c = this.__e.keyCode; + if( typeof( e ) == "string" ) + { + this.__key = e; + this.__modKeys = 0; + this.__kCode = Map( e ); + this.__escape = this.__kCode == ESC; + } + else + { + this.__e = e; - this.__escape = c == ESC || ( e.ctrlKey && c == C ); - this.__kCode = c - + ( e.shiftKey || e.getModifierState( "CapsLock" ) ? SHIFT : 0 ) - + ( e.ctrlKey ? CTRL : 0 ) - + ( e.altKey ? ALT : 0 ); + var c = this.__e.keyCode; - this.__modKeys = c == KEY_SHIFT || c == KEY_CTRL || c == KEY_ALT; - this.__key = e.key; + this.__escape = c == ESC || ( e.ctrlKey && c == C ); + this.__kCode = c + + ( e.shiftKey || e.getModifierState( "CapsLock" ) ? SHIFT : 0 ) + + ( e.ctrlKey ? CTRL : 0 ) + + ( e.altKey ? ALT : 0 ); + + this.__modKeys = c == KEY_SHIFT || c == KEY_CTRL || c == KEY_ALT; + this.__key = e.key; + } this.__range = null; }; diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js index be80a42..bd1967d 100644 --- a/botanjs/src/Components/Vim/Cursor.js +++ b/botanjs/src/Components/Vim/Cursor.js @@ -396,11 +396,11 @@ }; // Open, Run, then close an action - Cursor.prototype.openRunAction = function( name, e ) + Cursor.prototype.openRunAction = function( name, e, arg1 ) { /** @type {Components.Vim.IAction} */ var action = new (Actions[ name ])( this ); - action.handler( e ); + action.handler( e, arg1 ); this.__pulseMsg = action.getMessage(); action.dispose(); @@ -497,6 +497,8 @@ return p; } ); + __readOnly( Cursor.prototype, "face", function() { return "\u2588"; } ); + __readOnly( Cursor.prototype, "message", function() { if( this.__pulseMsg ) diff --git a/botanjs/src/Components/Vim/Ex/Search.js b/botanjs/src/Components/Vim/Ex/Search.js new file mode 100644 index 0000000..169f5a5 --- /dev/null +++ b/botanjs/src/Components/Vim/Ex/Search.js @@ -0,0 +1,150 @@ +(function(){ + var ns = __namespace( "Components.Vim.Ex" ); + + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + /** @type {System.utils.Perf} */ + var Perf = __import( "System.utils.Perf" ); + + var Mesg = __import( "Components.Vim.Message" ); + + /** @type {Components.Vim.Cursor.IAction} */ + var Search = function( Cursor ) + { + var _self = this; + + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + + this.__statusBar = Cursor.Vim.statusBar; + + this.__command = []; + this.__blinkId = "ExSearchBlinkCycle" + Perf.uuid; + this.__curPos = 0; + + this.__disp = function() + { + }; + + var feeder = Cursor.feeder; + + var __blink = false; + var __holdBlink = false; + this.__blink = function() + { + __blink = true; + __holdBlink = true + }; + + Cycle.perma( this.__blinkId, function() + { + if( __holdBlink ) __holdBlink = false; + else __blink = !__blink; + + feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); + }, 600 ); + + this.__doBlink = function() + { + var c = ""; + var comm = _self.__command; + var pos = _self.__curPos; + var cLen = comm.length; + var faced = true; + + for( var i = 0; i < cLen; i ++ ) + { + var v = comm[i]; + if( __blink && i == pos ) + { + face = true; + v = Cursor.face + v.substr( 1 ); + } + + c+= v; + } + + if( __blink && cLen <= pos ) + { + c += Cursor.face; + } + + return c; + }; + + this.__statusBar.override = this.__doBlink; + }; + + Search.prototype.dispose = function() + { + this.__statusBar.override = null; + + Cycle.permaRemove( this.__blinkId ); + var feeder = this.__cursor.feeder; + feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); + }; + + Search.prototype.handler = function( e ) + { + e.preventDefault(); + + if( e.ModKeys ) return; + + this.__blink(); + + var InputKey = null; + + if( e.kMap( "Tab" ) ) + { + InputKey = "^I"; + } + else if( e.kMap( "C-v" ) ) + { + this.__direct = true; + } + else if( e.kMap( "BS" ) ) + { + this.__command.splice( --this.__curPos, 1 ); + if( this.__command.length == 0 ) return true; + } + else if( e.kMap( "Del" ) ) + { + this.__command.splice( this.__curPos, 1 ); + } + else if( e.kMap( "Enter" ) ) + { + return true; + } + else if( e.kMap( "Up" ) ) // History navigations + { + } + else if( e.kMap( "Down" ) ) + { + } + else if( e.kMap( "Left" ) ) + { + if( 0 < this.__curPos ) this.__curPos --; + } + else if( e.kMap( "Right" ) ) + { + if( this.__curPos < this.__command.length ) + this.__curPos ++; + } + else + { + InputKey = e.key; + } + + if( InputKey != null ) + { + this.__command.splice( this.__curPos ++, 0, InputKey ); + } + + var feeder = this.__cursor.feeder; + feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); + } + + ns[ NS_EXPORT ]( EX_CLASS, "Search", Search ); +})(); diff --git a/botanjs/src/Components/Vim/StatusBar.js b/botanjs/src/Components/Vim/StatusBar.js index 1a57d5c..81af357 100644 --- a/botanjs/src/Components/Vim/StatusBar.js +++ b/botanjs/src/Components/Vim/StatusBar.js @@ -10,6 +10,7 @@ { this.cols = cols; this.statStamp = {}; + this.override = null; }; StatusBar.prototype.stamp = function( pos, func ) @@ -17,8 +18,12 @@ this.statStamp[ pos ] = func; }; + StatusBar.prototype.override; + __readOnly( StatusBar.prototype, "statusText", function() { + if( this.override ) return this.override(); + var display = ""; var l = this.cols; diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index 95b02c6..c5480ec 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -123,9 +123,10 @@ { sfeeder.init( statusBar.statusText ); + var sLine = sfeeder.linesOccupied; element.value = - cfeeder.render( 0, r - sfeeder.linesOccupied ) - + "\n" + sfeeder.render(); + cfeeder.render( 0, r - sLine ) + + "\n" + sfeeder.render( 0, sLine < r ? sLine : r ); _self.__blink = false; _self.select( cfeeder.cursor.position ); diff --git a/botanjs/src/externs/Components.Vim.StatusBar.js b/botanjs/src/externs/Components.Vim.StatusBar.js index 356c980..8e43a79 100644 --- a/botanjs/src/externs/Components.Vim.StatusBar.js +++ b/botanjs/src/externs/Components.Vim.StatusBar.js @@ -3,5 +3,7 @@ Components.Vim.StatusBar = function(){}; /** @type Function */ Components.Vim.StatusBar.stamp; +/** @type Function */ +Components.Vim.StatusBar.override; /** @type String */ Components.Vim.StatusBar.statusText;