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"