penguin/AstroJS

Javascript framework for my blog

commit a847510f4965799000917bb5e147d9e72856fddb

author斟酌 鵬兄 <tgckpg@gmail.com>
date2017-01-28T04:18:19Z
subjectVA_REC impl
commit a847510f4965799000917bb5e147d9e72856fddb
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2017-01-28T04:18:19Z

    VA_REC impl
---
 .../src/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(-)

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 */