diff --git a/botanjs/src/Components/Vim/Actions/DELETE.js b/botanjs/src/Components/Vim/Actions/DELETE.js index 922f703..b509fb5 100644 --- a/botanjs/src/Components/Vim/Actions/DELETE.js +++ b/botanjs/src/Components/Vim/Actions/DELETE.js @@ -41,19 +41,22 @@ var feeder = cur.feeder; var Triggered = false; - if( sp == undefined && this.__startX != cur.aPos ) + + if( sp == undefined ) { - Triggered = true; - - if( e.kMap( "l" ) ) + if( this.__startX != cur.aPos ) { - cur.moveX( -1 ); + Triggered = true; + + if( e.kMap( "l" ) ) + { + cur.moveX( -1 ); + } + + sp = this.__startX; } - - sp = this.__startX; + else return; } - else if( sp == undefined ) return; - var c = feeder.content; diff --git a/botanjs/src/Components/Vim/Actions/VISUAL.js b/botanjs/src/Components/Vim/Actions/VISUAL.js index 1574d95..7cac789 100644 --- a/botanjs/src/Components/Vim/Actions/VISUAL.js +++ b/botanjs/src/Components/Vim/Actions/VISUAL.js @@ -27,7 +27,6 @@ /** @type {Components.Vim.Cursor} */ this.__cursor = Cursor; this.__startaP = Cursor.aPos; - this.__startP = { x: Cursor.X, y: Cursor.Y, p: Cursor.P }; this.__start = Cursor.PStart; this.__selStart = Cursor.PStart; }; @@ -71,10 +70,9 @@ // to keep the cursor position as the top on UNDO / REDO if( Action.constructor == DELETE && this.__startaP < cur.aPos ) { - this.__startaP = cur.aPos; - cur.X = this.__startP.x; - cur.Y = this.__startP.y; - cur.P = this.__startP.p; + var o = cur.aPos; + cur.moveTo( this.__startaP, true ); + this.__startaP = o; } Action.handler( e, this.__startaP ); @@ -97,12 +95,12 @@ if( cur.aPos == this.__startaP ) { - cur.moveX( r.open - this.__startaP ); + cur.moveTo( r.open, true ); this.__reset( cur ); } cur.unsuppressEvent(); - cur.moveX( r.close - cur.aPos ); + cur.moveTo( r.close, true ); } var prevPos = this.__start; diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index f318060..950ddbc 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -257,6 +257,8 @@ } var ccur = this.__ccur; + var vima = this.__vimArea; + var cfeeder = ccur.feeder; var cursorHandled = true; switch( kCode ) @@ -267,6 +269,29 @@ case K: this.__cMoveY( -1 ); break; // Up case J: this.__cMoveY( 1 ); break; // Down + case CTRL + F: // Page Down + if( cfeeder.firstBuffer.next.placeholder ) + { + beep(); + break; + } + + var oPan = cfeeder.panY; + cfeeder.pan( undefined, vima.rows - 1 ); + ccur.moveY( -ccur.Y ); + + break; + case CTRL + B: // Page Up + if( cfeeder.panY == 0 ) + { + beep(); + break; + } + cfeeder.pan( undefined, -vima.rows + 1 ); + ccur.moveY( -ccur.Y ); + if( !cfeeder.EOF ) ccur.moveY( cfeeder.moreAt ); + break; + case SHIFT + H: // First line buffer break; case SHIFT + L: // Last line buffer @@ -313,29 +338,33 @@ var analyzer = this.__vimArea.contentAnalyzer; this.__cMovement = true; + // Word boundary this.__comp( e, function( e2 ) { var WordMatch = analyzer.wordAt( ccur.aPos ); - - debug.Info( "Word: " - + ccur.feeder.content.substring( WordMatch.open, WordMatch.close + 1 ) - ); - e2.__range = WordMatch; }, W ); - this.__comp( e, function(){ - debug.Info( "Bracket boundary [" ); - }, S_BRACKET_L ); - this.__comp( e, function(){ - debug.Info( "Bracket boundary ]" ); - }, S_BRACKET_R ); - this.__comp( e, function(){ - debug.Info( "Bracket boundary {" ); - }, SHIFT + S_BRACKET_L ); - this.__comp( e, function(){ - debug.Info( "Bracket boundary }" ); - analyzer.bracketAt( ccur.aPos ); - }, SHIFT + S_BRACKET_R ); + + var bracket = function( e2 ) { + var BracketMatch = analyzer.bracketIn( "(", ccur.aPos ); + e2.__range = BracketMatch; + }; + var curlyBracket = function( e2 ) { + var BracketMatch = analyzer.bracketIn( "{", ccur.aPos ); + e2.__range = BracketMatch; + }; + var squareBracket = function( e2 ) { + var BracketMatch = analyzer.bracketIn( "[", ccur.aPos ); + e2.__range = BracketMatch; + }; + + // Bracket boundaries + this.__comp( e, bracket , SHIFT + _0 ); + this.__comp( e, bracket, SHIFT + _9 ); + this.__comp( e, squareBracket, S_BRACKET_L ); + this.__comp( e, squareBracket, S_BRACKET_R ); + this.__comp( e, curlyBracket, SHIFT + S_BRACKET_L ); + this.__comp( e, curlyBracket, SHIFT + S_BRACKET_R ); break; case G: // Go to top diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js index c39080f..47b10ad 100644 --- a/botanjs/src/Components/Vim/Cursor.js +++ b/botanjs/src/Components/Vim/Cursor.js @@ -89,7 +89,7 @@ Cursor.prototype.Vim; // Move to an absolute position - Cursor.prototype.moveTo = function( aPos ) + Cursor.prototype.moveTo = function( aPos, phantomSpace ) { var content = this.feeder.content; var lastLineNum = this.getLine().lineNum; @@ -115,7 +115,7 @@ if( 0 < this.getLine().lineNum && lineStart <= aPos ) jumpX --; this.moveX( - Number.MAX_VALUE ); - this.moveX( jumpX ); + this.moveX( jumpX, false, phantomSpace ); }; diff --git a/botanjs/src/Components/Vim/LineFeeder.js b/botanjs/src/Components/Vim/LineFeeder.js index e50f4ac..b27779f 100644 --- a/botanjs/src/Components/Vim/LineFeeder.js +++ b/botanjs/src/Components/Vim/LineFeeder.js @@ -149,7 +149,9 @@ var a = this.content.indexOf( "\n", f + 1 ); if( a == -1 ) { - Y = i; + Y = i - 1; + // -2 to compensate the last "\n" content placeholder + f -= 2; break; } f = a; diff --git a/botanjs/src/Components/Vim/Syntax/Analyzer.js b/botanjs/src/Components/Vim/Syntax/Analyzer.js index cb816cf..131ec75 100644 --- a/botanjs/src/Components/Vim/Syntax/Analyzer.js +++ b/botanjs/src/Components/Vim/Syntax/Analyzer.js @@ -117,6 +117,24 @@ }; /* End Private Class }}}*/ + var SetParent = function( BracketPairs, pair ) + { + if( !pair ) throw new Error( "Parent not found" ); + + var tMatch = new TokenMatch(); + tMatch.__level = pair[ TOK_LEVEL ]; + tMatch.__open = pair[ TOK_OPEN ]; + tMatch.__close = pair[ TOK_CLOSED ]; + + if( -1 < pair[ TOK_PARENT ] ) + { + var rPair = BracketPairs.find( pair[ TOK_PARENT ] ); + tMatch.__parent = SetParent( BracketPairs, rPair ); + } + + return tMatch; + }; + var Analyzer = function( feeder ) { /* @type {Components.Vim.LineFeeder} */ @@ -136,17 +154,17 @@ { case "{": tokState = TOK_OPEN; case "}": - BracketPairs = this.GetPairs( TOK_JOIN( "{", "}" ) ); + BracketPairs = this.__getPairs( TOK_JOIN( "{", "}" ) ); break; case "[": tokState = TOK_OPEN; case "]": - BracketPairs = this.GetPairs( TOK_JOIN( "[", "]" ) ); + BracketPairs = this.__getPairs( TOK_JOIN( "[", "]" ) ); break; case "(": tokState = TOK_OPEN; case ")": - BracketPairs = this.GetPairs( TOK_JOIN( "(", ")" ) ); + BracketPairs = this.__getPairs( TOK_JOIN( "(", ")" ) ); break; case "/": @@ -186,39 +204,65 @@ { case "/*": tokState = TOK_OPEN; case "*/": - BracketPairs = this.GetPairs( TOK_JOIN( "/*", "*/" ) ); + BracketPairs = this.__getPairs( TOK_JOIN( "/*", "*/" ) ); break; default: return new TokenMatch(); } - var SetParent = function( pair ) - { - if( !pair ) throw new Error( "Parent not found" ); - - var tMatch = new TokenMatch(); - tMatch.__level = pair[ TOK_LEVEL ]; - tMatch.__open = pair[ TOK_OPEN ]; - tMatch.__close = pair[ TOK_CLOSED ]; - - if( -1 < pair[ TOK_PARENT ] ) - { - var rPair = BracketPairs.find( pair[ TOK_PARENT ] ); - tMatch.__parent = SetParent( rPair ); - } - - return tMatch; - }; - var rPair = BracketPairs.find( p, tokState ); - var tMatch = SetParent( rPair ) + var tMatch = SetParent( BracketPairs, rPair ) tMatch.__selected = p; return tMatch; }; - Analyzer.prototype.GetPairs = function( def, reload ) + Analyzer.prototype.bracketIn = function( b, p ) + { + var bro = "{[("; + var brc = "}])"; + + var i = bro.indexOf( b ); + if( i < 0 ) i = brc.indexOf( b ); + if( i < 0 ) throw new Error( "Unsupported bracket: " + b ); + + var tokPairs = this.__getPairs( TOK_JOIN( bro[i], brc[i] ) ); + var pairs = tokPairs.__pairs; + + var l = pairs.length; + + var highest = null; + + // Find the range of highest level + for( var i = 0; i < l; i ++ ) + { + var pair = pairs[ i ]; + + if( pair[ TOK_OPEN ] <= p && p <= pair[ TOK_CLOSED ] ) + { + if( ( highest && highest[ TOK_LEVEL ] < pair[ TOK_LEVEL ] ) || !highest ) + { + highest = pair; + } + } + + } + + var tMatch = SetParent( tokPairs, highest ); + var oMatch = tMatch; + + do { + oMatch.__open ++; + oMatch.__close --; + } while( oMatch = oMatch.parent ) + + if( highest ) return tMatch; + + return new TokenMatch(); + }; + + Analyzer.prototype.__getPairs = function( def, reload ) { if( !reload && this.__tokpairs[ def ] ) { diff --git a/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js b/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js index 6be9e80..47a3b3b 100644 --- a/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js +++ b/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js @@ -4,6 +4,8 @@ Components.Vim.Syntax.Analyzer = function(){}; /** @type Function */ Components.Vim.Syntax.Analyzer.bracketAt; /** @type Function */ +Components.Vim.Syntax.Analyzer.bracketIn; +/** @type Function */ Components.Vim.Syntax.Analyzer.wordAt; /** @type Function */ Components.Vim.Syntax.Analyzer.quoteAt;