penguin/AstroJS

Javascript framework for my blog

commit 42bbc3b24046f5134c96860cff1a5a4a778ac164

author斟酌 鵬兄 <tgckpg@gmail.com>
date2017-01-25T03:04:29Z
subjectFixed cursor mis-positioned on tab characters
commit 42bbc3b24046f5134c96860cff1a5a4a778ac164
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2017-01-25T03:04:29Z

    Fixed cursor mis-positioned on tab characters
---
 botanjs/src/Components/Vim/Actions/INSERT.js      |  6 +-
 botanjs/src/Components/Vim/Actions/SHIFT_LINES.js |  2 +-
 botanjs/src/Components/Vim/Actions/VISUAL.js      |  4 +-
 botanjs/src/Components/Vim/Controls.js            | 18 +++--
 botanjs/src/Components/Vim/Cursor.js              | 81 ++++++++++++++++++++---
 botanjs/src/Components/Vim/_this.js               |  2 +-
 6 files changed, 90 insertions(+), 23 deletions(-)

diff --git a/botanjs/src/Components/Vim/Actions/INSERT.js b/botanjs/src/Components/Vim/Actions/INSERT.js
index 4beaca5..bec9396 100644
--- a/botanjs/src/Components/Vim/Actions/INSERT.js
+++ b/botanjs/src/Components/Vim/Actions/INSERT.js
@@ -60,7 +60,7 @@
 		}
 		this.__msg = "";
 		this.__rec( "", true );
-		this.__cursor.moveX( -1 );
+		this.__cursor.moveX( -1, false, false, true );
 	};
 
 	INSERT.prototype.__rec = function( c, newRec )
@@ -197,7 +197,7 @@
 		{
 			this.__realizeIndent();
 			feeder.pan();
-			cur.moveX( inputChar == "\t" ? feeder.firstBuffer.tabWidth : 1, false, true );
+			cur.moveX( inputChar == "\t" ? feeder.firstBuffer.tabWidth : 1, false, true, true );
 		}
 
 		feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
@@ -262,7 +262,7 @@
 
 			feeder.softReset();
 			feeder.pan();
-			cur.moveX( i * feeder.firstBuffer.tabWidth, false, true );
+			cur.moveX( i, false, true );
 
 			var a = [];
 			a[ IN_START ] = f;
diff --git a/botanjs/src/Components/Vim/Actions/SHIFT_LINES.js b/botanjs/src/Components/Vim/Actions/SHIFT_LINES.js
index 0e83a39..606e17d 100644
--- a/botanjs/src/Components/Vim/Actions/SHIFT_LINES.js
+++ b/botanjs/src/Components/Vim/Actions/SHIFT_LINES.js
@@ -345,7 +345,7 @@
 			f();
 			// Offset correction after REDO / UNDO
 			cur.moveTo( recStart );
-			cur.lineStart();
+			cur.lineStart( true );
 		} );
 
 		cur.moveTo( recStart );
diff --git a/botanjs/src/Components/Vim/Actions/VISUAL.js b/botanjs/src/Components/Vim/Actions/VISUAL.js
index 55aa192..3bdb8d3 100644
--- a/botanjs/src/Components/Vim/Actions/VISUAL.js
+++ b/botanjs/src/Components/Vim/Actions/VISUAL.js
@@ -220,13 +220,13 @@
 
 				if( cur.aPos == startLine.aPos )
 				{
-					cur.moveTo( r.open, true );
+					cur.moveTo( r.open, true, false, true );
 					this.__reset( cur );
 					startLine = this.__startLine;
 				}
 
 				cur.unsuppressEvent();
-				cur.moveTo( r.close, true );
+				cur.moveTo( r.close, true, false, true );
 			}
 
 			var currAp = cur.aPos;
diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index cdb320c..0c34dcc 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -259,9 +259,17 @@
 		{
 			case SHIFT + A: // Append at the line end
 				ccur.lineEnd();
-			case A: // Append
-				ccur.moveX( 1, true, true );
+				ccur.moveX( 1, true, true, true );
+				ccur.openAction( "INSERT", e );
+				break;
 			case I: // Insert
+				ccur.moveX( -1 );
+			case A: // Append
+				ccur.moveX( 1, true, true, true );
+				ccur.openAction( "INSERT", e );
+				break;
+			case SHIFT + I: // Append at line start
+				ccur.lineStart( true );
 				ccur.openAction( "INSERT", e );
 				break;
 
@@ -515,11 +523,11 @@
 			case SHIFT + L: // Last line buffer
 				break;
 
-			case _0: // Really - line Start
+			case _0: // Really line Start
 				ccur.lineStart();
 				break;
-			case SHIFT + _6: // ^, line Start, XXX: skip tabs
-				ccur.lineStart();
+			case SHIFT + _6: // ^, line Start at word
+				ccur.lineStart( true );
 				break;
 			case SHIFT + _4: // $, End
 				ccur.lineEnd( ccur.pSpace );
diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js
index 810bf70..e59b69d 100644
--- a/botanjs/src/Components/Vim/Cursor.js
+++ b/botanjs/src/Components/Vim/Cursor.js
@@ -103,7 +103,7 @@
 	Cursor.prototype.Vim;
 
 	// Move to an absolute position
-	Cursor.prototype.moveTo = function( aPos, phantomSpace )
+	Cursor.prototype.moveTo = function( aPos, phantomSpace, skipTabs )
 	{
 		var content = this.feeder.content;
 		var pline = this.getLine();
@@ -133,19 +133,18 @@
 		var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart;
 
 		jumpX += Math.ceil( jumpX / pline.cols ) - 1;
-		jumpX += occurence( content.substring( lineStart + 1, aPos ), "\t" ) * ( pline.tabWidth - 1 );
 
 		if( jumpY ) this.moveY( jumpY );
 
 		// This is needed because first line does not contain the first "\n" character
 		if( 0 < this.getLine().lineNum && lineStart <= aPos ) jumpX --;
 
-		this.moveX( - Number.MAX_VALUE );
-		this.moveX( jumpX, false, phantomSpace );
+		this.moveX( - Number.MAX_VALUE, false, false, true );
+		this.moveX( jumpX, false, phantomSpace, skipTabs );
 	};
 
 	// 0 will be treated as default ( 1 )
-	Cursor.prototype.moveX = function( d, penetrate, phantomSpace )
+	Cursor.prototype.moveX = function( d, penetrate, phantomSpace, skipTab )
 	{
 		var x = this.pX;
 		var updatePx = Boolean( d );
@@ -177,6 +176,8 @@
 
 		/** @type {Components.Vim.LineBuffer} */
 		var line = this.getLine();
+		var tabStep = line.tabWidth - 1;
+		var rline = this.rawLine;
 		var content = line.visualLines.join( "\n" );
 		var cLen = content.length;
 
@@ -190,8 +191,7 @@
 		{
 			// Begin check if this line contains phantomSpace
 			// hasPhantomSpace = 0 < ( rawLine.displayLength ) % cols
-			var rline = this.rawLine;
-			hasPhantomSpace = 0 < ( rline.length + occurence( rline, "\t" ) * ( line.tabWidth - 1 ) ) % line.cols;
+			hasPhantomSpace = 0 < ( rline.length + occurence( rline, "\t" ) * tabStep ) % line.cols;
 
 			if( hasPhantomSpace )
 			{
@@ -203,6 +203,56 @@
 			}
 		}
 
+		// Hacky tab compensations
+		if( !skipTab )
+		{
+			var s = this.aX;
+			var a = rline[ s + d ];
+			var e = s;
+			if( d < 0 )
+			{
+				if( rline[ s ] == "\t" )
+				{
+					x -= tabStep;
+					if( x < 0 )
+						x = tabStep;
+				}
+
+				s += d;
+
+				var ntabs = occurence( rline.substring( s, e ), "\t" ) - 1;
+				if( 0 < ntabs ) x -= ntabs * tabStep;
+			}
+			else if( updatePx ) // && 0 < d ( assuming d can never be 0 )
+			{
+				// Going from one line to next
+				// linebreaks are *invisible*
+				var isLF = ( content[ x ] == "\n" ) ? 1 : 0;
+
+				if( s == 0 )
+				{
+					x = 1;
+					if ( rline[ 0 ] == "\t" )
+					{
+						x += tabStep;
+					}
+				}
+
+				e += d;
+
+				var ntabs = occurence( rline.substring( s + 1, e + 1 ), "\t" );
+				x += ntabs * tabStep + isLF;
+				if( 1 < d ) x += d - 1;
+			}
+			else // jk, non-X navigation. i.e., pX does not change
+			{
+				// s = 0, which is unused here
+				e = x + d;
+				x += ( occurence( rline.substring( 0, e ), "\t" ) ) * tabStep;
+				if( 1 < d ) x += d - 1;
+			}
+		}
+
 		var c = content[ x ];
 
 		// Whether x is at line boundary
@@ -227,22 +277,31 @@
 
 		if( updatePx )
 		{
-			this.pX = x;
+			this.pX = this.aX;
 			this.updatePosition();
 		}
 
 	};
 
-	Cursor.prototype.lineStart = function()
+	Cursor.prototype.lineStart = function( atWord )
 	{
-		this.pX = 0;
+		if( atWord )
+		{
+			var a = this.rawLine.match( /^[ \t]+/g );
+			this.pX = a ? a[0].length : 0;
+		}
+		else
+		{
+			this.pX = 0;
+		}
+
 		this.moveX();
 		this.updatePosition();
 	};
 
 	Cursor.prototype.lineEnd = function( phantomSpace )
 	{
-		this.moveX( Number.MAX_VALUE, false, phantomSpace );
+		this.moveX( Number.MAX_VALUE, false, phantomSpace, true );
 	};
 
 	Cursor.prototype.updatePosition = function()
diff --git a/botanjs/src/Components/Vim/_this.js b/botanjs/src/Components/Vim/_this.js
index bfa1b4b..e00d556 100644
--- a/botanjs/src/Components/Vim/_this.js
+++ b/botanjs/src/Components/Vim/_this.js
@@ -6,7 +6,7 @@ VIMRE_VERSION = "1.0.0b";
 		"INSERT": "-- INSERT --"
 		, "REPLACE": "-- REPLACE --"
 		, "MORE": "-- MORE --"
-		, "VISUAL": "-- VISUAL  --"
+		, "VISUAL": "-- VISUAL --"
 		, "VISLINE": "-- VISUAL LINE --"
 		, "REGISTERS": "--- Registers ---"
 		, "WRITE": "\"%1\" %2L, %3C written"