From 564aef86aa2ae402339328bb52434bd5d59595f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= <tgckpg@gmail.com>
Date: Wed, 30 Mar 2016 06:17:37 +0800
Subject: [PATCH] Previous approach had performance issue, fixing it

---
 botanjs/src/Components/Vim/Controls.js       | 17 ++--
 botanjs/src/Components/Vim/Cursor.js         | 83 +++++++++++---------
 botanjs/src/externs/Components.Vim.Cursor.js |  2 +
 3 files changed, 51 insertions(+), 51 deletions(-)

diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index 09090156..44334c60 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -292,18 +292,11 @@
 					break;
 				}
 
-				var d = 1;
-				var at = bracketMatch.close;
-				if( bracketMatch.selected == at )
-				{
-					d = -1;
-					at = bracketMatch.open;
-				}
-
-				while( ccur.aPos != at )
-				{
-					ccur.moveX( d, true );
-				}
+				ccur.moveTo(
+					bracketMatch.selected == bracketMatch.close
+						? bracketMatch.open
+						: bracketMatch.close
+				);
 
 				break;
 			case T: // To
diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js
index 240dd108..c39080fc 100644
--- a/botanjs/src/Components/Vim/Cursor.js
+++ b/botanjs/src/Components/Vim/Cursor.js
@@ -88,6 +88,37 @@
 	// Set by VimArea
 	Cursor.prototype.Vim;
 
+	// Move to an absolute position
+	Cursor.prototype.moveTo = function( aPos )
+	{
+		var content = this.feeder.content;
+		var lastLineNum = this.getLine().lineNum;
+
+		var expLineNum = 0;
+		var lineStart = 0;
+		for( var i = content.indexOf( "\n" ); 0 <= i ; i = content.indexOf( "\n", i ) )
+		{
+			if( aPos <= i )
+			{
+				break;
+			}
+
+			lineStart = i;
+			i ++;
+			expLineNum ++;
+		}
+
+		var jumpY = expLineNum - lastLineNum;
+		var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart;
+
+		if( jumpY ) this.moveY( jumpY );
+		if( 0 < this.getLine().lineNum && lineStart <= aPos ) jumpX --;
+
+		this.moveX( - Number.MAX_VALUE );
+		this.moveX( jumpX );
+
+	};
+
 	// 0 will be treated as default ( 1 )
 	Cursor.prototype.moveX = function( d, penetrate, phantomSpace )
 	{
@@ -120,38 +151,12 @@
 		// Motion includes empty lines before cursor end
 		if( ( phantomSpace && cLen - 1 <= x ) || ( cLen == 1 && c == undefined ) )
 		{
-			if( 0 < d )
-			{
-				x = cLen - 1;
-				if( penetrate )
-				{
-					this.X = 0;
-					this.moveY( 1 );
-					return;
-				}
-			}
-			else
-			{
-				x = 0;
-			}
+			x = 0 < d ? cLen - 1 : 0;
 		}
 		// ( 2 < cLen ) motion excludes empty lines at cursor end
 		else if( ( 2 <= cLen && x == cLen - 1 && c == " " ) || c == undefined )
 		{
-			if( 0 < d )
-			{
-				x = cLen - 2;
-				if( penetrate )
-				{
-					this.X = 0;
-					this.moveY( 1 );
-					return;
-				}
-			}
-			else
-			{
-				x = 0;
-			}
+			x = 0 < d ? cLen - 2 : 0;
 		}
 		else if( c == "\n" )
 		{
@@ -199,7 +204,7 @@
 		this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
 	};
 
-	Cursor.prototype.moveY = function( d, penetrate )
+	Cursor.prototype.moveY = function( d )
 	{
 		var i;
 		var Y = this.Y + d;
@@ -208,7 +213,7 @@
 
 		if( Y < 0 )
 		{
-			feeder.pan( undefined, d );
+			feeder.pan( undefined, Y );
 
 			this.Y = 0;
 			this.moveX();
@@ -222,11 +227,7 @@
 		{
 			var feeder = this.feeder;
 
-			if( penetrate )
-			{
-				feeder.pan( undefined, Y - moreAt );
-			}
-			else if( feeder.linesTotal < Y )
+			if( feeder.linesTotal < Y )
 			{
 				while( !feeder.EOF )
 				{
@@ -244,18 +245,22 @@
 				if( !feeder.EOF )
 					feeder.pan( undefined, lineShift );
 
+				// The line number cursor need to be in
+				Y = thisLine + d;
+
 				// if it turns out to be the same line
+				// OR the cursor can not reside on the needed line
 				// before after panning
 				// we keep scrolling it ( panning )
 				// until the entire line cosumes the screen
-				while( !feeder.EOF && feeder.lastBuffer.lineNum == lastLine )
+				while( !feeder.EOF && (
+					feeder.lastBuffer.lineNum == lastLine
+					||  feeder.lastBuffer.lineNum < Y
+				) )
 				{
 					feeder.pan( undefined, 1 );
 				}
 
-				// The line number cursor need to be in
-				Y = thisLine + d;
-
 				i = this.Y;
 				this.Y = 0;
 				// Calculate the visual line position "i"
diff --git a/botanjs/src/externs/Components.Vim.Cursor.js b/botanjs/src/externs/Components.Vim.Cursor.js
index 2f42cdb4..8cf84f8d 100644
--- a/botanjs/src/externs/Components.Vim.Cursor.js
+++ b/botanjs/src/externs/Components.Vim.Cursor.js
@@ -10,6 +10,8 @@ Components.Vim.Cursor.action;
 /** @type {Components.Vim.State.Recorder} */
 Components.Vim.Cursor.rec;
 
+/** @type Function */
+Components.Vim.Cursor.moveTo;
 /** @type Function */
 Components.Vim.Cursor.moveX;
 /** @type Function */