penguin/AstroJS

Javascript framework for my blog

commit 751530b42d7ea237677ac3333fc28b9fd42cab12

author斟酌 鵬兄 <tgckpg@gmail.com>
date2016-03-13T00:35:29Z
subjectSome navigation, but not working:(
commit 751530b42d7ea237677ac3333fc28b9fd42cab12
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2016-03-13T00:35:29Z

    Some navigation, but not working:(
---
 botanjs/src/Components/Vim/Cursor.js     | 162 +++++++++++++++++++++++++++++++
 botanjs/src/Components/Vim/LineBuffer.js | 111 +++++++++++++++++++++
 botanjs/src/Components/Vim/LineFeeder.js | 118 ++++------------------
 botanjs/src/Components/Vim/VimArea.js    |  94 +++++++++++-------
 botanjs/src/Components/Vim/_this.js      |   1 +
 5 files changed, 352 insertions(+), 134 deletions(-)

diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js
new file mode 100644
index 0000000..b72ea1b
--- /dev/null
+++ b/botanjs/src/Components/Vim/Cursor.js
@@ -0,0 +1,162 @@
+(function(){
+	var ns = __namespace( "Components.Vim" );
+
+	/** @type {Dandelion} */
+	var Dand                                    = __import( "Dandelion" );
+	/** @type {Dandelion.IDOMElement} */
+	var IDOMElement                             = __import( "Dandelion.IDOMElement" );
+	/** @type {Dandelion.IDOMObject} */
+	var IDOMObject                              = __import( "Dandelion.IDOMObject" );
+	/** @type {System.Cycle} */
+	var Cycle                                   = __import( "System.Cycle" );
+	/** @type {System.Debug} */
+	var debug                                   = __import( "System.Debug" );
+
+	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} */
+		var offset = 0;
+
+		for( var i = 0, line = buffs[0];
+			line && i < l; i ++ )
+		{
+			while( line )
+			{
+				if( line.br )
+				{
+					offset += line.prev.toString().length + 1;
+
+					// Empty line has a special space
+					if( line.content == "" ) offset ++;
+
+					line = line.next;
+					break;
+				}
+				else
+				{
+					if( offset == 0 ) offset -= 1;
+
+					if( line.next && !line.next.br )
+						offset += line.cols + 1;
+				}
+
+				line = line.next;
+			}
+		}
+
+		debug.Info( offset );
+
+		return offset;
+	};
+
+	var Cursor = function( buffs )
+	{
+		this.buffers = buffs;
+		this.cols = buffs[0].cols;
+
+		// The preferred X position
+		this.pX = 0;
+
+		// The displaying X position
+		this.X = 0;
+
+		// The current line resided
+		this.Y = 0;
+
+		// The resulting position
+		this.P = 0;
+	};
+
+	// Can only be 1, -1
+	// 0 will be treated as undefined
+	Cursor.prototype.moveX = function( d )
+	{
+		var x = this.pX;
+
+		var updatePx = Boolean( d );
+		if( updatePx ) x = this.X + d;
+
+		if( !d ) d = 1;
+
+		var buffs = this.buffers;
+
+		/** @type {Components.Vim.LineBuffer} */
+		var line = GetLine( buffs, this.Y );
+		var content = line.visualLines.join( "\n" );
+
+		var c = content[ x ];
+
+		if( c == undefined )
+		{
+			x = d > 0 ? content.length - 1 : 0;
+		}
+		else if( c == "\n" )
+		{
+			x += d;
+		}
+
+		this.X = x;
+
+		if( updatePx )
+		{
+			this.pX = x;
+			this.updatePosition();
+		}
+	};
+
+	Cursor.prototype.lineStart = function()
+	{
+		this.pX = 0;
+		this.moveX();
+		this.updatePosition();
+	};
+
+	Cursor.prototype.lineEnd = function()
+	{
+		/** @type {Components.Vim.LineBuffer} */
+		this.moveX( Number.MAX_VALUE );
+	};
+
+	Cursor.prototype.updatePosition = function()
+	{
+		this.P = this.X + LineOffset( this.buffers, this.Y );
+	};
+
+	Cursor.prototype.moveY = function( d )
+	{
+		this.Y += d;
+		this.moveX();
+		this.updatePosition();
+	};
+
+	__readOnly( Cursor.prototype, "position", function()
+	{
+		return {
+			start: this.P
+			, end: this.P + 1
+		};
+	} );
+
+
+	ns[ NS_EXPORT ]( EX_CLASS, "Cursor", Cursor );
+})();
diff --git a/botanjs/src/Components/Vim/LineBuffer.js b/botanjs/src/Components/Vim/LineBuffer.js
new file mode 100644
index 0000000..aa0360a
--- /dev/null
+++ b/botanjs/src/Components/Vim/LineBuffer.js
@@ -0,0 +1,111 @@
+(function(){
+	var ns = __namespace( "Components.Vim" );
+
+	/** @type {Dandelion} */
+	var Dand                                    = __import( "Dandelion" );
+	/** @type {Dandelion.IDOMElement} */
+	var IDOMElement                             = __import( "Dandelion.IDOMElement" );
+	/** @type {Dandelion.IDOMObject} */
+	var IDOMObject                              = __import( "Dandelion.IDOMObject" );
+	/** @type {System.Cycle} */
+	var Cycle                                   = __import( "System.Cycle" );
+	/** @type {System.Debug} */
+	var debug                                   = __import( "System.Debug" );
+
+	var LineBuffer = function( cols, nextLineBuffer )
+	{
+		this.prev = null;
+		this.cols = cols;
+		this.next = nextLineBuffer;
+		this.br = false;
+		this.placeholder = true;
+
+		if( nextLineBuffer )
+		{
+			nextLineBuffer.prev = this;
+		}
+
+	};
+
+	LineBuffer.prototype.Push = function( content, wrap )
+	{
+		if( content == undefined || content === "" )
+		{
+			this.content = "~";
+			this.placeholder = true;
+			if( this.next ) this.next.Push( content, wrap );
+			return;
+		}
+
+		this.placeholder = false;
+
+		var line = "";
+		var br = false;
+
+		if( wrap )
+		{
+			for( var i = 0; i < this.cols; i ++ )
+			{
+				var c = content[i];
+				if( c === undefined ) break;
+
+				if( c == "\n" )
+				{
+					br = true;
+					i ++;
+					break;
+				}
+
+				line += c;
+			}
+		}
+		else
+		{
+			br = true;
+			for( var i = 0; true; i ++ )
+			{
+				var c = content[i];
+				if( c === undefined ) break;
+
+				if( c == "\n" )
+				{
+					i ++;
+					break;
+				}
+
+				if( i < this.cols )
+				{
+					line += c;
+				}
+			}
+		}
+
+		if( this.next )
+		{
+			this.next.br = br;
+			this.next.Push( content.substr( i ), wrap );
+		}
+
+		this.content = line;
+	};
+
+	LineBuffer.prototype.toString = function()
+	{
+		return this.content || " ";
+	};
+
+	__readOnly( LineBuffer.prototype, "visualLines", function()
+	{
+		var lines = [ this ];
+		var line = this;
+		while( ( line = line.next ) && !line.br )
+		{
+			lines.push( line );
+		}
+
+		return lines;
+	} );
+
+
+	ns[ NS_EXPORT ]( EX_CLASS, "LineBuffer", LineBuffer );
+})();
diff --git a/botanjs/src/Components/Vim/LineFeeder.js b/botanjs/src/Components/Vim/LineFeeder.js
index ae8af80..2aba1f8 100644
--- a/botanjs/src/Components/Vim/LineFeeder.js
+++ b/botanjs/src/Components/Vim/LineFeeder.js
@@ -12,111 +12,38 @@
 	/** @type {System.Debug} */
 	var debug                                   = __import( "System.Debug" );
 
