Merge remote-tracking branch 'vim/master' into Astro

This commit is contained in:
斟酌 鵬兄 2017-01-09 10:49:14 +08:00
commit 33bf67f587
11 changed files with 205 additions and 52 deletions

View File

@ -197,7 +197,7 @@
{ {
this.__realizeIndent(); this.__realizeIndent();
feeder.pan(); feeder.pan();
cur.moveX( 1, false, true ); cur.moveX( inputChar == "\t" ? feeder.firstBuffer.tabWidth : 1, false, true );
} }
feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
@ -262,7 +262,7 @@
feeder.softReset(); feeder.softReset();
feeder.pan(); feeder.pan();
cur.moveX( i, false, true ); cur.moveX( i * feeder.firstBuffer.tabWidth, false, true );
var a = []; var a = [];
a[ IN_START ] = f; a[ IN_START ] = f;

View File

@ -25,7 +25,7 @@
this.__cursor.unsuppressEvent(); this.__cursor.unsuppressEvent();
}; };
PUT.prototype.handler = function( e ) PUT.prototype.handler = function( e, sp, newLine )
{ {
e.preventDefault(); e.preventDefault();
@ -63,20 +63,32 @@
var stator = new Stator( cur ); var stator = new Stator( cur );
var aP = cur.aPos; var aP = cur.aPos;
var contentUndo = "";
if( sp == undefined )
{
feeder.content = feeder.content.substring( 0, aP ) feeder.content = feeder.content.substring( 0, aP )
+ cput + cput + feeder.content.substring( aP );
+ feeder.content.substring( aP );
feeder.pan(); feeder.pan();
cur.moveTo( 0 < nLines ? aP : aP + clen, true ); cur.moveTo( 0 < nLines ? aP : aP + clen, true );
}
else
{
sp ++;
contentUndo = feeder.content.substring( aP, sp );
feeder.content = feeder.content.substring( 0, aP )
+ cput + feeder.content.substring( sp );
feeder.pan();
cur.moveTo( aP + clen, true );
}
var stack = new Stack(); var stack = new Stack();
if( newLine ) if( newLine )
{ {
var f = stator.save( clen, "" ); var f = stator.save( clen, contentUndo );
stack.store( function() stack.store( function()
{ {
f(); f();
@ -85,7 +97,7 @@
} }
else else
{ {
stack.store( stator.save( clen, "" ) ); stack.store( stator.save( clen, contentUndo ) );
} }
cur.rec.record( stack ); cur.rec.record( stack );

View File

@ -38,7 +38,7 @@
if( 0 < n ) p ++; if( 0 < n ) p ++;
var lowerLimmit = p; var lowerLimit = p;
var Char = et.key; var Char = et.key;
if( et.kMap( "Tab" ) ) if( et.kMap( "Tab" ) )
@ -64,7 +64,7 @@
tX = f.content.lastIndexOf( Char, cur.aPos - 1 ); tX = f.content.lastIndexOf( Char, cur.aPos - 1 );
} }
if( lowerLimmit <= tX && tX < upperLimit ) if( lowerLimit <= tX && tX < upperLimit )
{ {
cur.moveTo( tX ); cur.moveTo( tX );
} }

View File

@ -12,6 +12,8 @@
var DELETE = ns[ NS_INVOKE ]( "DELETE" ); var DELETE = ns[ NS_INVOKE ]( "DELETE" );
/** @type {Components.Vim.IAction} */ /** @type {Components.Vim.IAction} */
var SHIFT_LINES = ns[ NS_INVOKE ]( "SHIFT_LINES" ); var SHIFT_LINES = ns[ NS_INVOKE ]( "SHIFT_LINES" );
/** @type {Components.Vim.IAction} */
var PUT = ns[ NS_INVOKE ]( "PUT" );
var MODE_NULL = -1; var MODE_NULL = -1;
var MODE_VISUAL = 0; var MODE_VISUAL = 0;
@ -121,6 +123,10 @@
{ {
Action = new DELETE( cur ); Action = new DELETE( cur );
} }
else if( e.kMap( "p" ) )
{
Action = new PUT( cur );
}
else if( e.kMap( "V" ) ) else if( e.kMap( "V" ) )
{ {
if( this.__mode == MODE_LINE ) return true; if( this.__mode == MODE_LINE ) return true;
@ -180,7 +186,8 @@
// this swap the cursor direction from LTR to RTL // this swap the cursor direction from LTR to RTL
// i.e. treat all delete as "e<----s" flow // i.e. treat all delete as "e<----s" flow
// to keep the cursor position as the top on UNDO / REDO // to keep the cursor position as the top on UNDO / REDO
if( Action.constructor == DELETE && startLine.aPos < cur.aPos ) var IsContMod = ~[ DELETE, PUT ].indexOf( Action.constructor );
if( IsContMod && startLine.aPos < cur.aPos )
{ {
var o = cur.aPos; var o = cur.aPos;
cur.moveTo( startLine.aPos, true ); cur.moveTo( startLine.aPos, true );
@ -189,7 +196,7 @@
Action.handler( e, startLine.aPos, lineMode ); Action.handler( e, startLine.aPos, lineMode );
if( Action.constructor != DELETE ) if( !IsContMod )
{ {
cur.moveTo( startLine.aPos ); cur.moveTo( startLine.aPos );
} }

View File

@ -616,6 +616,14 @@
var BracketMatch = analyzer.bracketIn( "[", ccur.aPos ); var BracketMatch = analyzer.bracketIn( "[", ccur.aPos );
e2.__range = BracketMatch; e2.__range = BracketMatch;
}; };
var singleQuote = function( e2 ) {
var BracketMatch = analyzer.quoteIn( "'", ccur.aPos );
e2.__range = BracketMatch;
};
var doubleQuote = function( e2 ) {
var BracketMatch = analyzer.quoteIn( "\"", ccur.aPos );
e2.__range = BracketMatch;
};
// Bracket boundaries // Bracket boundaries
this.__composite( e, bracket, SHIFT + _0 ); this.__composite( e, bracket, SHIFT + _0 );
@ -624,6 +632,10 @@
this.__composite( e, squareBracket, S_BRACKET_R ); this.__composite( e, squareBracket, S_BRACKET_R );
this.__composite( e, curlyBracket, SHIFT + S_BRACKET_L ); this.__composite( e, curlyBracket, SHIFT + S_BRACKET_L );
this.__composite( e, curlyBracket, SHIFT + S_BRACKET_R ); this.__composite( e, curlyBracket, SHIFT + S_BRACKET_R );
// Quote boundaries
this.__composite( e, singleQuote, QUOTE );
this.__composite( e, doubleQuote, SHIFT + QUOTE );
break; break;
case G: case G:
@ -725,7 +737,7 @@
var cfeeder = this.__cfeeder; var cfeeder = this.__cfeeder;
var ccur = this.__ccur; var ccur = this.__ccur;
if( !ccur.action || ccur.action.allowMovement ) if( !this.__cMovement && ( !ccur.action || ccur.action.allowMovement ) )
{ {
this.__modCommand( e ); this.__modCommand( e );
if( e.canceled ) return; if( e.canceled ) return;

View File

@ -9,6 +9,8 @@
var Actions = __import( "Components.Vim.Actions.*" ); var Actions = __import( "Components.Vim.Actions.*" );
var occurence = __import( "System.utils.Perf.CountSubstr" );
var LineOffset = function( buffs, l ) var LineOffset = function( buffs, l )
{ {
/** @type {Components.Vim.LineBuffer} */ /** @type {Components.Vim.LineBuffer} */
@ -69,6 +71,8 @@
this.cols = feeder.firstBuffer.cols; this.cols = feeder.firstBuffer.cols;
// The preferred X position // The preferred X position
// i.e. last line was at pos 23
// moving to next line will prefer pos at 23
this.pX = 0; this.pX = 0;
// The displaying X position // The displaying X position
@ -129,10 +133,11 @@
var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart; var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart;
jumpX += Math.ceil( jumpX / pline.cols ) - 1; jumpX += Math.ceil( jumpX / pline.cols ) - 1;
jumpX += occurence( content.substring( lineStart + 1, aPos ), "\t" ) * ( pline.tabWidth - 1 );
if( jumpY ) this.moveY( jumpY ); if( jumpY ) this.moveY( jumpY );
// This needed because first line does not contain first "\n" character // This is needed because first line does not contain the first "\n" character
if( 0 < this.getLine().lineNum && lineStart <= aPos ) jumpX --; if( 0 < this.getLine().lineNum && lineStart <= aPos ) jumpX --;
this.moveX( - Number.MAX_VALUE ); this.moveX( - Number.MAX_VALUE );
@ -179,26 +184,14 @@
var hasPhantomSpace = true; var hasPhantomSpace = true;
// Empty lines has length of 1 // Empty lines has length of 1
// If length larger than a, need to compensate the lineEnd // Need to compensate the lineEnd for phantomSpace
// for phantomSpace // if length is 1 < and != line.cols
if( 1 < cLen ) if( 1 < cLen )
{ {
// Begin check if whether this line contains phantomSpace // Begin check if this line contains phantomSpace
var lineNum = line.lineNum - 1; // hasPhantomSpace = 0 < ( rawLine.displayLength ) % cols
var str = feeder.content; var rline = this.rawLine;
for( var i = str.indexOf( "\n" ), j = 0; 0 <= i; i = str.indexOf( "\n", i ), j ++ ) hasPhantomSpace = 0 < ( rline.length + occurence( rline, "\t" ) * ( line.tabWidth - 1 ) ) % line.cols;
{
if( lineNum == j ) break;
i ++;
}
if( j == 0 && i == -1 ) i = 0;
var end = str.indexOf( "\n", i + 1 );
end = end == -1 ? str.length : end;
// Actual LineLength
var hasPhantomSpace = 0 < ( end - i - 1 ) % line.cols;
if( hasPhantomSpace ) if( hasPhantomSpace )
{ {
@ -421,14 +414,12 @@
Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; }; Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; };
Cursor.prototype.unsuppressEvent = function() { -- this.__suppEvt; }; Cursor.prototype.unsuppressEvent = function() { -- this.__suppEvt; };
Cursor.prototype.getLine = function() Cursor.prototype.getLine = function( raw )
{ {
var feeder = this.feeder; var feeder = this.feeder;
var line = feeder.firstBuffer; var line = feeder.firstBuffer;
var eBuffer = feeder.lastBuffer.next; var eBuffer = feeder.lastBuffer.next;
for( var i = 0; for( var i = 0; line != eBuffer; line = line.next )
line != eBuffer;
line = line.next )
{ {
if( line.br ) i ++; if( line.br ) i ++;
if( this.Y == i ) return line; if( this.Y == i ) return line;
@ -437,26 +428,49 @@
return null; return null;
}; };
__readOnly( Cursor.prototype, "rawLine", function()
{
var str = this.feeder.content;
var lineNum = this.getLine().lineNum - 1;
var i = str.indexOf( "\n" ), j = 0;
for( ; 0 <= i; i = str.indexOf( "\n", i ), j ++ )
{
if( lineNum == j ) break;
i ++;
}
if( j == 0 && i == -1 ) i = 0;
var end = str.indexOf( "\n", i + 1 );
return str.substring( i + 1, end );
} );
// The position offset relative to current line // The position offset relative to current line
__readOnly( Cursor.prototype, "aX", function() __readOnly( Cursor.prototype, "aX", function()
{ {
var X = this.X; var X = this.X;
var f = this.feeder; var f = this.feeder;
var w = 1; var w = 0;
// Calculate wordwrap offset // Calculate wordwrap offset
if( f.wrap ) if( f.wrap )
{ {
var lines = this.getLine().visualLines; var lines = this.getLine().visualLines;
// Since w represent valid absX position
// w couldn't handle INSERT at the line end with phantomSpace
// because phantomSpace is not a valid character
// So we calculate along with the phantomSpace here
var phantomSpace = X;
for( var i in lines ) for( var i in lines )
{ {
/** @type {Components.Vim.LineBuffer} */ /** @type {Components.Vim.LineBuffer} */
var vline = lines[ i ]; var vline = lines[ i ];
// Actual length // Actual length
var aLen = vline.content.toString().length; var aLen = vline.content.length;
// Visual length // Visual length
var vLen = vline.toString().length; var vLen = vline.toString().length;
@ -467,10 +481,36 @@
if( 0 <= X ) if( 0 <= X )
{ {
w += aLen; w += aLen;
phantomSpace -= 1 + occurence( vline.content, "\t" ) * ( vline.tabWidth - 1 );
} }
else if( X < 0 ) else if( X < 0 )
{ {
w += X + vLen; X += vLen + 1;
var rline = this.rawLine.substr( w );
var l = rline.length;
var j = 0;
if( rline[ 0 ] == "\t" )
{
X -= vline.tabWidth - 1;
phantomSpace -= vline.tabWidth - 1;
}
for( var i = 1; j < X && i < rline.length; i ++ )
{
if( rline[ i ] == "\t" )
{
X -= vline.tabWidth - 1;
phantomSpace -= vline.tabWidth - 1;
}
j ++;
}
w += j;
if( w < phantomSpace ) w = phantomSpace;
break; break;
} }
} }

View File

@ -13,7 +13,9 @@
this.br = false; this.br = false;
this.placeholder = true; this.placeholder = true;
this.lineNum = 0; this.lineNum = 0;
this.tabWidth = 8; this.tabWidth = 4;
this.__tabc = "";
for( var i = 0; i < this.tabWidth; i ++ ) this.__tabc += " ";
if( nextLineBuffer ) if( nextLineBuffer )
{ {
@ -105,13 +107,14 @@
LineBuffer.prototype.toString = function() LineBuffer.prototype.toString = function()
{ {
var c = this.cols - occurence( this.content, "\t" ) * ( this.tabWidth - 1 ); var cont = this.content.replace( /\t/g, this.__tabc );
if( this.content.length < c )
if( cont.length < this.cols )
{ {
return this.content + " "; return cont + " ";
} }
return this.content || " "; return cont || " ";
}; };
__readOnly( LineBuffer.prototype, "nextLine", function() __readOnly( LineBuffer.prototype, "nextLine", function()

View File

@ -158,9 +158,7 @@
} }
} }
this.firstBuffer.Push( this.firstBuffer.Push( this.content.substr( f + 1 ), this.wrap, i );
this.content.substr( f + 1 )
, this.wrap, i );
this.panX = X; this.panX = X;
this.panY = Y; this.panY = Y;
@ -213,11 +211,19 @@
var line = this.cursor.getLine(); var line = this.cursor.getLine();
var tabStat = ""; var tabStat = "";
var tabs = line.content.match( /\t/g ); var tabs = 0;
var l = this.cursor.aPos;
var i = l - X;
do
{
if( this.content[ i + 1 ] == "\t" ) tabs ++;
i ++;
}
while( i < l )
if( tabs ) if( tabs )
{ {
tabStat = "-" + ( X + tabs.length * ( line.tabWidth - 1 ) ); tabStat = "-" + ( X + tabs * ( line.tabWidth - 1 ) );
} }
return ( line.lineNum + 1 ) + "," + X + tabStat; return ( line.lineNum + 1 ) + "," + X + tabStat;

View File

@ -4,6 +4,8 @@
/** @type {System.Debug} */ /** @type {System.Debug} */
var debug = __import( "System.Debug" ); var debug = __import( "System.Debug" );
var beep = __import( "Components.Vim.Beep" );
/** @type {Components.Vim.Syntax.Word} */ /** @type {Components.Vim.Syntax.Word} */
var Word = ns[ NS_INVOKE ]( "Word" ); var Word = ns[ NS_INVOKE ]( "Word" );
@ -265,6 +267,73 @@
return new TokenMatch(); return new TokenMatch();
}; };
Analyzer.prototype.quoteIn = function( Char )
{
var f = this.__feeder;
var cur = f.cursor;
var n = cur.getLine().lineNum;
var p = 0;
for( var i = 0; p != -1 && i < n; i ++ ) p = f.content.indexOf( "\n", p + 1 );
var upperLimit = f.content.indexOf( "\n", p + 1 );
if( 0 < n ) p ++;
var lowerLimit = p;
// Cursor is at the quote character
// Move cursor inside the matching quote
if( f.content[ cur.aPos ] == Char )
{
// Mark all quotes on current line
var quotePos = [];
var l = 0;
for( var i = lowerLimit; i < upperLimit; i ++ )
{
if( f.content[ i ] == Char )
quotePos[ l ++ ] = i;
}
var indexQuote = quotePos.indexOf( cur.aPos );
var indexEnd = ( indexQuote == ( l - 1 ) );
// Length is even: Quotes are matched
// OR
// Length is odd and cursor is not at the last quote
if( l % 2 == 0 || !indexEnd )
{
cur.moveX( indexQuote % 2 == 0 ? 1 : -1 );
}
// Cursor is at the last quote
else
{
// Beep because last quote of odd length is an unmatch quote
beep();
return new TokenMatch();
}
}
// Forward
var fX = f.content.indexOf( Char, cur.aPos + 1 );
// backward
var bX = f.content.lastIndexOf( Char, cur.aPos - 1 );
if( lowerLimit <= bX && fX < upperLimit )
{
var tMatch = new TokenMatch();
tMatch.__open = bX + 1;
tMatch.__close = fX - 1;
tMatch.__selected = Char;
return tMatch;
}
else beep();
return new TokenMatch();
};
Analyzer.prototype.__getPairs = function( def, reload ) Analyzer.prototype.__getPairs = function( def, reload )
{ {
if( !reload && this.__tokpairs[ def ] ) if( !reload && this.__tokpairs[ def ] )

View File

@ -63,3 +63,5 @@ Components.Vim.Cursor.position;
Components.Vim.Cursor.position.start; Components.Vim.Cursor.position.start;
/** @type Number */ /** @type Number */
Components.Vim.Cursor.position.end; Components.Vim.Cursor.position.end;
/** @type String */
Components.Vim.Cursor.rawLine;

View File

@ -6,6 +6,8 @@ Components.Vim.Syntax.Analyzer.bracketAt;
/** @type Function */ /** @type Function */
Components.Vim.Syntax.Analyzer.bracketIn; Components.Vim.Syntax.Analyzer.bracketIn;
/** @type Function */ /** @type Function */
Components.Vim.Syntax.Analyzer.quoteIn;
/** @type Function */
Components.Vim.Syntax.Analyzer.wordAt; Components.Vim.Syntax.Analyzer.wordAt;
/** @type Function */ /** @type Function */
Components.Vim.Syntax.Analyzer.quoteAt; Components.Vim.Syntax.Analyzer.quoteAt;