From 2548970f3a77df69da1f463514dfdaa2e7beb7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sun, 13 Mar 2016 20:26:26 +0800 Subject: [PATCH] Partial nav of "jkhl$^" --- botanjs/src/Components/Vim/Cursor.js | 51 +++++++----- botanjs/src/Components/Vim/LineBuffer.js | 2 +- botanjs/src/Components/Vim/LineFeeder.js | 100 ++++++++++++++++------- botanjs/src/Components/Vim/VimArea.js | 27 +++++- botanjs/src/Components/Vim/_this.js | 1 + 5 files changed, 129 insertions(+), 52 deletions(-) diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js index b72ea1b..4ce90fa 100644 --- a/botanjs/src/Components/Vim/Cursor.js +++ b/botanjs/src/Components/Vim/Cursor.js @@ -37,42 +37,39 @@ /** @type {Components.Vim.LineBuffer} */ var offset = 0; + LineLoop: for( var i = 0, line = buffs[0]; line && i < l; i ++ ) { while( line ) { - if( line.br ) + if( line.next && line.next.placeholder ) + break LineLoop; + + if( line.next && line.next.br ) { - offset += line.prev.toString().length + 1; - - // Empty line has a special space - if( line.content == "" ) offset ++; - + offset += line.toString().length + 1; line = line.next; break; } else { - if( offset == 0 ) offset -= 1; - - if( line.next && !line.next.br ) - offset += line.cols + 1; + offset += line.cols + 1; } line = line.next; } } - debug.Info( offset ); - return offset; }; - var Cursor = function( buffs ) + var Cursor = function( feeder ) { - this.buffers = buffs; - this.cols = buffs[0].cols; + /** @type {Components.Vim.LineFeeder} */ + this.feeder = feeder; + + this.cols = feeder.lineBuffers[0].cols; // The preferred X position this.pX = 0; @@ -98,7 +95,7 @@ if( !d ) d = 1; - var buffs = this.buffers; + var buffs = this.feeder.lineBuffers; /** @type {Components.Vim.LineBuffer} */ var line = GetLine( buffs, this.Y ); @@ -133,18 +130,34 @@ Cursor.prototype.lineEnd = function() { - /** @type {Components.Vim.LineBuffer} */ this.moveX( Number.MAX_VALUE ); }; Cursor.prototype.updatePosition = function() { - this.P = this.X + LineOffset( this.buffers, this.Y ); + this.P = this.X + LineOffset( this.feeder.lineBuffers, this.Y ); }; Cursor.prototype.moveY = function( d ) { - this.Y += d; + var Y = this.Y; + + Y += d; + if( Y < 0 ) Y = 0; + + if( this.feeder.moreAt < Y ) + { + this.feeder.pan( undefined, Y - this.feeder.moreAt ); + + // Keep original position after panning + this.moveX(); + this.updatePosition(); + this.refresh(); + return; + } + + this.Y = Y; + this.moveX(); this.updatePosition(); }; diff --git a/botanjs/src/Components/Vim/LineBuffer.js b/botanjs/src/Components/Vim/LineBuffer.js index aa0360a..ff54620 100644 --- a/botanjs/src/Components/Vim/LineBuffer.js +++ b/botanjs/src/Components/Vim/LineBuffer.js @@ -24,7 +24,6 @@ { nextLineBuffer.prev = this; } - }; LineBuffer.prototype.Push = function( content, wrap ) @@ -32,6 +31,7 @@ if( content == undefined || content === "" ) { this.content = "~"; + this.br = true; this.placeholder = true; if( this.next ) this.next.Push( content, wrap ); return; diff --git a/botanjs/src/Components/Vim/LineFeeder.js b/botanjs/src/Components/Vim/LineFeeder.js index 2aba1f8..7725443 100644 --- a/botanjs/src/Components/Vim/LineFeeder.js +++ b/botanjs/src/Components/Vim/LineFeeder.js @@ -29,10 +29,18 @@ lineBuffers[i] = new LineBuffer( cols, lineBuffers[ i + 1 ] ); } - this.cursor = new Cursor( lineBuffers ); - this.lineBuffers = lineBuffers; + + this.panX = 0; + this.panY = 0; + this.setRender(); + + this.cursor = new Cursor( this ); + this.dispatcher = new EventDispatcher(); + + this.__clseLine = null; + this.__moreAt = -1; }; Feeder.prototype.init = function( content, wrap ) @@ -52,38 +60,35 @@ { if( placeholder == undefined ) placeholder = true; - if( placeholder ) - { - this.__render = function( line, steps ) - { - var display = ( line == undefined ? "" : line ) + ""; + var _self = this; - for( var i = 0; - line && i < steps && ( line = line.next ); - i ++ ) + var placeholdCond = placeholder + ? function( line ) { return true; } + : function( line ) { return !line.placeholder; } + ; + + this.__render = function( line, steps ) + { + var display = ( line == undefined ? "" : line ) + ""; + + var atSpace = false + for( var i = 0; + line && i < steps && ( line = line.next ) && placeholdCond( line ); + i ++ ) + { + if( atSpace || ( line.br && steps < ( i + line.visualLines.length ) ) ) { - display += "\n" + line; + if( !atSpace ) _self.__clseLine = line; + atSpace = true; + display += "\n@"; + continue; } - return display; - }; - } - else - { - this.__render = function( line, steps ) - { - var display = ( line == undefined ? "" : line ) + ""; + display += "\n" + line; + } - for( var i = 0; - line && i < steps && ( line = line.next ) && !line.placeholder; - i ++ ) - { - display += "\n" + line; - } - - return display; - }; - } + return display; + }; } Feeder.prototype.render = function( start, length ) @@ -101,6 +106,43 @@ return this.__render( buffs[ start ], length - 1 ); }; + Feeder.prototype.pan = function( dX, dY ) + { + if( dX == undefined ) dX = 0; + if( dY == undefined ) dY = 0; + + var X = this.panX + dX; + var Y = this.panY + dY; + + // this.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); + }; + + __readOnly( Feeder.prototype, "moreAt", function() { + if( 0 < this.__moreAt ) return this.__moreAt; + + var line = this.lineBuffers[0]; + if( line.placeholder ) return 0; + + var i = 0; + do + { + if( this.__clseLine == line ) break; + if( line.br ) i ++; + } + while( line = line.next ); + + return ( this.__moreAt = i ); + } ); + + __readOnly( Feeder.prototype, "lineStat", function() { + var X = this.cursor.X; + return ( this.cursor.Y + this.panY + 1 ) + "," + X + "-" + ( X ); + } ); + + __readOnly( Feeder.prototype, "docPos", function() { + return "Top"; + } ); + __readOnly( Feeder.prototype, "linesOccupied", function() { var line = this.lineBuffers[0]; if( line.placeholder ) return 0; diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index 159a34f..0cea4d7 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -52,6 +52,7 @@ { // Cursor movements case 72: // h + case 8: // Backspace cfeeder.cursor.moveX( -1 ); break; case 74: // j @@ -86,6 +87,14 @@ case 112: // F1, help } + var sfeeder = sender.statusFeeder; + var statusBar = sender.statusBar; + + sfeeder.init( statusBar.statusText ); + sender.stage.element.value = + cfeeder.render( 0, sender.rows - sfeeder.linesOccupied ) + + "\n" + sfeeder.render(); + sender.__blink = false; sender.select( cfeeder.cursor.position ); }; @@ -112,7 +121,13 @@ this.PosX = 1; this.PosY = 1; + this.__active = false; + + var _self = this; + stage.addEventListener( "KeyDown", KeyHandler( this, VimControls ) ); + stage.addEventListener( "Focus", function() { _self.__active = true; } ); + stage.addEventListener( "Blur", function() { _self.__active = false; } ); // Init this.content = element.value; @@ -125,6 +140,7 @@ VimArea.prototype.select = function( sel ) { + if( !this.__active ) return; var textarea = this.stage.element; if( sel ) @@ -154,12 +170,12 @@ // XXX: Placeholder var statusBar = new StatusBar( c ); statusBar.stamp( -18, function(){ - return "1,1-1"; + return cfeeder.lineStat; }); statusBar.stamp( -3, function(){ - return "All"; - }); + return cfeeder.docPos; + } ); sfeeder.init( statusBar.statusText ); @@ -167,8 +183,13 @@ cfeeder.render( 0, r - sfeeder.linesOccupied ) + "\n" + sfeeder.render(); + cfeeder.dispatcher.addEventListener( "VisualUpdate", function() + { + } ); + this.contentFeeder = cfeeder; this.statusFeeder = sfeeder; + this.statusBar = statusBar; this.__cursor = cfeeder.cursor; diff --git a/botanjs/src/Components/Vim/_this.js b/botanjs/src/Components/Vim/_this.js index 5de456f..d61f8fc 100644 --- a/botanjs/src/Components/Vim/_this.js +++ b/botanjs/src/Components/Vim/_this.js @@ -16,6 +16,7 @@ "INSERT": "-- INSERT --" , "REPLACE": "-- REPLACE --" , "MORE": "-- MORE --" + , "VISLINE": "-- VISUAL LINE --" , "WRITE": "\"%1\" %2L, %3C written" , "CONTINUE": "Press ENTER or type command to continue" , "SEARCH_HIT_BOTTOM": "Seach hit BOTTOM, contining at TOP"