From a847510f4965799000917bb5e147d9e72856fddb 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: Sat, 28 Jan 2017 12:18:19 +0800 Subject: [PATCH] VA_REC impl --- .../Components/Vim/Actions/EDITOR_COMMAND.js | 3 + botanjs/src/Components/Vim/Actions/VA_REC.js | 109 ++++++++++++++++++ botanjs/src/Components/Vim/Controls.js | 14 ++- botanjs/src/Components/Vim/VimArea.js | 63 +++++++++- botanjs/src/Components/Vim/_this.js | 6 +- botanjs/src/externs/Components.Vim.VimArea.js | 7 +- 6 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 botanjs/src/Components/Vim/Actions/VA_REC.js diff --git a/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js b/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js index d4de6dd..7b2a6f1 100644 --- a/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js +++ b/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js @@ -87,6 +87,9 @@ case "help": out[ CMD_TYPE ] = "HELP"; break; + case "varec": + out[ CMD_TYPE ] = "VA_REC"; + break; } if( range !== "" ) diff --git a/botanjs/src/Components/Vim/Actions/VA_REC.js b/botanjs/src/Components/Vim/Actions/VA_REC.js new file mode 100644 index 0000000..e86f503 --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/VA_REC.js @@ -0,0 +1,109 @@ +(function(){ + var ns = __namespace( "Components.Vim.Actions" ); + + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + /** @type {System.utils.EventKey} */ + var EventKey = __import( "System.utils.EventKey" ); + /** @type {Components.Vim.ActionEvent} */ + var ActionEvent = __import( "Components.Vim.ActionEvent" ); + + var Mesg = __import( "Components.Vim.Message" ); + + // Recording Sessions + var Sessions = []; + + /** @type {Components.Vim.IAction} */ + var VA_REC = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + this.__msg = Mesg( "VA_REC_START" ); + Cursor.suppressEvent(); + }; + + VA_REC.prototype.dispose = function() + { + this.__cursor.unsuppressEvent(); + }; + + VA_REC.prototype.handler = function( e, endReplay ) + { + if( endReplay ) + { + var msg = Mesg( "VA_REC_END" ); + var lastLine = Mesg( "WAIT_FOR_INPUT" ); + + var l = this.__cursor.feeder.firstBuffer.cols; + for( var i = msg.length; i < l; i ++ ) msg += " "; + + this.__msg = msg + "\n" + lastLine; + return; + } + + e.preventDefault(); + var inst = this.__cursor.Vim; + var sender = inst.stage; + var sIndex = inst.index; + + var session; + + if( Sessions[ sIndex ] ) + { + session = Sessions[ sIndex ]; + } + else + { + session = Sessions[ sIndex ] = {}; + } + + if( session.started ) + { + session.__dispose(); + this.__msg = "Exported Session Data"; + setTimeout( function() { + window.prompt( "Session data ( Ctrl + C )", JSON.stringify( session.data ) ); + }, 1 ); + return; + } + else + { + session.started = true; + } + + var sessData = session.data = []; + var lastTime = Date.now(); + + session.__event = new EventKey( + "KeyDown", function( e2 ) + { + var evt = new ActionEvent( sender, e2 ); + if( [ "Control", "Alt", "Shift" ].indexOf( e2.key ) != -1 ) return; + + var now = Date.now(); + sessData.push( now - lastTime, evt.keyCode ); + lastTime = now; + } + ); + + var feeder = this.__cursor.feeder; + + // Handles quit event on VimArea + session.__dispose = function() { + debug.Info( "VA_REC: Disposing active session" ); + delete Sessions[ sIndex ]; + sender.removeEventListener( session.__event ); + inst.removeEventListener( "Dispose", session.__dispose ); + }; + + inst.addEventListener( "Dispose", session.__dispose ); + sender.addEventListener( session.__event ); + }; + + VA_REC.prototype.getMessage = function() + { + return this.__msg; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "VA_REC", VA_REC ); +})(); diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index ba2fbc8..31d3cbd 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -90,6 +90,7 @@ case "Del": kCode = Mod + DELETE; break; case "Enter": kCode = Mod + ENTER; break; case "Tab": kCode = Mod + TAB; break; + case "Escape": kCode = Mod + ESC; break; case "Up": kCode = Mod + UP; break; case "Down": kCode = Mod + DOWN; break; @@ -148,7 +149,7 @@ { switch( kCode ) { - case SPACE: return " "; + case SPACE: case SHIFT + SPACE: return " "; case A: return "a"; case B: return "b"; case C: return "c"; case D: return "d"; case E: return "e"; case F: return "f"; case G: return "g"; case H: return "h"; case I: return "i"; case J: return "j"; case K: return "k"; case L: return "l"; @@ -188,7 +189,8 @@ case SHIFT + S: return "S"; case SHIFT + T: return "T"; case SHIFT + U: return "U"; case SHIFT + V: return "V"; case SHIFT + W: return "W"; case SHIFT + X: return "X"; case SHIFT + Y: return "Y"; case SHIFT + Z: return "Z"; - case ESC: return "Escape"; case BACKSPACE: return "Backspace"; case DELETE: return "Delete"; + case SHIFT + BACKSPACE: case BACKSPACE: return "Backspace"; + case ESC: return "Escape"; case DELETE: return "Delete"; case SHIFT: return "Shift"; case ALT: return "Alt"; case CTRL: return "Control"; case ENTER: return "Enter"; case TAB: return "Tab"; } @@ -484,7 +486,6 @@ } var ccur = this.__ccur; - var vima = this.__vimArea; var cfeeder = ccur.feeder; var cursorHandled = true; @@ -807,6 +808,13 @@ this.__kCode = Map( e ); this.__escape = this.__kCode == ESC; } + else if( typeof( e ) == "number" ) + { + this.__key = RMap( e ); + this.__modKeys = 0; + this.__kCode = e; + this.__escape = this.__kCode == ESC || this.__kCode == ( CTRL + C ); + } else { this.__e = e; diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index 433be5a..a1b57f5 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -24,7 +24,7 @@ var VimControls = ns[ NS_INVOKE ]( "Controls" ); var ActionEvent = ns[ NS_INVOKE ]( "ActionEvent" ); - var mesg = ns[ NS_INVOKE ]( "Message" ); + var Mesg = ns[ NS_INVOKE ]( "Message" ); var Insts = []; var InstIndex = 0; @@ -47,6 +47,8 @@ { if( !stage ) throw new Error( "Invalid argument" ); + EventDispatcher.call( this ); + stage = IDOMElement( stage ); var element = stage.element; @@ -99,6 +101,8 @@ Insts[ this.__instIndex ] = this; }; + __extends( VimArea, EventDispatcher ); + VimArea.prototype.__testScreen = function( handler ) { var area = this.stage.element; @@ -205,7 +209,7 @@ // 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( -3, function(){ return Mesg( cfeeder.docPos ); } ); statusBar.stamp( 0, function(){ return cfeeder.cursor.message; } ); sfeeder.init( statusBar.statusText ); @@ -261,6 +265,60 @@ this.stage.addEventListeners( this.__stagedEvents ); }; + VimArea.prototype.demo = function( seq ) + { + if( this.__demoActive ) return; + + var _self = this; + + this.__demoActive = true; + var l = seq.length; + + var s = 0; + + var controls = new VimControls( this ); + var cursor = this.__cursor; + var statusBar = this.statusBar; + + var demoEnd = function() + { + statusBar.stamp( 1, false ); + controls.handler( _self, new ActionEvent( _self, "Escape" ) ); + setTimeout( function() { + cursor.openRunAction( "VA_REC", undefined, true ); + _self.__demoActive = false; + _self.stage.addEventListeners( _self.__stagedEvents ); + }, 100 ); + }; + + var demoChain = function() + { + _self.stage.element.focus(); + + var key = seq[ s + 1 ]; + controls.handler( _self, new ActionEvent( _self, key ) ); + s += 2; + + if( s < l ) + { + // Wait time cannot be 0 + setTimeout( demoChain, seq[ s ] || 20 ); + } + else + { + setTimeout( demoEnd, 100 ); + } + }; + + statusBar.stamp( 1, function(){ return Mesg( "VA_REC_REPLAY" ); } ); + + var evts = this.__stagedEvents; + for( var i in evts ) this.stage.removeEventListener( evts[ i ] ); + this.__active = true; + + setTimeout( demoChain, seq[ s ] ); + }; + VimArea.prototype.dispose = function() { var stage = this.stage; @@ -272,6 +330,7 @@ debug.Info( "Destroy instance: " + id ); feeder.dispatcher.removeEventListener( "VisualUpdate", this.__visualUpdate ); + this.dispatchEvent( new BotanEvent( "Dispose" ) ); stage.removeAttribute( "data-vimarea" ); diff --git a/botanjs/src/Components/Vim/_this.js b/botanjs/src/Components/Vim/_this.js index e00d556..b221d18 100644 --- a/botanjs/src/Components/Vim/_this.js +++ b/botanjs/src/Components/Vim/_this.js @@ -1,4 +1,4 @@ -VIMRE_VERSION = "1.0.0b"; +var VIMRE_VERSION = "1.0.0"; (function(){ var ns = __namespace( "Components.Vim" ); @@ -31,6 +31,10 @@ VIMRE_VERSION = "1.0.0b"; , "SEARCH_HIT_BOTTOM": "search hit BOTTOM, continuing at TOP" , "SEARCH_HIT_TOP": "search hit TOP, continuing at BOTTOM" , "REPLACE": "%1 substitution(s) on %2 line(s)" + + , "VA_REC_START": "Recording Session ..." + , "VA_REC_REPLAY": "Replaying Session ..." + , "VA_REC_END": "Session Ended" }; var errors = { diff --git a/botanjs/src/externs/Components.Vim.VimArea.js b/botanjs/src/externs/Components.Vim.VimArea.js index 6d40d52..6e191f5 100644 --- a/botanjs/src/externs/Components.Vim.VimArea.js +++ b/botanjs/src/externs/Components.Vim.VimArea.js @@ -1,4 +1,6 @@ -/** @constructor */ +/** @constructor + * @extends {EventDispatcher} + */ Components.Vim.VimArea = function(){}; /** @type {Components.Vim.LineFeeder} */ @@ -10,6 +12,9 @@ Components.Vim.VimArea.statusFeeder; /** @type {Components.Vim.StatusBar} */ Components.Vim.VimArea.statusBar; +/** @type Function */ +Components.Vim.VimArea.demo; + /** @type Number */ Components.Vim.VimArea.index; /** @type Number */