forked from Botanical/BotanJS
		
	Merge remote-tracking branches 'origin/master' and 'vim/master' into Astro
This commit is contained in:
		
							
								
								
									
										112
									
								
								botanjs/src/Components/Vim/Actions/DELETE.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								botanjs/src/Components/Vim/Actions/DELETE.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
(function(){
 | 
			
		||||
	var ns = __namespace( "Components.Vim.Actions" );
 | 
			
		||||
 | 
			
		||||
	/** @type {System.Debug} */
 | 
			
		||||
	var debug = __import( "System.Debug" );
 | 
			
		||||
 | 
			
		||||
	/** @type {Components.Vim.State.Stator} */
 | 
			
		||||
	var Stator                                 = __import( "Components.Vim.State.Stator" );
 | 
			
		||||
	/** @type {Components.Vim.State.Stack} */
 | 
			
		||||
	var Stack                                  = __import( "Components.Vim.State.Stack" );
 | 
			
		||||
 | 
			
		||||
	var Mesg = __import( "Components.Vim.Message" );
 | 
			
		||||
 | 
			
		||||
	var occurence = __import( "System.utils.Perf.CountSubstr" );
 | 
			
		||||
 | 
			
		||||
	/** @type {Components.Vim.Cursor.IAction} */
 | 
			
		||||
	var DELETE = function( Cursor )
 | 
			
		||||
	{
 | 
			
		||||
		/** @type {Components.Vim.Cursor} */
 | 
			
		||||
		this.__cursor = Cursor;
 | 
			
		||||
		this.__nline = 0;
 | 
			
		||||
		this.__startX = Cursor.aPos;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	DELETE.prototype.allowMovement = true;
 | 
			
		||||
 | 
			
		||||
	DELETE.prototype.dispose = function()
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	DELETE.prototype.handler = function( e, sp )
 | 
			
		||||
	{
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		/** @type {Components.Vim.State.Registers} */
 | 
			
		||||
		var reg = e.target.registers;
 | 
			
		||||
 | 
			
		||||
		var cur = this.__cursor;
 | 
			
		||||
		var feeder = cur.feeder;
 | 
			
		||||
 | 
			
		||||
		var Triggered = false;
 | 
			
		||||
		if( sp == undefined && this.__startX != cur.aPos )
 | 
			
		||||
		{
 | 
			
		||||
			Triggered = true;
 | 
			
		||||
 | 
			
		||||
			if( e.kMap( "l" ) )
 | 
			
		||||
			{
 | 
			
		||||
				cur.moveX( -1 );
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			sp = this.__startX;
 | 
			
		||||
		}
 | 
			
		||||
		else if( sp == undefined ) return;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		var c = feeder.content;
 | 
			
		||||
 | 
			
		||||
		var s = sp;
 | 
			
		||||
		var e = cur.aPos;
 | 
			
		||||
 | 
			
		||||
		if( e < s )
 | 
			
		||||
		{
 | 
			
		||||
			s = cur.aPos;
 | 
			
		||||
			e = sp;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var removed = c.substring( s, e + 1 );
 | 
			
		||||
		reg.change( removed );
 | 
			
		||||
 | 
			
		||||
		this.__nline = occurence( removed, "\n" );
 | 
			
		||||
 | 
			
		||||
		feeder.content = c.substring( 0, s ) + c.substring( e + 1 );
 | 
			
		||||
 | 
			
		||||
		var stator = new Stator( cur, s );
 | 
			
		||||
		var stack = new Stack();
 | 
			
		||||
 | 
			
		||||
		c = c[ e + 1 ];
 | 
			
		||||
		if( c == "\n" || c == undefined )
 | 
			
		||||
		{
 | 
			
		||||
			cur.suppressEvent();
 | 
			
		||||
			cur.moveX( -1 );
 | 
			
		||||
			cur.unsuppressEvent();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var f = stator.save( 0, removed );
 | 
			
		||||
		stack.store( function() {
 | 
			
		||||
			f();
 | 
			
		||||
			// Offset correction after REDO / UNDO
 | 
			
		||||
			cur.moveX( 1 );
 | 
			
		||||
		} );
 | 
			
		||||
 | 
			
		||||
		cur.rec.record( stack );
 | 
			
		||||
 | 
			
		||||
		feeder.pan();
 | 
			
		||||
 | 
			
		||||
		return Triggered;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	DELETE.prototype.getMessage = function()
 | 
			
		||||
	{
 | 
			
		||||
		if( this.__nline )
 | 
			
		||||
		{
 | 
			
		||||
			return Mesg( "LINE_FEWER", this.__nline );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return "";
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	ns[ NS_EXPORT ]( EX_CLASS, "DELETE", DELETE );
 | 
			
		||||
})();
 | 
			
		||||
@@ -2,9 +2,11 @@
 | 
			
		||||
	var ns = __namespace( "Components.Vim.Actions" );
 | 
			
		||||
 | 
			
		||||
	/** @type {Components.Vim.State.Stack} */
 | 
			
		||||
	var Stack                                 = __import( "Components.Vim.State.Stack" );
 | 
			
		||||
	var Stack                                  = __import( "Components.Vim.State.Stack" );
 | 
			
		||||
	/** @type {Components.Vim.State.Stator} */
 | 
			
		||||
	var Stator                                 = __import( "Components.Vim.State.Stator" );
 | 
			
		||||
	/** @type {System.Debug} */
 | 
			
		||||
	var debug                                 = __import( "System.Debug" );
 | 
			
		||||
	var debug                                  = __import( "System.Debug" );
 | 
			
		||||
 | 
			
		||||
	var Mesg = __import( "Components.Vim.Message" );
 | 
			
		||||
 | 
			
		||||
@@ -27,40 +29,20 @@
 | 
			
		||||
		/** @type {Components.Vim.Cursor} */
 | 
			
		||||
		this.__cursor = Cursor;
 | 
			
		||||
 | 
			
		||||
		this.__startX = Cursor.aPos;
 | 
			
		||||
		this.__Stator = new Stator( Cursor );
 | 
			
		||||
 | 
			
		||||
		// Initialize this stack
 | 
			
		||||
		this.__rec( "", true );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	INSERT.prototype.allowMovement = false;
 | 
			
		||||
 | 
			
		||||
	INSERT.prototype.dispose = function()
 | 
			
		||||
	{
 | 
			
		||||
		this.__cursor.moveX( -1 );
 | 
			
		||||
		this.__rec( "", true );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	INSERT.prototype.__storeState = function()
 | 
			
		||||
	{
 | 
			
		||||
		var cur = this.__cursor;
 | 
			
		||||
		var feeder = cur.feeder;
 | 
			
		||||
		var insertLength = this.__insertLength;
 | 
			
		||||
		var contentUndo = this.__contentUndo;
 | 
			
		||||
		var startPos = this.__startPosition;
 | 
			
		||||
		var startX = this.__startX;
 | 
			
		||||
 | 
			
		||||
		return function() {
 | 
			
		||||
			var contentRedo = feeder.content.substr( startPos, insertLength );
 | 
			
		||||
			feeder.content =
 | 
			
		||||
				feeder.content.substring( 0, startPos )
 | 
			
		||||
				+ contentUndo
 | 
			
		||||
				+ feeder.content.substring( startPos + insertLength );
 | 
			
		||||
			insertLength = contentUndo.length;
 | 
			
		||||
			contentUndo = contentRedo;
 | 
			
		||||
 | 
			
		||||
			feeder.pan();
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	INSERT.prototype.__rec = function( c, newRec )
 | 
			
		||||
	{
 | 
			
		||||
		if( newRec || !this.__stack )
 | 
			
		||||
@@ -73,7 +55,7 @@
 | 
			
		||||
				) return;
 | 
			
		||||
 | 
			
		||||
				this.__stack.store(
 | 
			
		||||
					this.__storeState()
 | 
			
		||||
					this.__Stator.save( this.__insertLength, this.__contentUndo )
 | 
			
		||||
				);
 | 
			
		||||
 | 
			
		||||
				this.__cursor.rec.record( this.__stack );
 | 
			
		||||
@@ -82,7 +64,6 @@
 | 
			
		||||
			this.__insertLength = 0;
 | 
			
		||||
			this.__contentUndo = "";
 | 
			
		||||
			this.__stack = new Stack();
 | 
			
		||||
			this.__startPosition = this.__cursor.aPos;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if( c == "\n" )
 | 
			
		||||
@@ -98,45 +79,37 @@
 | 
			
		||||
		var cur = this.__cursor;
 | 
			
		||||
		var feeder = cur.feeder;
 | 
			
		||||
 | 
			
		||||
		switch( e.keyCode )
 | 
			
		||||
		// Backspace
 | 
			
		||||
		if( e.kMap( "BS" ) )
 | 
			
		||||
		{
 | 
			
		||||
			case 8: // Backspace
 | 
			
		||||
				var oY = feeder.panY + cur.Y;
 | 
			
		||||
				if( cur.X == 0 && feeder.panY == 0 && cur.Y == 0 ) return;
 | 
			
		||||
			var oY = feeder.panY + cur.Y;
 | 
			
		||||
			if( cur.X == 0 && feeder.panY == 0 && cur.Y == 0 ) return;
 | 
			
		||||
 | 
			
		||||
				cur.moveX( -1, true, true );
 | 
			
		||||
			cur.moveX( -1, true, true );
 | 
			
		||||
 | 
			
		||||
				var f = cur.aPos;
 | 
			
		||||
			var f = cur.aPos;
 | 
			
		||||
 | 
			
		||||
				if( this.__insertLength <= 0 )
 | 
			
		||||
				{
 | 
			
		||||
					this.__contentUndo = feeder.content.substr( f, 1 ) + this.__contentUndo;
 | 
			
		||||
					this.__startPosition --;
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					this.__insertLength --;
 | 
			
		||||
				}
 | 
			
		||||
			if( this.__insertLength <= 0 )
 | 
			
		||||
			{
 | 
			
		||||
				this.__contentUndo = feeder.content.substr( f, 1 ) + this.__contentUndo;
 | 
			
		||||
				this.__insertLength --;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
				feeder.content =
 | 
			
		||||
					feeder.content.substring( 0, f )
 | 
			
		||||
					+ feeder.content.substring( f + 1 );
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
			case 46: // Delete
 | 
			
		||||
				var f = cur.aPos;
 | 
			
		||||
 | 
			
		||||
				this.__contentUndo += feeder.content.substr( f, 1 );
 | 
			
		||||
 | 
			
		||||
				feeder.content =
 | 
			
		||||
					feeder.content.substring( 0, f )
 | 
			
		||||
					+ feeder.content.substring( f + 1 );
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				// Do nothing
 | 
			
		||||
				return;
 | 
			
		||||
			feeder.content =
 | 
			
		||||
				feeder.content.substring( 0, f )
 | 
			
		||||
				+ feeder.content.substring( f + 1 );
 | 
			
		||||
		}
 | 
			
		||||
		else if( e.kMap( "Del" ) )
 | 
			
		||||
		{
 | 
			
		||||
			var f = cur.aPos;
 | 
			
		||||
 | 
			
		||||
			this.__contentUndo += feeder.content.substr( f, 1 );
 | 
			
		||||
 | 
			
		||||
			feeder.content =
 | 
			
		||||
				feeder.content.substring( 0, f )
 | 
			
		||||
				+ feeder.content.substring( f + 1 );
 | 
			
		||||
		}
 | 
			
		||||
		else return;
 | 
			
		||||
 | 
			
		||||
		feeder.pan();
 | 
			
		||||
		feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
 | 
			
		||||
@@ -163,12 +136,23 @@
 | 
			
		||||
			+ inputChar
 | 
			
		||||
			+ feeder.content.substring( f );
 | 
			
		||||
 | 
			
		||||
		feeder.pan();
 | 
			
		||||
		if( inputChar == "\n" )
 | 
			
		||||
		{
 | 
			
		||||
			feeder.softReset();
 | 
			
		||||
			feeder.pan();
 | 
			
		||||
			cur.moveY( 1 );
 | 
			
		||||
			cur.lineStart();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			feeder.pan();
 | 
			
		||||
			cur.moveX( 1, false, true );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
 | 
			
		||||
 | 
			
		||||
		this.__rec( inputChar );
 | 
			
		||||
 | 
			
		||||
		cur.moveX( 1 );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	INSERT.prototype.getMessage = function()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								botanjs/src/Components/Vim/Actions/PRINT_HEX.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								botanjs/src/Components/Vim/Actions/PRINT_HEX.js
									
									
									
									
									
										Normal file
									
								
							@@ -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 );
 | 
			
		||||
})();
 | 
			
		||||
							
								
								
									
										114
									
								
								botanjs/src/Components/Vim/Actions/VISUAL.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								botanjs/src/Components/Vim/Actions/VISUAL.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
(function(){
 | 
			
		||||
	var ns = __namespace( "Components.Vim.Actions" );
 | 
			
		||||
 | 
			
		||||
	/** @type {System.Debug} */
 | 
			
		||||
	var debug = __import( "System.Debug" );
 | 
			
		||||
 | 
			
		||||
	var Mesg = __import( "Components.Vim.Message" );
 | 
			
		||||
 | 
			
		||||
	/** @type {Components.Vim.Cursor.IAction} */
 | 
			
		||||
	var YANK = ns[ NS_INVOKE ]( "YANK" );
 | 
			
		||||
	/** @type {Components.Vim.Cursor.IAction} */
 | 
			
		||||
	var DELETE = ns[ NS_INVOKE ]( "DELETE" );
 | 
			
		||||
 | 
			
		||||
	/** @type {Components.Vim.Cursor.IAction} */
 | 
			
		||||
	var VISUAL = function( Cursor )
 | 
			
		||||
	{
 | 
			
		||||
		/** @type {Components.Vim.Cursor} */
 | 
			
		||||
		this.__cursor = Cursor;
 | 
			
		||||
		this.__startaP = Cursor.aPos;
 | 
			
		||||
		this.__startP = { x: Cursor.X, y: Cursor.Y, p: Cursor.P };
 | 
			
		||||
		this.__start = Cursor.PStart;
 | 
			
		||||
		this.__selStart = Cursor.PStart;
 | 
			
		||||
		this.__msg = Mesg( "VISUAL" );
 | 
			
		||||
		this.__leaveMesg = "";
 | 
			
		||||
 | 
			
		||||
		Cursor.blink = false;
 | 
			
		||||
		Cursor.pSpace = true;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VISUAL.prototype.allowMovement = true;
 | 
			
		||||
 | 
			
		||||
	VISUAL.prototype.dispose = function()
 | 
			
		||||
	{
 | 
			
		||||
		this.__msg = this.__leaveMesg;
 | 
			
		||||
		this.__cursor.blink = true;
 | 
			
		||||
		this.__cursor.pSpace = false;
 | 
			
		||||
		this.__cursor.PStart = this.__selStart;
 | 
			
		||||
		this.__cursor.PEnd = this.__selStart + 1;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VISUAL.prototype.handler = function( e, done )
 | 
			
		||||
	{
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
 | 
			
		||||
		if( e.ModKeys ) return;
 | 
			
		||||
 | 
			
		||||
		var cur = this.__cursor;
 | 
			
		||||
		var Action = null;
 | 
			
		||||
 | 
			
		||||
		if( e.kMap( "y" ) )
 | 
			
		||||
		{
 | 
			
		||||
			Action = new YANK( cur );
 | 
			
		||||
		}
 | 
			
		||||
		else if( e.kMap( "d" ) )
 | 
			
		||||
		{
 | 
			
		||||
			Action = new DELETE( cur );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if( Action )
 | 
			
		||||
		{
 | 
			
		||||
			cur.suppressEvent();
 | 
			
		||||
 | 
			
		||||
			// Low-level cursor position adjustment
 | 
			
		||||
			// this swap the cursor direction from LTR to RTL
 | 
			
		||||
			// i.e. treat all delete as "e<----s" flow
 | 
			
		||||
			// to keep the cursor position as the top on UNDO / REDO
 | 
			
		||||
			if( Action.constructor == DELETE && this.__startaP < cur.aPos )
 | 
			
		||||
			{
 | 
			
		||||
				this.__startaP = cur.aPos;
 | 
			
		||||
				cur.X = this.__startP.x;
 | 
			
		||||
				cur.Y = this.__startP.y;
 | 
			
		||||
				cur.P = this.__startP.p;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Action.handler( e, this.__startaP );
 | 
			
		||||
			this.__leaveMesg = Action.getMessage();
 | 
			
		||||
 | 
			
		||||
			Action.dispose();
 | 
			
		||||
			cur.unsuppressEvent();
 | 
			
		||||
 | 
			
		||||
			this.__selStart = cur.PStart;
 | 
			
		||||
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			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()
 | 
			
		||||
	{
 | 
			
		||||
		return this.__msg;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	ns[ NS_EXPORT ]( EX_CLASS, "VISUAL", VISUAL );
 | 
			
		||||
})();
 | 
			
		||||
							
								
								
									
										32
									
								
								botanjs/src/Components/Vim/Actions/YANK.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								botanjs/src/Components/Vim/Actions/YANK.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
(function(){
 | 
			
		||||
	var ns = __namespace( "Components.Vim.Actions" );
 | 
			
		||||
 | 
			
		||||
	var Mesg = __import( "Components.Vim.Message" );
 | 
			
		||||
 | 
			
		||||
	/** @type {Components.Vim.Cursor.IAction} */
 | 
			
		||||
	var YANK = function( Cursor )
 | 
			
		||||
	{
 | 
			
		||||
		/** @type {Components.Vim.Cursor} */
 | 
			
		||||
		this.__cursor = Cursor;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	YANK.prototype.allowMovement = true;
 | 
			
		||||
 | 
			
		||||
	YANK.prototype.dispose = function()
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	YANK.prototype.handler = function( e )
 | 
			
		||||
	{
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	YANK.prototype.getMessage = function()
 | 
			
		||||
	{
 | 
			
		||||
		return "<TODO> YANK COMMAND";
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	ns[ NS_EXPORT ]( EX_CLASS, "YANK", YANK );
 | 
			
		||||
})();
 | 
			
		||||
@@ -1,13 +1,20 @@
 | 
			
		||||
(function(){
 | 
			
		||||
	var ns = __namespace( "Components.Vim" );
 | 
			
		||||
 | 
			
		||||
	/** @type {System.Debug} */
 | 
			
		||||
	var debug = __import( "System.Debug" );
 | 
			
		||||
	var beep = ns[ NS_INVOKE ]( "Beep" );
 | 
			
		||||
 | 
			
		||||
	var SHIFT = 1 << 9;
 | 
			
		||||
	var CTRL = 1 << 10;
 | 
			
		||||
	var ALT = 1 << 11;
 | 
			
		||||
 | 
			
		||||
	var KEY_SHIFT = 16;
 | 
			
		||||
	var KEY_CTRL = 17;
 | 
			
		||||
	var KEY_ALT = 18;
 | 
			
		||||
 | 
			
		||||
	var BACKSPACE = 8;
 | 
			
		||||
	var DELETE = 46;
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
@@ -19,151 +26,159 @@
 | 
			
		||||
	var U = 85; var V = 86; var W = 87; var X = 88; var Y = 89;
 | 
			
		||||
	var Z = 90;
 | 
			
		||||
 | 
			
		||||
	var S_BRACKET_L = 219; var S_BRACKET_R = 221;
 | 
			
		||||
 | 
			
		||||
	var ESC = 27;
 | 
			
		||||
 | 
			
		||||
	var F1 = 112; var F2 = 113; var F3 = 114; var F4 = 115; var F5 = 116;
 | 
			
		||||
	var F6 = 117; var F7 = 118; var F8 = 119; var F9 = 120; var F10 = 121;
 | 
			
		||||
	var F11 = 122; var F12 = 123;
 | 
			
		||||
 | 
			
		||||
	var COMMA = 188; var FULLSTOP = 190;
 | 
			
		||||
 | 
			
		||||
	var __maps = {};
 | 
			
		||||
	var Map = function( str )
 | 
			
		||||
	{
 | 
			
		||||
		if( __maps[ str ] ) return __maps[ str ];
 | 
			
		||||
 | 
			
		||||
		// C-Left, A-Up ...
 | 
			
		||||
		var Code = str.split( "-" );
 | 
			
		||||
		var sCode = Code[0];
 | 
			
		||||
 | 
			
		||||
		var Mod = 0;
 | 
			
		||||
		if( Code.length == 2 )
 | 
			
		||||
		{
 | 
			
		||||
			var m = true;
 | 
			
		||||
			switch( Code[0] )
 | 
			
		||||
			{
 | 
			
		||||
				case "C": Mod = CTRL; break;
 | 
			
		||||
				case "A": Mod = ALT; break;
 | 
			
		||||
				case "S": Mod = SHIFT; break;
 | 
			
		||||
				default:
 | 
			
		||||
					m = false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if( m )
 | 
			
		||||
			{
 | 
			
		||||
				sCode = Code[1];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var kCode;
 | 
			
		||||
		switch( sCode )
 | 
			
		||||
		{
 | 
			
		||||
			case "BS": kCode = Mod + BACKSPACE; break;
 | 
			
		||||
			case "Del": kCode = Mod + DELETE; break;
 | 
			
		||||
 | 
			
		||||
			case "A": Mod = SHIFT; case "a": kCode = Mod + A; break;
 | 
			
		||||
			case "B": Mod = SHIFT; case "b": kCode = Mod + B; break;
 | 
			
		||||
			case "C": Mod = SHIFT; case "c": kCode = Mod + C; break;
 | 
			
		||||
			case "D": Mod = SHIFT; case "d": kCode = Mod + D; break;
 | 
			
		||||
			case "E": Mod = SHIFT; case "e": kCode = Mod + E; break;
 | 
			
		||||
			case "F": Mod = SHIFT; case "f": kCode = Mod + F; break;
 | 
			
		||||
			case "G": Mod = SHIFT; case "g": kCode = Mod + G; break;
 | 
			
		||||
			case "H": Mod = SHIFT; case "h": kCode = Mod + H; break;
 | 
			
		||||
			case "I": Mod = SHIFT; case "i": kCode = Mod + I; break;
 | 
			
		||||
			case "J": Mod = SHIFT; case "j": kCode = Mod + J; break;
 | 
			
		||||
			case "K": Mod = SHIFT; case "k": kCode = Mod + K; break;
 | 
			
		||||
			case "L": Mod = SHIFT; case "l": kCode = Mod + L; break;
 | 
			
		||||
			case "M": Mod = SHIFT; case "m": kCode = Mod + M; break;
 | 
			
		||||
			case "N": Mod = SHIFT; case "n": kCode = Mod + N; break;
 | 
			
		||||
			case "O": Mod = SHIFT; case "o": kCode = Mod + O; break;
 | 
			
		||||
			case "P": Mod = SHIFT; case "p": kCode = Mod + P; break;
 | 
			
		||||
			case "Q": Mod = SHIFT; case "q": kCode = Mod + Q; break;
 | 
			
		||||
			case "R": Mod = SHIFT; case "r": kCode = Mod + R; break;
 | 
			
		||||
			case "S": Mod = SHIFT; case "s": kCode = Mod + S; break;
 | 
			
		||||
			case "T": Mod = SHIFT; case "t": kCode = Mod + T; break;
 | 
			
		||||
			case "U": Mod = SHIFT; case "u": kCode = Mod + U; break;
 | 
			
		||||
			case "V": Mod = SHIFT; case "v": kCode = Mod + V; break;
 | 
			
		||||
			case "W": Mod = SHIFT; case "w": kCode = Mod + W; break;
 | 
			
		||||
			case "X": Mod = SHIFT; case "x": kCode = Mod + X; break;
 | 
			
		||||
			case "Y": Mod = SHIFT; case "y": kCode = Mod + Y; break;
 | 
			
		||||
			case "Z": Mod = SHIFT; case "z": kCode = Mod + Z; break;
 | 
			
		||||
 | 
			
		||||
			case "!": Mod = SHIFT; case "1": kCode = Mod + _1; break;
 | 
			
		||||
			case "@": Mod = SHIFT; case "2": kCode = Mod + _2; break;
 | 
			
		||||
			case "#": Mod = SHIFT; case "3": kCode = Mod + _3; break;
 | 
			
		||||
			case "$": Mod = SHIFT; case "4": kCode = Mod + _4; break;
 | 
			
		||||
			case "%": Mod = SHIFT; case "5": kCode = Mod + _5; break;
 | 
			
		||||
			case "^": Mod = SHIFT; case "6": kCode = Mod + _6; break;
 | 
			
		||||
			case "&": Mod = SHIFT; case "7": kCode = Mod + _7; break;
 | 
			
		||||
			case "*": Mod = SHIFT; case "8": kCode = Mod + _8; break;
 | 
			
		||||
			case "(": Mod = SHIFT; case "9": kCode = Mod + _9; break;
 | 
			
		||||
			case ")": Mod = SHIFT; case "0": kCode = Mod + _0; break;
 | 
			
		||||
			case "<": Mod = SHIFT; case ",": kCode = Mod + COMMA; break;
 | 
			
		||||
			case ">": Mod = SHIFT; case ".": kCode = Mod + FULLSTOP; break;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				throw new Error( "Unsupport keys: " + str );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return __maps[ str ] = kCode;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	var Controls = function( vimArea )
 | 
			
		||||
	{
 | 
			
		||||
		/** @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();
 | 
			
		||||
					this.__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.__comboLeftShift = function( e ) { return false; };
 | 
			
		||||
 | 
			
		||||
	// >
 | 
			
		||||
	Controls.prototype.__comboRightShift = function( e ) { return false; };
 | 
			
		||||
 | 
			
		||||
	Controls.prototype.__comboKey = function( e )
 | 
			
		||||
	Controls.prototype.__actionCommand = function( e )
 | 
			
		||||
	{
 | 
			
		||||
		return this.__comboG( e )
 | 
			
		||||
			|| this.__comboT( e )
 | 
			
		||||
			|| this.__comboLeftShift( e )
 | 
			
		||||
			|| this.__comboRightShift( e );
 | 
			
		||||
	};
 | 
			
		||||
		var ActionHandled = true;
 | 
			
		||||
		var ccur = this.__ccur;
 | 
			
		||||
 | 
			
		||||
	Controls.prototype.handler = function( sender, e )
 | 
			
		||||
	{
 | 
			
		||||
		// Neve capture these keys
 | 
			
		||||
		if( e.altKey
 | 
			
		||||
			// F2 - F12
 | 
			
		||||
			|| ( 112 < 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 == 27 || ( e.ctrlKey && e.keyCode == 67 );
 | 
			
		||||
 | 
			
		||||
		// Clear the keychains in combo commands
 | 
			
		||||
		if( Escape && this.__keyChains.length )
 | 
			
		||||
		// Action Command
 | 
			
		||||
		switch( e.keyCode )
 | 
			
		||||
		{
 | 
			
		||||
			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();
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		switch( kCode )
 | 
			
		||||
		{
 | 
			
		||||
			// Cursor movements
 | 
			
		||||
			case BACKSPACE: // Backspace, go back 1 char, regardless of line
 | 
			
		||||
				cMoveX( -1, true );
 | 
			
		||||
				break;
 | 
			
		||||
			case H: // Left
 | 
			
		||||
				cMoveX( -1 );
 | 
			
		||||
				break;
 | 
			
		||||
			case L: // Right
 | 
			
		||||
				cMoveX( 1 );
 | 
			
		||||
				break;
 | 
			
		||||
			case K: // Up
 | 
			
		||||
				cMoveY( -1 );
 | 
			
		||||
				break;
 | 
			
		||||
			case J: // Down
 | 
			
		||||
				cMoveY( 1 );
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			// Insert
 | 
			
		||||
			case SHIFT + A: // Append at the line end
 | 
			
		||||
				ccur.lineEnd();
 | 
			
		||||
			case A: // Append
 | 
			
		||||
				cMoveX( 1, true, true );
 | 
			
		||||
				ccur.openAction( "INSERT" );
 | 
			
		||||
				break;
 | 
			
		||||
				this.__cMoveX( 1, true, true );
 | 
			
		||||
			case I: // Insert
 | 
			
		||||
				ccur.openAction( "INSERT" );
 | 
			
		||||
				break;
 | 
			
		||||
			case U: // Undo
 | 
			
		||||
				ccur.openRunAction( "UNDO", e );
 | 
			
		||||
@@ -171,9 +186,10 @@
 | 
			
		||||
			case CTRL + R: // Redo
 | 
			
		||||
				ccur.openRunAction( "REDO", e );
 | 
			
		||||
				break;
 | 
			
		||||
			case X: // Del
 | 
			
		||||
			case D: // Del with motion
 | 
			
		||||
				ccur.openAction( "DELETE" );
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + A: // Append at the line end
 | 
			
		||||
			case X: // Del
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + X: // Delete before
 | 
			
		||||
				break;
 | 
			
		||||
@@ -181,37 +197,223 @@
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + I: // Append before the line start, after spaces
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + J: // Join lines
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + K: // Find the manual entry
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case SHIFT + G: // Goto last line
 | 
			
		||||
				ccur.moveY( Number.MAX_VALUE );
 | 
			
		||||
				ccur.moveX( Number.MAX_VALUE, true );
 | 
			
		||||
			case V: // Visual
 | 
			
		||||
				ccur.openAction( "VISUAL" );
 | 
			
		||||
				break;
 | 
			
		||||
			// remove characters
 | 
			
		||||
			case X: // Remove in cursor
 | 
			
		||||
			case SHIFT + V: // Visual line
 | 
			
		||||
				ccur.openAction( "VISUAL_LINE" );
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + X: // Remove before cursor
 | 
			
		||||
 | 
			
		||||
			case F1: // F1, help
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				ActionHandled = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return ActionHandled;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Controls.prototype.__cMoveX = function( a, b, c )
 | 
			
		||||
	{
 | 
			
		||||
		var ccur = this.__ccur;
 | 
			
		||||
 | 
			
		||||
		var x = ccur.X;
 | 
			
		||||
		ccur.moveX( a, b, c || ccur.pSpace );
 | 
			
		||||
		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 )
 | 
			
		||||
	{
 | 
			
		||||
		var kCode = e.keyCode;
 | 
			
		||||
 | 
			
		||||
		if( this.__cMovement && this.__comp )
 | 
			
		||||
		{
 | 
			
		||||
			if( !e.ModKeys )
 | 
			
		||||
			{
 | 
			
		||||
				this.__comp( kCode );
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var ccur = this.__ccur;
 | 
			
		||||
 | 
			
		||||
		var cursorHandled = true;
 | 
			
		||||
		switch( kCode )
 | 
			
		||||
		{
 | 
			
		||||
			case BACKSPACE: this.__cMoveX( -1, true ); break; // Backspace, go back 1 char
 | 
			
		||||
			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;
 | 
			
		||||
			case SHIFT + L: // Last line buffer
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + _4: // $, End
 | 
			
		||||
				ccur.lineEnd();
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + _5: // %, Find next item
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + _6: // ^, Start
 | 
			
		||||
				ccur.lineStart();
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + J: // Join lines
 | 
			
		||||
			case SHIFT + _4: // $, End
 | 
			
		||||
				ccur.lineEnd( ccur.pSpace );
 | 
			
		||||
				break;
 | 
			
		||||
			case SHIFT + K: // manual entry
 | 
			
		||||
			case SHIFT + G: // Goto last line
 | 
			
		||||
				ccur.moveY( Number.MAX_VALUE );
 | 
			
		||||
				ccur.moveX( Number.MAX_VALUE, true );
 | 
			
		||||
				break
 | 
			
		||||
 | 
			
		||||
			case SHIFT + _5: // %, Find next item
 | 
			
		||||
				break;
 | 
			
		||||
			case 112: // F1, help
 | 
			
		||||
			case T: // To
 | 
			
		||||
				break;
 | 
			
		||||
			case I: // In between boundary
 | 
			
		||||
				if( !ccur.action )
 | 
			
		||||
				{
 | 
			
		||||
					cursorHandled = false;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				this.__cMovement = true;
 | 
			
		||||
				// Word boundary
 | 
			
		||||
				this.__comp( kCode, function(){
 | 
			
		||||
					debug.Info( "Word boundary" );
 | 
			
		||||
				}, W );
 | 
			
		||||
				this.__comp( kCode, function(){
 | 
			
		||||
					debug.Info( "Bracket boundary [" );
 | 
			
		||||
				}, S_BRACKET_L );
 | 
			
		||||
				this.__comp( kCode, function(){
 | 
			
		||||
					debug.Info( "Bracket boundary ]" );
 | 
			
		||||
				}, S_BRACKET_R );
 | 
			
		||||
				this.__comp( kCode, function(){
 | 
			
		||||
					debug.Info( "Bracket boundary {" );
 | 
			
		||||
				}, SHIFT + S_BRACKET_L );
 | 
			
		||||
				this.__comp( kCode, function(){
 | 
			
		||||
					debug.Info( "Bracket boundary }" );
 | 
			
		||||
				}, SHIFT + S_BRACKET_R );
 | 
			
		||||
				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;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * sender @param  {Components.Vim.VimArea}
 | 
			
		||||
	 * e @param {Components.Vim.Controls.InputEvent}
 | 
			
		||||
	 * */
 | 
			
		||||
	Controls.prototype.handler = function( sender, e )
 | 
			
		||||
	{
 | 
			
		||||
		// Never capture these keys
 | 
			
		||||
		if( e.keyCode == ( ALT + D )
 | 
			
		||||
			// F2 - F12
 | 
			
		||||
			|| ( F1 < e.keyCode && e.keyCode <= F12 )
 | 
			
		||||
		) return;
 | 
			
		||||
 | 
			
		||||
		// Clear composite command
 | 
			
		||||
		if( e.Escape && this.__compReg )
 | 
			
		||||
		{
 | 
			
		||||
			this.__compReg = null;
 | 
			
		||||
			this.__cMovement = false;
 | 
			
		||||
			beep();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var cfeeder = this.__cfeeder;
 | 
			
		||||
		var ccur = this.__ccur;
 | 
			
		||||
 | 
			
		||||
		var kCode = e.keyCode;
 | 
			
		||||
 | 
			
		||||
		// Action commands are handled by the actions themselves
 | 
			
		||||
		if( ccur.action )
 | 
			
		||||
		{
 | 
			
		||||
			if( e.Escape )
 | 
			
		||||
			{
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				ccur.closeAction();
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				if( ccur.action.allowMovement )
 | 
			
		||||
					this.__cursorCommand( e, kCode );
 | 
			
		||||
 | 
			
		||||
				if( ccur.action.handler( e ) )
 | 
			
		||||
				{
 | 
			
		||||
					ccur.closeAction();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
 | 
			
		||||
		if( this.__cursorCommand( e ) ) return;
 | 
			
		||||
		if( this.__actionCommand( e ) ) return;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	var InputEvent = function( sender, e )
 | 
			
		||||
	{
 | 
			
		||||
		this.__e = e;
 | 
			
		||||
		this.__target = sender;
 | 
			
		||||
 | 
			
		||||
		var c = this.__e.keyCode;
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	__readOnly( InputEvent.prototype, "target", function() { return this.__target; } );
 | 
			
		||||
	__readOnly( InputEvent.prototype, "key", function() { return this.__key; } );
 | 
			
		||||
	__readOnly( InputEvent.prototype, "keyCode", function() { return this.__kCode; } );
 | 
			
		||||
	__readOnly( InputEvent.prototype, "ModKeys", function() { return this.__modKeys; } );
 | 
			
		||||
	__readOnly( InputEvent.prototype, "Escape", function() { return this.__escape; } );
 | 
			
		||||
 | 
			
		||||
	InputEvent.prototype.kMap = function( map )
 | 
			
		||||
	{
 | 
			
		||||
		return this.__kCode == Map( map );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	InputEvent.prototype.preventDefault = function()
 | 
			
		||||
	{
 | 
			
		||||
		if( this.__e ) this.__e.preventDefault();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	ns[ NS_EXPORT ]( EX_CLASS, "Controls", Controls );
 | 
			
		||||
	ns[ NS_EXPORT ]( EX_CLASS, "InputEvent", InputEvent );
 | 
			
		||||
})();
 | 
			
		||||
 
 | 
			
		||||
@@ -9,26 +9,6 @@
 | 
			
		||||
 | 
			
		||||
	var Actions = __import( "Components.Vim.Actions.*" );
 | 
			
		||||
 | 
			
		||||
	var GetLine = function( buffs, l )
 | 
			
		||||
	{
 | 
			
		||||
		/** @type {Components.Vim.LineBuffer} */
 | 
			
		||||
		var LineHead = buffs[0];
 | 
			
		||||
		l ++;
 | 
			
		||||
 | 
			
		||||
		for( var i = 0, line = LineHead;
 | 
			
		||||
			line && i < l; i ++ )
 | 
			
		||||
		{
 | 
			
		||||
			LineHead = line;
 | 
			
		||||
			while( line )
 | 
			
		||||
			{
 | 
			
		||||
				line = line.next;
 | 
			
		||||
				if( line.br ) break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return LineHead;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	var LineOffset = function( buffs, l )
 | 
			
		||||
	{
 | 
			
		||||
		/** @type {Components.Vim.LineBuffer} */
 | 
			
		||||
@@ -55,6 +35,25 @@
 | 
			
		||||
		return offset;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Rush cursor to wanted position "d" then get the actual position
 | 
			
		||||
	var GetRushPos = function( c, d )
 | 
			
		||||
	{
 | 
			
		||||
		var line = c.getLine();
 | 
			
		||||
		var l = c.Y + d;
 | 
			
		||||
		var i = c.Y;
 | 
			
		||||
 | 
			
		||||
		// First line ( visual ) does not count
 | 
			
		||||
		if( line != c.feeder.firstBuffer ) i --;
 | 
			
		||||
 | 
			
		||||
		for( ; i < l; line = line.nextLine )
 | 
			
		||||
		{
 | 
			
		||||
			if( line.placeholder ) break;
 | 
			
		||||
			if( line.br ) i ++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return i;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	var Cursor = function( feeder )
 | 
			
		||||
	{
 | 
			
		||||
		/** @type {Components.Vim.LineFeeder} */
 | 
			
		||||
@@ -72,14 +71,23 @@
 | 
			
		||||
		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;
 | 
			
		||||
		this.pSpace = false;
 | 
			
		||||
 | 
			
		||||
		this.__suppEvt = 0;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Set by VimArea
 | 
			
		||||
	Cursor.prototype.Vim;
 | 
			
		||||
 | 
			
		||||
	// Can only be 1, -1
 | 
			
		||||
	// 0 will be treated as undefined
 | 
			
		||||
	Cursor.prototype.moveX = function( d, penentrate, phantomSpace )
 | 
			
		||||
@@ -93,15 +101,18 @@
 | 
			
		||||
 | 
			
		||||
		var buffs = this.feeder.lineBuffers;
 | 
			
		||||
 | 
			
		||||
		if( penentrate && x < 0 && ( 0 < this.feeder.panY || 0 < this.Y ) )
 | 
			
		||||
		if( penentrate )
 | 
			
		||||
		{
 | 
			
		||||
			this.moveY( -1 );
 | 
			
		||||
			this.lineEnd( phantomSpace );
 | 
			
		||||
			return;
 | 
			
		||||
			if( x < 0 && ( 0 < this.feeder.panY || 0 < this.Y ) )
 | 
			
		||||
			{
 | 
			
		||||
				this.moveY( -1 );
 | 
			
		||||
				this.lineEnd( phantomSpace );
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/** @type {Components.Vim.LineBuffer} */
 | 
			
		||||
		var line = GetLine( buffs, this.Y );
 | 
			
		||||
		var line = this.getLine();
 | 
			
		||||
		var content = line.visualLines.join( "\n" );
 | 
			
		||||
		var cLen = content.length;
 | 
			
		||||
 | 
			
		||||
@@ -110,12 +121,12 @@
 | 
			
		||||
		// Include empty lines befor cursor end
 | 
			
		||||
		if( ( phantomSpace && cLen - 1 <= x ) || ( cLen == 1 && c == undefined ) )
 | 
			
		||||
		{
 | 
			
		||||
			x = d > 0 ? cLen - 1 : 0;
 | 
			
		||||
			x = 0 < d ? cLen - 1 : 0;
 | 
			
		||||
		}
 | 
			
		||||
		// ( 2 < cLen ) Exclude empty lines at cursor end
 | 
			
		||||
		else if( ( 2 < cLen && x == cLen - 1 && c == " " ) || c == undefined )
 | 
			
		||||
		else if( ( 2 <= cLen && x == cLen - 1 && c == " " ) || c == undefined )
 | 
			
		||||
		{
 | 
			
		||||
			x = d > 0 ? cLen - 2 : 0;
 | 
			
		||||
			x = 0 < d ? cLen - 2 : 0;
 | 
			
		||||
		}
 | 
			
		||||
		else if( c == "\n" )
 | 
			
		||||
		{
 | 
			
		||||
@@ -145,58 +156,98 @@
 | 
			
		||||
 | 
			
		||||
	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.__fireUpdate();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Cursor.prototype.__fireUpdate = function()
 | 
			
		||||
	{
 | 
			
		||||
		if( 0 < this.__suppEvt )
 | 
			
		||||
		{
 | 
			
		||||
			debug.Info( "Event suppressed, suppression level is: " + this.__suppEvt );
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Cursor.prototype.moveY = function( d, penentrate )
 | 
			
		||||
	{
 | 
			
		||||
		var i;
 | 
			
		||||
		var Y = this.Y + d;
 | 
			
		||||
		var feeder = this.feeder;
 | 
			
		||||
		var line;
 | 
			
		||||
 | 
			
		||||
		if( Y < 0 )
 | 
			
		||||
		{
 | 
			
		||||
			this.feeder.pan( undefined, d );
 | 
			
		||||
			feeder.pan( undefined, d );
 | 
			
		||||
 | 
			
		||||
			this.Y = 0;
 | 
			
		||||
			this.moveX();
 | 
			
		||||
			this.updatePosition();
 | 
			
		||||
 | 
			
		||||
			this.feeder.softReset();
 | 
			
		||||
			feeder.softReset();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		else if( this.feeder.moreAt < Y )
 | 
			
		||||
		// More at bottom, start panning
 | 
			
		||||
		else if( !feeder.EOF && feeder.moreAt < Y )
 | 
			
		||||
		{
 | 
			
		||||
			var feeder = this.feeder;
 | 
			
		||||
			var lastLine = feeder.lastBuffer.lineNum;
 | 
			
		||||
			var lineShift = Y - feeder.moreAt;
 | 
			
		||||
 | 
			
		||||
			var i = 0;
 | 
			
		||||
			while( !feeder.EOF )
 | 
			
		||||
			if( penentrate )
 | 
			
		||||
			{
 | 
			
		||||
				feeder.pan( undefined, lineShift + i );
 | 
			
		||||
				feeder.pan( undefined, Y - moreAt );
 | 
			
		||||
			}
 | 
			
		||||
			else if( feeder.linesTotal < Y )
 | 
			
		||||
			{
 | 
			
		||||
				while( !feeder.EOF )
 | 
			
		||||
				{
 | 
			
		||||
					feeder.pan( undefined, 1 );
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				i = GetRushPos( this, d );
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				var lastLine = feeder.lastBuffer.lineNum;
 | 
			
		||||
				var lineShift = Y - feeder.moreAt;
 | 
			
		||||
				var thisLine = this.getLine().lineNum;
 | 
			
		||||
 | 
			
		||||
				if( !feeder.EOF )
 | 
			
		||||
					feeder.pan( undefined, lineShift );
 | 
			
		||||
 | 
			
		||||
				// if it turns out to be the same line
 | 
			
		||||
				// before after panning
 | 
			
		||||
				// we keep scrolling it ( panning )
 | 
			
		||||
				// until the entire line cosumes the screen
 | 
			
		||||
				if( feeder.lastBuffer.lineNum == lastLine )
 | 
			
		||||
				while( !feeder.EOF && feeder.lastBuffer.lineNum == lastLine )
 | 
			
		||||
				{
 | 
			
		||||
					i ++;
 | 
			
		||||
					feeder.pan( undefined, 1 );
 | 
			
		||||
				}
 | 
			
		||||
				else break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// The line number cursor need to be in
 | 
			
		||||
			Y = lastLine + lineShift;
 | 
			
		||||
				// The line number cursor need to be in
 | 
			
		||||
				Y = thisLine + d;
 | 
			
		||||
 | 
			
		||||
			// Calculate the visual line position
 | 
			
		||||
			for( i = 0, line = feeder.firstBuffer;
 | 
			
		||||
				line != feeder.lastBuffer;
 | 
			
		||||
				line = line.next )
 | 
			
		||||
			{
 | 
			
		||||
				if( line.br ) i ++;
 | 
			
		||||
				if( line.lineNum == Y || line.next.placeholder ) break;
 | 
			
		||||
				i = this.Y;
 | 
			
		||||
				this.Y = 0;
 | 
			
		||||
				// Calculate the visual line position "i"
 | 
			
		||||
				for( var line = this.getLine();
 | 
			
		||||
					line && line.lineNum != Y && !line.placeholder;
 | 
			
		||||
					this.Y ++, line = this.getLine() )
 | 
			
		||||
				{
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				i = this.Y;
 | 
			
		||||
 | 
			
		||||
				// Check if this line is collapsed
 | 
			
		||||
				if( !feeder.EOF && feeder.lastBuffer.next.lineNum == line.lineNum )
 | 
			
		||||
				{
 | 
			
		||||
					// If yes, step back to last visible line
 | 
			
		||||
					i --;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			this.Y = i;
 | 
			
		||||
@@ -204,20 +255,18 @@
 | 
			
		||||
			this.moveX();
 | 
			
		||||
			this.updatePosition();
 | 
			
		||||
 | 
			
		||||
			// Because it is panned, soft reset is needed
 | 
			
		||||
			feeder.softReset();
 | 
			
		||||
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( 0 < d )
 | 
			
		||||
		{
 | 
			
		||||
			// If panning is forward
 | 
			
		||||
			// and next line does not exists
 | 
			
		||||
			line = this.getLine().nextLine;
 | 
			
		||||
			if( !line || line.placeholder )
 | 
			
		||||
			{
 | 
			
		||||
				// do nothing
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			var line = this.getLine();
 | 
			
		||||
			// If already at bottom
 | 
			
		||||
			if( line.nextLine.placeholder ) return;
 | 
			
		||||
 | 
			
		||||
			Y = GetRushPos( this, d );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.Y = Y;
 | 
			
		||||
@@ -226,25 +275,28 @@
 | 
			
		||||
		this.updatePosition();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Open an action handler
 | 
			
		||||
	// i.e. YANK, VISUAL, INSERT, UNDO, etc.
 | 
			
		||||
	Cursor.prototype.openAction = function( name )
 | 
			
		||||
	{
 | 
			
		||||
		if( this.action ) this.action.dispose();
 | 
			
		||||
		this.action = new (Actions[ name ])( this );
 | 
			
		||||
		this.__pulseMsg = null;
 | 
			
		||||
 | 
			
		||||
		this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
 | 
			
		||||
		this.__fireUpdate();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Cursor.prototype.closeAction = function()
 | 
			
		||||
	{
 | 
			
		||||
		if( !this.action ) return;
 | 
			
		||||
		this.action.dispose();
 | 
			
		||||
		this.__pulseMsg = this.action.getMessage();
 | 
			
		||||
		this.action = null;
 | 
			
		||||
		this.__pulseMsg = null;
 | 
			
		||||
 | 
			
		||||
		this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
 | 
			
		||||
		this.__fireUpdate();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Open, Run, then close an action
 | 
			
		||||
	Cursor.prototype.openRunAction = function( name, e )
 | 
			
		||||
	{
 | 
			
		||||
		/** @type {Components.Vim.IAction} */
 | 
			
		||||
@@ -253,22 +305,26 @@
 | 
			
		||||
		this.__pulseMsg = action.getMessage();
 | 
			
		||||
		action.dispose();
 | 
			
		||||
 | 
			
		||||
		this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
 | 
			
		||||
		this.__fireUpdate();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; };
 | 
			
		||||
	Cursor.prototype.unsuppressEvent = function() { -- this.__suppEvt; };
 | 
			
		||||
 | 
			
		||||
	Cursor.prototype.getLine = function()
 | 
			
		||||
	{
 | 
			
		||||
		var feeder = this.feeder;
 | 
			
		||||
		var line = feeder.firstBuffer;
 | 
			
		||||
		var eBuffer = feeder.lastBuffer.next;
 | 
			
		||||
		for( var i = 0;
 | 
			
		||||
			line != feeder.lastBuffer;
 | 
			
		||||
			line != eBuffer;
 | 
			
		||||
			line = line.next )
 | 
			
		||||
		{
 | 
			
		||||
			if( line.br ) i ++;
 | 
			
		||||
			if( this.Y == i ) break;
 | 
			
		||||
			if( this.Y == i ) return line;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return line;
 | 
			
		||||
		return null;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// The absX for current Line
 | 
			
		||||
@@ -356,8 +412,8 @@
 | 
			
		||||
	__readOnly( Cursor.prototype, "position", function()
 | 
			
		||||
	{
 | 
			
		||||
		return {
 | 
			
		||||
			start: this.P
 | 
			
		||||
			, end: this.P + 1
 | 
			
		||||
			start: this.PStart
 | 
			
		||||
			, end: this.PEnd
 | 
			
		||||
		};
 | 
			
		||||
	} );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@
 | 
			
		||||
	/** @type {Components.Vim.Cursor} */
 | 
			
		||||
	var Cursor = ns[ NS_INVOKE ]( "Cursor" );
 | 
			
		||||
 | 
			
		||||
	var occurence = __import( "System.utils.Perf.CountSubstr" );
 | 
			
		||||
 | 
			
		||||
	var Feeder = function( rows, cols )
 | 
			
		||||
	{
 | 
			
		||||
		var lineBuffers = [];
 | 
			
		||||
@@ -92,7 +94,7 @@
 | 
			
		||||
		this.__softRender = function()
 | 
			
		||||
		{
 | 
			
		||||
			var line = _self.lineBuffers[ _self.__rStart ];
 | 
			
		||||
			var steps = _self.__rLength;
 | 
			
		||||
			var steps = _self.__rLength + 1;
 | 
			
		||||
 | 
			
		||||
			for( var i = 0;
 | 
			
		||||
				line && i < steps && ( line = line.next ) && placeholdCond( line );
 | 
			
		||||
@@ -170,7 +172,7 @@
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	__readOnly( Feeder.prototype, "linesTotal", function() {
 | 
			
		||||
		return this.content.match( "\n" );
 | 
			
		||||
		return occurence( this.content, "\n" );
 | 
			
		||||
	} );
 | 
			
		||||
 | 
			
		||||
	__readOnly( Feeder.prototype, "firstBuffer", function() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								botanjs/src/Components/Vim/State/Registers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								botanjs/src/Components/Vim/State/Registers.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
(function(){
 | 
			
		||||
/*  From Vim, :help registers
 | 
			
		||||
	There are ten types of registers:
 | 
			
		||||
	1. The unnamed register ""
 | 
			
		||||
	2. 10 numbered registers "0 to "9
 | 
			
		||||
	3. The small delete register "-
 | 
			
		||||
	4. 26 named registers "a to "z or "A to "Z
 | 
			
		||||
	5. three read-only registers ":, "., "%
 | 
			
		||||
	6. alternate buffer register "#
 | 
			
		||||
	7. the expression register "=
 | 
			
		||||
	8. The selection and drop registers "*, "+ and "~ 
 | 
			
		||||
	9. The black hole register "_
 | 
			
		||||
	10. Last search pattern register "/
 | 
			
		||||
	i.e. 0123456789-abcdefghijklmnopqrstuvwxyz:.%$=*+~_/
 | 
			
		||||
*/
 | 
			
		||||
	var ns = __namespace( "Components.Vim.State" );
 | 
			
		||||
 | 
			
		||||
	var Registers = function()
 | 
			
		||||
	{
 | 
			
		||||
		this.__registers = {};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Registers.prototype.unnamed = function( str )
 | 
			
		||||
	{
 | 
			
		||||
		this.__registers[ "\"" ] = str;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Registers.prototype.yank = function( str )
 | 
			
		||||
	{
 | 
			
		||||
		this.unnamed( str );
 | 
			
		||||
		this.__registers[ 0 ] = str;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Registers.prototype.change = function( str )
 | 
			
		||||
	{
 | 
			
		||||
		this.unnamed( str );
 | 
			
		||||
		var r = this.__registers;
 | 
			
		||||
		for( var i = 9; 1 < i; i -- )
 | 
			
		||||
		{
 | 
			
		||||
			if( r[ i - 1 ] != undefined )
 | 
			
		||||
			{
 | 
			
		||||
				r[ i ] = r[ i - 1 ];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		r[ 1 ] = str;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	ns[ NS_EXPORT ]( EX_CLASS, "Registers", Registers );
 | 
			
		||||
})();
 | 
			
		||||
							
								
								
									
										71
									
								
								botanjs/src/Components/Vim/State/Stator.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								botanjs/src/Components/Vim/State/Stator.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
(function(){
 | 
			
		||||
	var ns = __namespace( "Components.Vim.State" );
 | 
			
		||||
 | 
			
		||||
	var Stator = function( cur, start )
 | 
			
		||||
	{
 | 
			
		||||
		this.__cursor = cur;
 | 
			
		||||
		this.__startPosition = start == undefined ? cur.aPos : start;
 | 
			
		||||
		this.__startState = this.__saveCur();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Stator.prototype.save = function( insertLength, contentUndo )
 | 
			
		||||
	{
 | 
			
		||||
		var cur = this.__cursor;
 | 
			
		||||
		var feeder = cur.feeder;
 | 
			
		||||
		var startPos = this.__startPosition;
 | 
			
		||||
 | 
			
		||||
		if( insertLength < 0 )
 | 
			
		||||
		{
 | 
			
		||||
			startPos += insertLength;
 | 
			
		||||
			insertLength = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var sSt = this.__startState;
 | 
			
		||||
		var eSt = this.__saveCur();
 | 
			
		||||
 | 
			
		||||
		var st = sSt;
 | 
			
		||||
		// Calling this repeatedly will swap between UNDO / REDO state
 | 
			
		||||
		return function() {
 | 
			
		||||
			var contentRedo = feeder.content.substr( startPos, insertLength );
 | 
			
		||||
			feeder.content =
 | 
			
		||||
				feeder.content.substring( 0, startPos )
 | 
			
		||||
				+ contentUndo
 | 
			
		||||
				+ feeder.content.substring( startPos + insertLength );
 | 
			
		||||
			insertLength = contentUndo.length;
 | 
			
		||||
			contentUndo = contentRedo;
 | 
			
		||||
 | 
			
		||||
			cur.PStart = st.p;
 | 
			
		||||
			cur.PEnd = st.p + 1;
 | 
			
		||||
			cur.X = st.x;
 | 
			
		||||
			cur.Y = st.y;
 | 
			
		||||
			feeder.panX = st.px;
 | 
			
		||||
			feeder.panY = st.py;
 | 
			
		||||
 | 
			
		||||
			feeder.pan();
 | 
			
		||||
 | 
			
		||||
			st = ( st == sSt ) ? eSt : sSt;
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Stator.prototype.__saveCur = function()
 | 
			
		||||
	{
 | 
			
		||||
		var c = this.__cursor;
 | 
			
		||||
		var obj = {
 | 
			
		||||
			p: c.PStart
 | 
			
		||||
			, x: c.X
 | 
			
		||||
			, y: c.Y
 | 
			
		||||
			, px: c.feeder.panX
 | 
			
		||||
			, py: c.feeder.panY
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		if( 0 < obj.x )
 | 
			
		||||
		{
 | 
			
		||||
			obj.p -= 1;
 | 
			
		||||
			obj.x -= 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return obj;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	ns[ NS_EXPORT ]( EX_CLASS, "Stator", Stator );
 | 
			
		||||
})();
 | 
			
		||||
@@ -10,14 +10,20 @@
 | 
			
		||||
	/** @type {System.Debug} */
 | 
			
		||||
	var debug                                   = __import( "System.Debug" );
 | 
			
		||||
 | 
			
		||||
	/** @type {Components.Vim.State.Registers} */
 | 
			
		||||
	var Registers                               = __import( "Components.Vim.State.Registers" );
 | 
			
		||||
 | 
			
		||||
	/** @type {Components.Vim.LineFeeder} */
 | 
			
		||||
	var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" );
 | 
			
		||||
	/** @type {Components.Vim.StatusBar} */
 | 
			
		||||
	var StatusBar = ns[ NS_INVOKE ]( "StatusBar" );
 | 
			
		||||
 | 
			
		||||
	var VimControls = ns[ NS_INVOKE ]( "Controls" );
 | 
			
		||||
	var InputEvent = ns[ NS_INVOKE ]( "InputEvent" );
 | 
			
		||||
	var mesg = ns[ NS_INVOKE ]( "Message" );
 | 
			
		||||
 | 
			
		||||
	var Insts = [];
 | 
			
		||||
 | 
			
		||||
	var KeyHandler = function( sender, handler )
 | 
			
		||||
	{
 | 
			
		||||
		return function( e )
 | 
			
		||||
@@ -26,7 +32,7 @@
 | 
			
		||||
			if ( e.keyCode ) code = e.keyCode;
 | 
			
		||||
			else if ( e.which ) code = e.which;
 | 
			
		||||
 | 
			
		||||
			handler( sender, e );
 | 
			
		||||
			handler( sender, new InputEvent( sender, e ) );
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@@ -53,17 +59,14 @@
 | 
			
		||||
 | 
			
		||||
		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; } );
 | 
			
		||||
 | 
			
		||||
		// Init
 | 
			
		||||
		this.VisualizeVimFrame( element.value );
 | 
			
		||||
 | 
			
		||||
		// Push this instance
 | 
			
		||||
		Insts.push( this );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VimArea.prototype.select = function( sel )
 | 
			
		||||
@@ -92,25 +95,24 @@
 | 
			
		||||
		// Content feeder
 | 
			
		||||
		var cfeeder = new LineFeeder( cRange, c );
 | 
			
		||||
 | 
			
		||||
		cfeeder.init( content );
 | 
			
		||||
		// Feed the contents to content feeder
 | 
			
		||||
		// This "\n" fixes the last line "\n" not displaying
 | 
			
		||||
		// it will be trimmed after saving
 | 
			
		||||
		cfeeder.init( content + "\n" );
 | 
			
		||||
 | 
			
		||||
		// Status can consumes up to full screen, I think
 | 
			
		||||
		sfeeder = new LineFeeder( r, c );
 | 
			
		||||
		sfeeder.setRender( false );
 | 
			
		||||
 | 
			
		||||
		// XXX: Placeholder
 | 
			
		||||
		// Set the Vim instance
 | 
			
		||||
		cfeeder.cursor.Vim = this;
 | 
			
		||||
		sfeeder.cursor.Vim = this;
 | 
			
		||||
 | 
			
		||||
		// 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( 0, function(){
 | 
			
		||||
			return cfeeder.cursor.message;
 | 
			
		||||
		} );
 | 
			
		||||
		statusBar.stamp( -18, function(){ return cfeeder.lineStat; } );
 | 
			
		||||
		statusBar.stamp( -3, function(){ return mesg( cfeeder.docPos ); } );
 | 
			
		||||
		statusBar.stamp( 0, function(){ return cfeeder.cursor.message; } );
 | 
			
		||||
 | 
			
		||||
		sfeeder.init( statusBar.statusText );
 | 
			
		||||
 | 
			
		||||
@@ -132,6 +134,7 @@
 | 
			
		||||
		this.contentFeeder = cfeeder;
 | 
			
		||||
		this.statusFeeder = sfeeder;
 | 
			
		||||
		this.statusBar = statusBar;
 | 
			
		||||
		this.registers = new Registers();
 | 
			
		||||
 | 
			
		||||
		this.__cursor = cfeeder.cursor;
 | 
			
		||||
 | 
			
		||||
@@ -139,15 +142,25 @@
 | 
			
		||||
		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, "Instances", function() {
 | 
			
		||||
		return Insts.slice();
 | 
			
		||||
	} );
 | 
			
		||||
 | 
			
		||||
	__readOnly( VimArea.prototype, "content", function() {
 | 
			
		||||
		return this.contentFeeder.content;
 | 
			
		||||
		return this.contentFeeder.content.slice( 0, -1 );
 | 
			
		||||
	} );
 | 
			
		||||
 | 
			
		||||
	ns[ NS_EXPORT ]( EX_CLASS, "VimArea", VimArea );
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
		"INSERT": "-- INSERT --"
 | 
			
		||||
		, "REPLACE": "-- REPLACE --"
 | 
			
		||||
		, "MORE": "-- MORE --"
 | 
			
		||||
		, "VISUAL": "-- VISUAL  --"
 | 
			
		||||
		, "VISLINE": "-- VISUAL LINE --"
 | 
			
		||||
		, "WRITE": "\"%1\" %2L, %3C written"
 | 
			
		||||
		, "CONTINUE": "Press ENTER or type command to continue"
 | 
			
		||||
@@ -16,6 +17,8 @@
 | 
			
		||||
 | 
			
		||||
		, "UNDO_LIMIT": "Already at oldest change"
 | 
			
		||||
		, "REDO_LIMIT": "Already at newest change"
 | 
			
		||||
 | 
			
		||||
		, "LINE_FEWER": "%1 fewer lines"
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	var errors = {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,10 @@
 | 
			
		||||
		Log.writeLine( e.name + "\n\t" + e.message + "\n\t" + e.stack, Log.ERROR );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	var Info = function(e)
 | 
			
		||||
	var Info = function()
 | 
			
		||||
	{
 | 
			
		||||
		if( st_info )
 | 
			
		||||
		Log.writeLine( e, Log.INFO );
 | 
			
		||||
		Log.writeLine( Array.prototype.join.call( arguments, " " ), Log.INFO );
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	var turnOff = function( what )
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								botanjs/src/externs/Components.Vim.Controls.InputEvent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								botanjs/src/externs/Components.Vim.Controls.InputEvent.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
/** @constructor */
 | 
			
		||||
Components.Vim.Controls.InputEvent = function(){};
 | 
			
		||||
 | 
			
		||||
/** @type {Components.Vim.VimArea} */
 | 
			
		||||
Components.Vim.Controls.InputEvent.target;
 | 
			
		||||
/** @type String */
 | 
			
		||||
Components.Vim.Controls.InputEvent.key;
 | 
			
		||||
/** @type Boolean */
 | 
			
		||||
Components.Vim.Controls.InputEvent.ModKeys;
 | 
			
		||||
/** @type Boolean */
 | 
			
		||||
Components.Vim.Controls.InputEvent.Escape;
 | 
			
		||||
/** @type Number */
 | 
			
		||||
Components.Vim.Controls.InputEvent.keyCode;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.Controls.InputEvent.kMap;
 | 
			
		||||
							
								
								
									
										2
									
								
								botanjs/src/externs/Components.Vim.Controls.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								botanjs/src/externs/Components.Vim.Controls.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
/** @constructor */
 | 
			
		||||
Components.Vim.Controls = function(){};
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
/** @constructor */
 | 
			
		||||
Components.Vim.Cursor = function(){};
 | 
			
		||||
 | 
			
		||||
/** @type {Components.Vim.VimArea} */
 | 
			
		||||
Components.Vim.Cursor.Vim;
 | 
			
		||||
/** @type {Components.Vim.LineFeeder} */
 | 
			
		||||
Components.Vim.Cursor.feeder;
 | 
			
		||||
/** @type {Components.Vim.IAction} */
 | 
			
		||||
@@ -24,13 +26,23 @@ Components.Vim.Cursor.openAction;
 | 
			
		||||
Components.Vim.Cursor.openRunAction;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.Cursor.closeAction;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.Cursor.suppressEvent;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.Cursor.unsuppressEvent;
 | 
			
		||||
 | 
			
		||||
/** @type {Boolean} */
 | 
			
		||||
Components.Vim.Cursor.blink;
 | 
			
		||||
/** @type {Boolean} */
 | 
			
		||||
Components.Vim.Cursor.pSpace;
 | 
			
		||||
/** @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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -7,3 +7,6 @@ Components.Vim.IAction.dispose;
 | 
			
		||||
Components.Vim.IAction.handler;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.IAction.getMessage;
 | 
			
		||||
 | 
			
		||||
/** @type Boolean */
 | 
			
		||||
Components.Vim.IAction.allowMovement;
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,8 @@ Components.Vim.LineFeeder.panY;
 | 
			
		||||
/** @type Number */
 | 
			
		||||
Components.Vim.LineFeeder.moreAt;
 | 
			
		||||
/** @type Number */
 | 
			
		||||
Components.Vim.LineFeeder.linesTotal;
 | 
			
		||||
/** @type Number */
 | 
			
		||||
Components.Vim.LineFeeder.linesOccupied;
 | 
			
		||||
/** @type String */
 | 
			
		||||
Components.Vim.LineFeeder.docPos;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@
 | 
			
		||||
Components.Vim.State.Recorder = function(){};
 | 
			
		||||
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.State.undo;
 | 
			
		||||
Components.Vim.State.Recorder.undo;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.State.redo;
 | 
			
		||||
Components.Vim.State.Recorder.redo;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.State.record;
 | 
			
		||||
Components.Vim.State.Recorder.record;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								botanjs/src/externs/Components.Vim.State.Registers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								botanjs/src/externs/Components.Vim.State.Registers.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/** @constructor */
 | 
			
		||||
Components.Vim.State.Registers = function(){};
 | 
			
		||||
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.State.Registers.change;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.State.Registers.yank;
 | 
			
		||||
/** @type Function */
 | 
			
		||||
Components.Vim.State.Registers.unnamed;
 | 
			
		||||
@@ -12,3 +12,5 @@ Components.Vim.VimArea.statusBar;
 | 
			
		||||
Components.Vim.VimArea.rows;
 | 
			
		||||
/** @type {Number} */
 | 
			
		||||
Components.Vim.VimArea.cols;
 | 
			
		||||
/** @type {Array} */
 | 
			
		||||
Components.Vim.VimArea.Instances;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user