-	var Line = function( cols, nextLine )
-	{
-		this.cols = cols;
-		this.next = nextLine;
-		this.br = false;
-		this.placeholder = true;
-	};
-
-	Line.prototype.Push = function( content, wrap )
-	{
-		if( content == undefined || content === "" )
-		{
-			this.content = "~";
-			this.placeholder = true;
-			if( this.next ) this.next.Push( content, wrap );
-			return;
-		}
-
-		this.placeholder = false;
-
-		var line = "";
-		var br = false;
-
-		if( wrap )
-		{
-			for( var i = 0; i < this.cols; i ++ )
-			{
-				var c = content[i];
-				if( c === undefined ) break;
-
-				if( c == "\n" )
-				{
-					br = true;
-					i ++;
-					break;
-				}
-
-				line += c;
-			}
-		}
-		else
-		{
-			br = true;
-			for( var i = 0; true; i ++ )
-			{
-				var c = content[i];
-				if( c === undefined ) break;
-
-				if( c == "\n" )
-				{
-					i ++;
-					break;
-				}
-
-				if( i < this.cols )
-				{
-					line += c;
-				}
-			}
-		}
-
-		if( this.next )
-		{
-			this.next.br = br;
-			this.next.Push( content.substr( i ), wrap );
-		}
-
-		this.content = line;
-	};
-
-	Line.prototype.toString = function()
-	{
-		return this.content;
-	};
+	/** @type {Components.Vim.LineBuffer} */
+	var LineBuffer = ns[ NS_INVOKE ]( "LineBuffer" );
+	/** @type {Components.Vim.Cursor} */
+	var Cursor = ns[ NS_INVOKE ]( "Cursor" );
 
 	var Feeder = function( rows, cols )
 	{
-		var lines = [];
+		var lineBuffers = [];
 
 		// Last line
-		lines[ rows - 1 ] = new Line( cols );
+		lineBuffers[ rows - 1 ] = new LineBuffer( cols );
 
 		for( var i = rows - 2; 0 <= i; i -- )
 		{
-			lines[i] = new Line( cols, lines[ i + 1 ] );
+			lineBuffers[i] = new LineBuffer( cols, lineBuffers[ i + 1 ] );
 		}
 
-		this.lines = lines;
+		this.cursor = new Cursor( lineBuffers );
+
+		this.lineBuffers = lineBuffers;
 		this.setRender();
 	};
 
 	Feeder.prototype.init = function( content, wrap )
 	{
 		if( wrap == undefined ) wrap = true;
-		if( this.lines.length )
+		if( this.lineBuffers.length )
 		{
-			this.lines[0].Push( content, wrap ); 
+			this.lineBuffers[0].Push( content, wrap ); 
 		}
 	};
 
