commit fcfe5d9b6028dfb04d09a031510dfd18ea9726cc
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2016-04-04T18:57:40Z |
| subject | Added VISUAL LINE |
commit fcfe5d9b6028dfb04d09a031510dfd18ea9726cc
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2016-04-04T18:57:40Z
Added VISUAL LINE
---
botanjs/src/Components/Vim/Actions/DELETE.js | 3 +-
botanjs/src/Components/Vim/Actions/TO.js | 8 +-
botanjs/src/Components/Vim/Actions/VISUAL.js | 227 ++++++++++++++++++++++++---
botanjs/src/Components/Vim/Actions/YANK.js | 3 +-
botanjs/src/Components/Vim/Controls.js | 5 +-
botanjs/src/Components/Vim/Cursor.js | 3 +-
botanjs/src/Components/Vim/VimArea.js | 5 +
7 files changed, 220 insertions(+), 34 deletions(-)
diff --git a/botanjs/src/Components/Vim/Actions/DELETE.js b/botanjs/src/Components/Vim/Actions/DELETE.js
index 30cb180..10a09c9 100644
--- a/botanjs/src/Components/Vim/Actions/DELETE.js
+++ b/botanjs/src/Components/Vim/Actions/DELETE.js
@@ -33,7 +33,7 @@
this.__cursor.unsuppressEvent();
};
- DELETE.prototype.handler = function( e, sp )
+ DELETE.prototype.handler = function( e, sp, newLine )
{
e.preventDefault();
@@ -46,7 +46,6 @@
var feeder = cur.feeder;
var Triggered = false;
- var newLine = false;
if( sp == undefined )
{
diff --git a/botanjs/src/Components/Vim/Actions/TO.js b/botanjs/src/Components/Vim/Actions/TO.js
index 1ff0bcd..eb1e00e 100644
--- a/botanjs/src/Components/Vim/Actions/TO.js
+++ b/botanjs/src/Components/Vim/Actions/TO.js
@@ -40,9 +40,6 @@
var lowerLimmit = p;
- var cX = cur.X;
- var tX = cX;
-
var Char = et.key;
if( et.kMap( "Tab" ) )
{
@@ -55,15 +52,16 @@
return;
}
+ var tX = -1;
// Forward
if( em.kMap( "t" ) || em.kMap( "f" ) )
{
- tX = f.content.indexOf( Char, p + cX + 1 );
+ tX = f.content.indexOf( Char, cur.aPos + 1 );
}
// backward
else
{
- tX = f.content.lastIndexOf( Char, p + cX - 1 );
+ tX = f.content.lastIndexOf( Char, cur.aPos - 1 );
}
if( lowerLimmit <= tX && tX < upperLimit )
diff --git a/botanjs/src/Components/Vim/Actions/VISUAL.js b/botanjs/src/Components/Vim/Actions/VISUAL.js
index bd9085d..b53b47d 100644
--- a/botanjs/src/Components/Vim/Actions/VISUAL.js
+++ b/botanjs/src/Components/Vim/Actions/VISUAL.js
@@ -11,12 +11,44 @@
/** @type {Components.Vim.IAction} */
var DELETE = ns[ NS_INVOKE ]( "DELETE" );
+ var MODE_NULL = -1;
+ var MODE_VISUAL = 0;
+ var MODE_LINE = 1;
+
+ // The offset of given line relative to content
+ var offsetY = function( cur, l )
+ {
+ if( l == 0 ) return 0;
+
+ var f = cur.feeder;
+
+ var j = 0;
+
+ var last = -1;
+ for( var i = f.content.indexOf( "\n" ); 0 <= i; i = f.content.indexOf( "\n", i + 1 ) )
+ {
+ last = i;
+ j ++;
+ if( l <= j ) break;
+ }
+
+ if( f.EOF ) i = last;
+
+ // "\n" compensation
+ var c = f.content[ i + 1 ];
+ if(!( c == undefined || c == "\n" ))
+ {
+ i ++;
+ }
+
+ return i;
+ };
+
/** @type {Components.Vim.IAction} */
var VISUAL = function( Cursor )
{
this.__reset( Cursor );
- this.__msg = Mesg( "VISUAL" );
-
+ this.__msg = "";
Cursor.blink = false;
Cursor.pSpace = true;
};
@@ -25,9 +57,25 @@
{
/** @type {Components.Vim.Cursor} */
this.__cursor = Cursor;
- this.__startaP = Cursor.aPos;
- this.__start = Cursor.PStart;
- this.__selStart = Cursor.PStart;
+
+ var s = {
+ lineNum: Cursor.getLine().lineNum
+ , X: Cursor.X
+ , aPos: Cursor.aPos
+ , pstart: Cursor.PStart
+ };
+
+ s.aStart = s.aPos - Cursor.aX;
+
+ Cursor.suppressEvent();
+ Cursor.lineEnd( true );
+
+ s.aEnd = Cursor.aPos;
+
+ Cursor.moveTo( s.aPos );
+ Cursor.unsuppressEvent();
+
+ this.__startLine = s;
};
VISUAL.prototype.allowMovement = true;
@@ -38,8 +86,7 @@
c.blink = true;
c.pSpace = false;
- c.PStart = this.__selStart;
- c.PEnd = this.__selStart + 1;
+ c.updatePosition();
// This fix the highlighting position of missing phantomSpace
// for maximum filled line
@@ -59,8 +106,11 @@
if( e.ModKeys ) return;
var cur = this.__cursor;
+ var feeder = cur.feeder;
var Action = null;
+ var dispatchUpdate = false;
+
if( e.kMap( "y" ) )
{
Action = new YANK( cur );
@@ -69,27 +119,73 @@
{
Action = new DELETE( cur );
}
+ else if( e.kMap( "V" ) )
+ {
+ if( this.__mode == MODE_LINE ) return true;
+ else
+ {
+ dispatchUpdate = true;
+ this.__mode = MODE_LINE;
+ this.__msg = Mesg( "VISLINE" );
+ }
+ }
+ else if( e.kMap( "v" ) )
+ {
+ if( this.__mode == MODE_VISUAL ) return true;
+ else
+ {
+ dispatchUpdate = true;
+ this.__mode = MODE_VISUAL;
+ this.__msg = Mesg( "VISUAL" );
+
+ cur.updatePosition();
+ }
+ }
+
+ if( dispatchUpdate )
+ feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
+
+ if( this.__mode == MODE_NULL )
+ {
+ debug.Error( new Error( "Mode is undefined" ) );
+ return true;
+ }
+ var startLine = this.__startLine;
if( Action )
{
cur.suppressEvent();
- // Low-level cursor position adjustment
+ var lineMode = this.__mode == MODE_LINE;
+ if( lineMode )
+ {
+ if( startLine.aPos < cur.aPos )
+ {
+ cur.lineEnd( true );
+ startLine.aPos = startLine.aStart;
+ }
+ else
+ {
+ cur.lineStart();
+ startLine.aPos = startLine.aEnd;
+ }
+ }
+ // Cursor position adjustment
// this swap the cursor direction from LTR to RTL
// i.e. treat all delete as "e<----s" flow
// to keep the cursor position as the top on UNDO / REDO
- if( Action.constructor == DELETE && this.__startaP < cur.aPos )
+ if( Action.constructor == DELETE && startLine.aPos < cur.aPos )
{
var o = cur.aPos;
- cur.moveTo( this.__startaP, true );
- this.__startaP = o;
+ cur.moveTo( startLine.aPos, true );
+ startLine.aPos = o;
}
- Action.handler( e, this.__startaP );
+ Action.handler( e, startLine.aPos, lineMode );
if( Action.constructor != DELETE )
{
- cur.moveTo( this.__startaP );
+ cur.moveTo( startLine.aPos );
}
this.__msg = Action.getMessage();
@@ -97,7 +193,7 @@
Action.dispose();
cur.unsuppressEvent();
- this.__selStart = cur.PStart;
+ startLine.pstart = cur.PStart;
return true;
}
@@ -109,30 +205,119 @@
var r = e.range;
- if( cur.aPos == this.__startaP )
+ if( cur.aPos == startLine.aPos )
{
cur.moveTo( r.open, true );
this.__reset( cur );
+ startLine = this.__startLine;
}
cur.unsuppressEvent();
cur.moveTo( r.close, true );
}
- var prevPos = this.__start;
- var newPos = cur.PStart;
+ var currAp = cur.aPos;
+
+ // Calculate the visible max min aPos of the current screen
+ var line = feeder.firstBuffer;
+ var firstLine = line.lineNum;
+ var minAp = offsetY( cur, firstLine );
+ var maxAp = offsetY( cur, firstLine + feeder.moreAt + 1 ) - 1;
+
+ debug.Info( "Min aPos: " + minAp, "Max aPos: " + maxAp );
+
+ var pstart = startLine.X;
+ var nstart = cur.PStart;
+
+ // highlight from the start
+ if( startLine.aPos < minAp )
+ {
+ pstart = 0;
+ }
+ // highlight from the end
+ else if( maxAp < startLine.aPos )
+ {
+ pstart = -2;
+ var i = 0;
+ do
+ {
+ if( line.placeholder ) break;
+ if( i <= feeder.moreAt )
+ {
+ pstart += line.toString().length + 1;
+ }
+ i ++;
+ }
+ while( line = line.next );
+ }
+ else
+ {
+ var l = startLine.lineNum;
+ if( this.__mode == MODE_LINE )
+ {
+ cur.suppressEvent();
+ pstart = 0;
+
+ if( currAp < startLine.aPos )
+ {
+ pstart = -1;
+ l ++;
+
+ cur.lineStart();
+ nstart = cur.PStart;
+ }
+ else if( startLine.aPos < currAp )
+ {
+ cur.lineEnd( true );
+ nstart = cur.PStart;
+ }
+ // aPos == currPos
+ else
+ {
+ cur.lineStart();
+ nstart = cur.PStart;
+ cur.lineEnd( true );
+ pstart = cur.PStart;
+ l = line.lineNum;
+ }
+
+ cur.moveTo( currAp, true );
+
+ cur.unsuppressEvent();
+ }
+ else if( this.__mode == MODE_VISUAL )
+ {
+ if( currAp == startLine.aPos ) return;
+ }
+
+ // Append the Y offset
+ var i = 0;
+ do
+ {
+ if( line.lineNum == l ) break;
+ pstart += line.toString().length + 1;
+ }
+ while( line = line.next );
+ }
+
+ var prevPos = pstart;
+ var newPos = nstart;
var posDiff = newPos - prevPos;
- if( 0 <= posDiff )
+
+ var currAp = cur.aPos;
+
+ // Sets the visual position
+ // s-->e
+ if( 0 < posDiff )
{
- this.__selStart = newPos;
newPos = newPos + 1;
}
+ // e<--s
else if( posDiff < 0 )
{
prevPos += posDiff;
- newPos = this.__start + 1;
- this.__selStart = prevPos;
+ newPos = pstart + 1;
}
cur.PStart = prevPos;
diff --git a/botanjs/src/Components/Vim/Actions/YANK.js b/botanjs/src/Components/Vim/Actions/YANK.js
index 86ba222..44e3c27 100644
--- a/botanjs/src/Components/Vim/Actions/YANK.js
+++ b/botanjs/src/Components/Vim/Actions/YANK.js
@@ -27,7 +27,7 @@
this.__cursor.unsuppressEvent();
};
- YANK.prototype.handler = function( e, sp )
+ YANK.prototype.handler = function( e, sp, newLine )
{
e.preventDefault();
@@ -41,7 +41,6 @@
var Triggered = false;
- var newLine = false;
if( sp == undefined )
{
Triggered = true;
diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index f38b847..aace42f 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -271,10 +271,9 @@
break;
case V: // Visual
- ccur.openAction( "VISUAL" );
- break;
case SHIFT + V: // Visual line
- ccur.openAction( "VISUAL_LINE" );
+ ccur.openAction( "VISUAL" );
+ ccur.action.handler( e );
break;
case SHIFT + SEMI_COLON: // ":" Command line
diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js
index 3eaaac0..876614e 100644
--- a/botanjs/src/Components/Vim/Cursor.js
+++ b/botanjs/src/Components/Vim/Cursor.js
@@ -435,7 +435,7 @@
return null;
};
- // The absX for current Line
+ // The position offset relative to current line
__readOnly( Cursor.prototype, "aX", function()
{
var X = this.X;
@@ -473,6 +473,7 @@
}
}
}
+ else return this.X;
return w;
} );
diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js
index 1817deb..f0899af 100644
--- a/botanjs/src/Components/Vim/VimArea.js
+++ b/botanjs/src/Components/Vim/VimArea.js
@@ -222,6 +222,11 @@
_self.select( cfeeder.cursor.position );
};
+ cfeeder.dispatcher.addEventListener( "SelectionChanged", function()
+ {
+ _self.select( cfeeder.cursor.position );
+ } );
+
cfeeder.dispatcher.addEventListener( "VisualUpdate", Update );
Update();