Fixed cursor mis-positioned on tab characters

This commit is contained in:
斟酌 鵬兄 2017-01-25 11:04:29 +08:00
parent 4b200697dc
commit 42bbc3b240
6 changed files with 90 additions and 23 deletions

View File

@ -60,7 +60,7 @@
} }
this.__msg = ""; this.__msg = "";
this.__rec( "", true ); this.__rec( "", true );
this.__cursor.moveX( -1 ); this.__cursor.moveX( -1, false, false, true );
}; };
INSERT.prototype.__rec = function( c, newRec ) INSERT.prototype.__rec = function( c, newRec )
@ -197,7 +197,7 @@
{ {
this.__realizeIndent(); this.__realizeIndent();
feeder.pan(); 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" ) ); feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
@ -262,7 +262,7 @@
feeder.softReset(); feeder.softReset();
feeder.pan(); feeder.pan();
cur.moveX( i * feeder.firstBuffer.tabWidth, false, true ); cur.moveX( i, false, true );
var a = []; var a = [];
a[ IN_START ] = f; a[ IN_START ] = f;

View File

@ -345,7 +345,7 @@
f(); f();
// Offset correction after REDO / UNDO // Offset correction after REDO / UNDO
cur.moveTo( recStart ); cur.moveTo( recStart );
cur.lineStart(); cur.lineStart( true );
} ); } );
cur.moveTo( recStart ); cur.moveTo( recStart );

View File

@ -220,13 +220,13 @@
if( cur.aPos == startLine.aPos ) if( cur.aPos == startLine.aPos )
{ {
cur.moveTo( r.open, true ); cur.moveTo( r.open, true, false, true );
this.__reset( cur ); this.__reset( cur );
startLine = this.__startLine; startLine = this.__startLine;
} }
cur.unsuppressEvent(); cur.unsuppressEvent();
cur.moveTo( r.close, true ); cur.moveTo( r.close, true, false, true );
} }
var currAp = cur.aPos; var currAp = cur.aPos;

View File

@ -259,9 +259,17 @@
{ {
case SHIFT + A: // Append at the line end case SHIFT + A: // Append at the line end
ccur.lineEnd(); ccur.lineEnd();
case A: // Append ccur.moveX( 1, true, true, true );
ccur.moveX( 1, true, true ); ccur.openAction( "INSERT", e );
break;
case I: // Insert 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 ); ccur.openAction( "INSERT", e );
break; break;
@ -515,11 +523,11 @@
case SHIFT + L: // Last line buffer case SHIFT + L: // Last line buffer
break; break;
case _0: // Really - line Start case _0: // Really line Start
ccur.lineStart(); ccur.lineStart();
break; break;
case SHIFT + _6: // ^, line Start, XXX: skip tabs case SHIFT + _6: // ^, line Start at word
ccur.lineStart(); ccur.lineStart( true );
break; break;
case SHIFT + _4: // $, End case SHIFT + _4: // $, End
ccur.lineEnd( ccur.pSpace ); ccur.lineEnd( ccur.pSpace );

View File

@ -103,7 +103,7 @@
Cursor.prototype.Vim; Cursor.prototype.Vim;
// Move to an absolute position // Move to an absolute position
Cursor.prototype.moveTo = function( aPos, phantomSpace ) Cursor.prototype.moveTo = function( aPos, phantomSpace, skipTabs )
{ {
var content = this.feeder.content; var content = this.feeder.content;
var pline = this.getLine(); var pline = this.getLine();
@ -133,19 +133,18 @@
var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart; var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart;
jumpX += Math.ceil( jumpX / pline.cols ) - 1; jumpX += Math.ceil( jumpX / pline.cols ) - 1;
jumpX += occurence( content.substring( lineStart + 1, aPos ), "\t" ) * ( pline.tabWidth - 1 );
if( jumpY ) this.moveY( jumpY ); if( jumpY ) this.moveY( jumpY );
// This is needed because first line does not contain the first "\n" character // This is needed because first line does not contain the first "\n" character
if( 0 < this.getLine().lineNum && lineStart <= aPos ) jumpX --; if( 0 < this.getLine().lineNum && lineStart <= aPos ) jumpX --;
this.moveX( - Number.MAX_VALUE ); this.moveX( - Number.MAX_VALUE, false, false, true );
this.moveX( jumpX, false, phantomSpace ); this.moveX( jumpX, false, phantomSpace, skipTabs );
}; };
// 0 will be treated as default ( 1 ) // 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 x = this.pX;
var updatePx = Boolean( d ); var updatePx = Boolean( d );
@ -177,6 +176,8 @@
/** @type {Components.Vim.LineBuffer} */ /** @type {Components.Vim.LineBuffer} */
var line = this.getLine(); var line = this.getLine();
var tabStep = line.tabWidth - 1;
var rline = this.rawLine;
var content = line.visualLines.join( "\n" ); var content = line.visualLines.join( "\n" );
var cLen = content.length; var cLen = content.length;
@ -190,8 +191,7 @@
{ {
// Begin check if this line contains phantomSpace // Begin check if this line contains phantomSpace
// hasPhantomSpace = 0 < ( rawLine.displayLength ) % cols // hasPhantomSpace = 0 < ( rawLine.displayLength ) % cols
var rline = this.rawLine; hasPhantomSpace = 0 < ( rline.length + occurence( rline, "\t" ) * tabStep ) % line.cols;
hasPhantomSpace = 0 < ( rline.length + occurence( rline, "\t" ) * ( line.tabWidth - 1 ) ) % line.cols;
if( hasPhantomSpace ) 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 ]; var c = content[ x ];
// Whether x is at line boundary // Whether x is at line boundary
@ -227,22 +277,31 @@
if( updatePx ) if( updatePx )
{ {
this.pX = x; this.pX = this.aX;
this.updatePosition(); this.updatePosition();
} }
}; };
Cursor.prototype.lineStart = function() Cursor.prototype.lineStart = function( atWord )
{
if( atWord )
{
var a = this.rawLine.match( /^[ \t]+/g );
this.pX = a ? a[0].length : 0;
}
else
{ {
this.pX = 0; this.pX = 0;
}
this.moveX(); this.moveX();
this.updatePosition(); this.updatePosition();
}; };
Cursor.prototype.lineEnd = function( phantomSpace ) Cursor.prototype.lineEnd = function( phantomSpace )
{ {
this.moveX( Number.MAX_VALUE, false, phantomSpace ); this.moveX( Number.MAX_VALUE, false, phantomSpace, true );
}; };
Cursor.prototype.updatePosition = function() Cursor.prototype.updatePosition = function()