-	// Advance the text to number of lines
-	Feeder.prototype.feed = function( num )
-	{
-	};
-
 	Feeder.prototype.wrap = function( setwrap )
 	{
 	};
@@ -159,30 +86,23 @@
 		}
 	}
 
-	Feeder.prototype.cursor = function( direction )
-	{
-		switch( direction )
-		{
-			case 0:
-				return { start: 0, end: 1 };
-		}
-	};
-
 	Feeder.prototype.render = function( start, length )
 	{
+		var buffs = this.lineBuffers;
+
 		if( start == undefined ) start = 0;
-		else if( this.lines.length < start ) return "";
+		else if( buffs.length < start ) return "";
 
-		if( length == undefined || ( this.lines.length - start ) < length ) 
-			length = this.lines.length - start;
+		if( length == undefined || ( buffs.length - start ) < length ) 
+			length = buffs.length - start;
 
 		if( length == 0 ) return "";
 
-		return this.__render( this.lines[ start ], length - 1 );
+		return this.__render( buffs[ start ], length - 1 );
 	};
 
 	__readOnly( Feeder.prototype, "linesOccupied", function() {
-		var line = this.lines[0];
+		var line = this.lineBuffers[0];
 		if( line.placeholder ) return 0;
 
 		var i = 0;
diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js
index 791f511..159a34f 100644
--- a/botanjs/src/Components/Vim/VimArea.js
+++ b/botanjs/src/Components/Vim/VimArea.js
@@ -14,8 +14,9 @@
 	/** @type {System.Debug} */
 	var debug                                   = __import( "System.Debug" );
 
-	/** @type {Components.VimArea.LineFeeder} */
+	/** @type {Components.Vim.LineFeeder} */
 	var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" );
+	/** @type {Components.Vim.StatusBar} */
 	var StatusBar = ns[ NS_INVOKE ]( "StatusBar" );
 
 	var KeyHandler = function( sender, handler )
@@ -32,6 +33,11 @@
 
 	var VimControls = function( sender, e )
 	{
+		if( e.altKey
+			// F2 - F12
+			|| ( 112 < e.keyCode && e.keyCode < 124 )
+		) return;
+
 		e.preventDefault();
 		if( e.ctrlKey )
 		{
@@ -39,28 +45,49 @@
 			return;
 		}
 
-		var kCode = e.KeyCode + ( e.shiftKey ? 1000 : 0 );
-		switch( e.KeyCode )
+		var kCode = e.keyCode + ( e.shiftKey ? 1000 : 0 );
+
+		var cfeeder = sender.contentFeeder;
+		switch( kCode )
 		{
-			case 65: // a
-			case 1065: // A
-				break;
+			// Cursor movements
 			case 72: // h
-			case 1072: // H
+				cfeeder.cursor.moveX( -1 );
 				break;
 			case 74: // j
-			case 1074: // J
+				cfeeder.cursor.moveY( 1 );
 				break;
 			case 75: // k
-			case 1075: // K
+				cfeeder.cursor.moveY( -1 );
 				break;
 			case 76: // l
-			case 1076: // L
+				cfeeder.cursor.moveX( 1 );
+				break;
+
+			case 65: // a
+			case 1065: // A
+				break;
+			case 1072: // H, First line buffer
+				break;
+			case 1076: // L, Last line buffer
+				break;
+			case 1052: // $
+				cfeeder.cursor.lineEnd();
 				break;
 			case 1053: // %
+				break;
 			case 1054: // ^
+				cfeeder.cursor.lineStart();
+				break;
+			case 1074: // J, Join lines
+				break;
+			case 1075: // K, manual entry
 				break;
+			case 112: // F1, help
 		}
+
+		sender.__blink = false;
+		sender.select( cfeeder.cursor.position );
 	};
 
 	/* stage @param {Dandelion.IDOMElement} */
@@ -94,31 +121,23 @@
 
 	VimArea.prototype.startInput = function( mode )
 	{
-		
-	};
-
-	VimArea.prototype.cursor = function( x, y )
-	{
-		return this.__cursor();
 	};
 
-	VimArea.prototype.flashCursor = function()
+	VimArea.prototype.select = function( sel )
 	{
-		var _self = this;
 		var textarea = this.stage.element;
-		Cycle.perma( "VimCursorFlashCycle", function()
+
+		if( sel )
 		{
-			var cursor = _self.cursor();
-			if( cursor )
-			{
-				textarea.selectionStart = cursor.start;
-				textarea.selectionEnd = cursor.end;
-			}
-		}, 600 );
+			textarea.selectionStart = sel.start;
+			textarea.selectionEnd = sel.end;
+		}
 	};
 
 	VimArea.prototype.VisualizeVimFrame = function()
 	{
+		var _self = this;
+
 		var element = this.stage.element;
 		var r = this.rows;
 		var c = this.cols;
@@ -132,6 +151,7 @@
 		sfeeder = new LineFeeder( r, c );
 		sfeeder.setRender( false );
 
+		// XXX: Placeholder
 		var statusBar = new StatusBar( c );
 		statusBar.stamp( -18, function(){
 			return "1,1-1";
@@ -143,20 +163,24 @@
 
 		sfeeder.init( statusBar.statusText );
 
-		element.value = cfeeder.render( 0, r - sfeeder.linesOccupied ) + "\n" + sfeeder.render();
+		element.value =
+			cfeeder.render( 0, r - sfeeder.linesOccupied )
+			+ "\n" + sfeeder.render();
 
 		this.contentFeeder = cfeeder;
 		this.statusFeeder = sfeeder;
 
-		var f = true;
-		this.__cursor = function()
-		{
-			if( f = !f )
-				return this.contentFeeder.cursor( 0 );
-			else return { start: 0, end: 0 };
-		}
+		this.__cursor = cfeeder.cursor;
 
-		this.flashCursor();
+		this.__blink = true;
+		Cycle.perma( "VimCursorBlinkCycle" + element.id, function()
+		{
+			_self.select(
+				( _self.__blink = !_self.__blink )
+					? _self.__cursor.position
+					: { start: 0, end: 0 }
+			);
+		}, 600 );
 	};
 
 	ns[ NS_EXPORT ]( EX_CLASS, "VimArea", VimArea );
diff --git a/botanjs/src/Components/Vim/_this.js b/botanjs/src/Components/Vim/_this.js
index 706cf48..5de456f 100644
--- a/botanjs/src/Components/Vim/_this.js
+++ b/botanjs/src/Components/Vim/_this.js
@@ -14,6 +14,7 @@
 
 	var messages = {
 		"INSERT": "-- INSERT --"
+		, "REPLACE": "-- REPLACE --"
 		, "MORE": "-- MORE --"
 		, "WRITE": "\"%1\" %2L, %3C written"
 		, "CONTINUE": "Press ENTER or type command to continue"