forked from Botanical/BotanJS
Added VISUAL LINE
This commit is contained in:
parent
21221a6e4e
commit
fcfe5d9b60
@ -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 )
|
||||
{
|
||||
|
@ -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 )
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
} );
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user