penguin/AstroJS

Javascript framework for my blog

commit e52c312af5f72ab345105ac17d636a87c5a5bbb7

author斟酌 鵬兄 <tgckpg@gmail.com>
date2016-03-21T18:08:07Z
subjectadded g8, v ( hightlight only )
commit e52c312af5f72ab345105ac17d636a87c5a5bbb7
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2016-03-21T18:08:07Z

    added g8, v ( hightlight only )
    
    Some structural changes on VimControls
---
 botanjs/src/Components/Vim/Actions/INSERT.js    |   5 +-
 botanjs/src/Components/Vim/Actions/PRINT_HEX.js |  52 +++++
 botanjs/src/Components/Vim/Actions/VISUAL.js    |  67 ++++++
 botanjs/src/Components/Vim/Controls.js          | 277 +++++++++++++-----------
 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, 304 insertions(+), 135 deletions(-)

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 = [];
-	};
-
-	Controls.prototype.__comboG = function( keyCode )
-	{
-		var keyON = this.__keyChains[ 0 ] == G;
-		if( keyON )
-		{
-			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;
-			return true;
-		}
-
-		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; };
+		this.__cfeeder = vimArea.contentFeeder;
+		this.__sfeeder = vimArea.statusFeeder;
 
-	Controls.prototype.__comboKey = function( e )
-	{
-		return this.__comboG( e )
-			|| this.__comboD( e )
-			|| this.__comboT( e )
-			|| this.__comboLeftShift( e )
-			|| this.__comboRightShift( e );
+		this.__ccur = this.__cfeeder.cursor;
 	};
 
-	Controls.prototype.handler = function( sender, e )
+	Controls.prototype.__comp = function( kCode, handler )
 	{
-		// 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 )
+		if( handler )
 		{
-			this.__keyChains = [];
-			beep();
-			return;
+			if( !this.__compReg ) this.__compReg = [];
+			this.__compReg.push({
+				keys: Array.prototype.slice.call( arguments, 2 )
+				, handler: handler
+				, i: 0
+			});
+			return true;
 		}
 
-		if( cfeeder.cursor.action )
+		for( var i = 0; i < this.__compReg.length; i ++ )
 		{
-			if( Escape )
-			{
-				e.preventDefault();
-				cfeeder.cursor.closeAction();
-			}
-			else
+			var compReg = this.__compReg[i];
+			var keys = compReg.keys;
+
+			if( keys[ compReg.i ++ ] == kCode )
 			{
-				cfeeder.cursor.action.handler( e );
+				if( compReg.i == keys.length )
+				{
+					compReg.handler();
+					compReg = null;
+					this.__cMovement = false;
+				}
+
+				return true;
 			}
-			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();
-			}
-		};
+		if( this.__compReg ) beep();
+		this.__compReg = null;
+		this.__cMovement = false;
+		return false;
+	};
 
+	Controls.prototype.__actionCommand = function( e, kCode )
+	{
 		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;