commit 1511c709573047aedbf219cea0866747217378c7
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2017-03-17T05:34:31Z |
| subject | Added :{number} support |
commit 1511c709573047aedbf219cea0866747217378c7
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2017-03-17T05:34:31Z
Added :{number} support
---
.../src/Components/Vim/Actions/EDITOR_COMMAND.js | 10 +++
botanjs/src/Components/Vim/Actions/MARKS.js | 83 ++++++++++++++++++++++
botanjs/src/Components/Vim/Actions/PRINT.js | 48 +++++++++++++
botanjs/src/Components/Vim/Controls.js | 35 ++++++---
botanjs/src/Components/Vim/Cursor.js | 81 +++++++++++++++------
botanjs/src/Components/Vim/LineFeeder.js | 40 +++++++++--
botanjs/src/Components/Vim/State/Marks.js | 31 ++++++++
botanjs/src/Components/Vim/VimArea.js | 3 +
botanjs/src/externs/Components.Vim.Cursor.js | 2 +
botanjs/src/externs/Components.Vim.LineFeeder.js | 2 +
botanjs/src/externs/Components.Vim.State.Marks.js | 10 +++
botanjs/src/externs/Components.Vim.VimArea.js | 5 ++
12 files changed, 313 insertions(+), 37 deletions(-)
diff --git a/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js b/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js
index 7b2a6f1..78ff532 100644
--- a/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js
+++ b/botanjs/src/Components/Vim/Actions/EDITOR_COMMAND.js
@@ -79,6 +79,9 @@
case "registers":
out[ CMD_TYPE ] = "REGISTERS";
break;
+ case "marks":
+ out[ CMD_TYPE ] = "MARKS";
+ break;
case "ver":
case "version":
out[ CMD_TYPE ] = "VERSION";
@@ -90,6 +93,13 @@
case "varec":
out[ CMD_TYPE ] = "VA_REC";
break;
+
+ case "": // Range jumping
+ pattern.push( true );
+ case "p":
+ allowRange = true;
+ out[ CMD_TYPE ] = "PRINT";
+ break;
}
if( range !== "" )
diff --git a/botanjs/src/Components/Vim/Actions/MARKS.js b/botanjs/src/Components/Vim/Actions/MARKS.js
new file mode 100644
index 0000000..4ffe01f
--- /dev/null
+++ b/botanjs/src/Components/Vim/Actions/MARKS.js
@@ -0,0 +1,83 @@
+(function(){
+ var ns = __namespace( "Components.Vim.Actions" );
+
+ /** @type {System.Debug} */
+ var debug = __import( "System.Debug" );
+
+ var VimError = __import( "Components.Vim.Error" );
+ var Mesg = __import( "Components.Vim.Message" );
+
+ /** @type {System.Debug} */
+ var Marks = __import( "Components.Vim.State.Marks" );
+ var Keys = Marks.Keys;
+
+ /** @type {Components.Vim.IAction} */
+ var MARKS = function( Cursor )
+ {
+ /** @type {Components.Vim.Cursor} */
+ this.__cursor = Cursor;
+ this.__msg = "";
+ Cursor.suppressEvent();
+ };
+
+ MARKS.prototype.dispose = function()
+ {
+ this.__cursor.unsuppressEvent();
+ };
+
+ MARKS.prototype.handler = function( e, p )
+ {
+ e.preventDefault();
+
+ /** @type {Components.Vim.State.Marks} */
+ var marks = e.target.marks;
+
+ var msg = ":marks";
+
+ /**
+ * Regarding to marks 0-9, from Vim docs
+ * Numbered marks '0 to '9 are quite different. They can not be set directly.
+ * They are only present when using a viminfo file viminfo-file. Basically '0
+ * is the location of the cursor when you last exited Vim, '1 the last but one
+ * time, etc. Use the "r" flag in 'viminfo' to specify files for which no
+ * Numbered mark should be stored. See viminfo-file-marks.
+ * TODO: Need to redefine marks 0-9
+ **/
+
+ // Fuck this, use silly paddings
+ msg += "\nmark line col file/text";
+
+ var feeder = this.__cursor.feeder;
+ for( var i = 0, j = Keys[ i ]; j != undefined; i ++, j = Keys[ i ] )
+ {
+ var r = marks.get( j );
+ if( !r ) continue;
+
+ var line = ( r[0] + 1 ) + "";
+ var col = ( r[1] + 1 ) + "";
+ var t = feeder.line( r[0] - 1 ).replace( /^[\t ]+/, "" );
+
+ var ll = 4 - line.length;
+ for( var il = 0; il < ll; il ++ ) line = " " + line;
+
+ var ll = 3 - col.length;
+ for( var il = 0; il < ll; il ++ ) col = " " + col;
+
+ msg += "\n " + j + " " + line + " " + col + " " + t;
+ }
+
+ var lastLine = Mesg( "WAIT_FOR_INPUT" );
+
+ var l = this.__cursor.feeder.firstBuffer.cols;
+ for( var i = msg.length; i < l; i ++ ) msg += " ";
+
+ this.__msg = msg + "\n" + lastLine;
+ };
+
+ MARKS.prototype.getMessage = function()
+ {
+ return this.__msg;
+ };
+
+ ns[ NS_EXPORT ]( EX_CLASS, "MARKS", MARKS );
+})();
diff --git a/botanjs/src/Components/Vim/Actions/PRINT.js b/botanjs/src/Components/Vim/Actions/PRINT.js
new file mode 100644
index 0000000..7e8a9ed
--- /dev/null
+++ b/botanjs/src/Components/Vim/Actions/PRINT.js
@@ -0,0 +1,48 @@
+(function(){
+ var ns = __namespace( "Components.Vim.Actions" );
+
+ /** @type {System.Debug} */
+ var debug = __import( "System.Debug" );
+
+ /** @type {Components.Vim.IAction} */
+ var PRINT = function( Cursor )
+ {
+ /** @type {Components.Vim.Cursor} */
+ this.__cursor = Cursor;
+ this.__msg = "";
+ };
+
+ PRINT.prototype.dispose = function() { };
+ PRINT.prototype.handler = function( e, args, range )
+ {
+ e.preventDefault();
+
+ if( args[0] === true )
+ {
+ switch( range )
+ {
+ case "%":
+ case "$":
+ this.__cursor.moveY( Number.MAX_VALUE );
+ return;
+ case ".":
+ this.__cursor.lineStart( true );
+ break;
+ case "":
+ default:
+ var lineNum = parseInt( range ) - 1;
+ if( lineNum )
+ {
+ this.__cursor.gotoLine( 0 < lineNum ? lineNum : 0 );
+ }
+ }
+ }
+ };
+
+ PRINT.prototype.getMessage = function()
+ {
+ return this.__msg;
+ };
+
+ ns[ NS_EXPORT ]( EX_CLASS, "PRINT", PRINT );
+})();
diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index 20654f1..7057be3 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -478,16 +478,17 @@
{
var kCode = e.keyCode;
- if( this.__cMovement )
+ if( this.__captureComp )
{
if( !e.ModKeys )
{
this.__composite( e );
- this.__cMovement = false;
+ this.__captureComp = false;
return true;
}
}
+ var inst = this.__vimArea;
var ccur = this.__ccur;
var cfeeder = ccur.feeder;
@@ -610,10 +611,22 @@
break;
+ case M:
+ this.__captureComp = true;
+
+ var marks = this.__vimArea.marks;
+ this.__composite( e, function( e2 ) {
+ var line = ccur.getLine().lineNum;
+ if( !marks.set( e2.key, line, ccur.aX ) )
+ {
+ beep();
+ }
+ }, ANY_KEY );
+ break;
case SHIFT + T: // To
case T: // To
- this.__cMovement = true;
+ this.__captureComp = true;
this.__composite( e, function( e2 ) {
var oX = ccur.X;
@@ -632,7 +645,7 @@
break;
case SHIFT + F: // To
case F: // To
- this.__cMovement = true;
+ this.__captureComp = true;
this.__composite( e, function( e2 ) {
ccur.openRunAction( "TO", e, e2 );
@@ -659,7 +672,7 @@
var analyzer = this.__vimArea.contentAnalyzer;
- this.__cMovement = true;
+ this.__captureComp = true;
// Word boundary
this.__composite( e, function( e2 ) {
@@ -703,7 +716,7 @@
case G:
- this.__cMovement = true;
+ this.__captureComp = true;
// Go to top
this.__composite( e, function() {
@@ -775,7 +788,7 @@
break;
case SLASH: // "/" Search movement
- this.__cMovement = true;
+ this.__captureComp = true;
this.__divedCCmd = new ExCommand( ccur, "/" );
this.__divedCCmd.handler( e );
@@ -788,7 +801,7 @@
break;
}
- this.__cMovement = true;
+ this.__captureComp = true;
var exCmd = new ExCommand( ccur, ":" );
exCmd.handler( e );
@@ -827,7 +840,7 @@
if( e.Escape )
{
var b = false;
- this.__cMovement = false;
+ this.__captureComp = false;
if( this.__compositeReg )
{
@@ -853,7 +866,7 @@
if( this.__divedCCmd.handler( e ) )
{
this.__divedCCmd.dispose();
- this.__cMovement = false;
+ this.__captureComp = false;
this.__divedCCmd = null;
return;
}
@@ -864,7 +877,7 @@
var cfeeder = this.__cfeeder;
var ccur = this.__ccur;
- if( !this.__cMovement && ( !ccur.action || ccur.action.allowMovement ) )
+ if( !this.__captureComp && ( !ccur.action || ccur.action.allowMovement ) )
{
this.__modCommand( e );
if( e.canceled ) return;
diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js
index ab3d28b..c1d7ceb 100644
--- a/botanjs/src/Components/Vim/Cursor.js
+++ b/botanjs/src/Components/Vim/Cursor.js
@@ -106,6 +106,8 @@
// Move to an absolute position
Cursor.prototype.moveTo = function( aPos, phantomSpace, skipTabs )
{
+ this.__suppressUpdate();
+
var content = this.feeder.content;
var pline = this.getLine();
var lastLineNum = pline.lineNum;
@@ -131,10 +133,7 @@
}
var jumpY = expLineNum - lastLineNum;
- if( jumpY )
- {
- this.moveY( jumpY );
- }
+ if( jumpY ) this.moveY( jumpY );
pline = this.getLine();
@@ -163,6 +162,50 @@
this.moveX( - Number.MAX_VALUE, false, false, true );
this.moveX( jumpX, false, phantomSpace, skipTabs );
+
+ this.__unsuppressUpdate();
+ };
+
+ // A line-only variant of moveTo, de-generalized for the sake of performance
+ Cursor.prototype.gotoLine = function( n )
+ {
+ this.__suppressUpdate();
+
+ var content = this.feeder.content;
+ var pline = this.getLine();
+ var lastLineNum = pline.lineNum;
+
+ if( pline.placeholder )
+ {
+ lastLineNum = 0;
+ this.Y = 0;
+ }
+
+ var expLineNum = 0;
+ var lineStart = 0;
+ for( var i = content.indexOf( "\n" ); 0 <= i ; i = content.indexOf( "\n", i ) )
+ {
+ if( expLineNum == n ) break;
+ lineStart = i;
+ i ++;
+ expLineNum ++;
+ }
+
+ if( expLineNum < n ) n = expLineNum;
+
+ var jumpY = expLineNum - lastLineNum;
+ if( jumpY ) this.moveY( jumpY );
+
+ pline = this.getLine();
+
+ if( pline.lineNum != expLineNum )
+ {
+ this.moveY( expLineNum - pline.lineNum );
+ }
+
+ this.lineStart( true );
+
+ this.__unsuppressUpdate();
};
// 0 will be treated as default ( 1 )
@@ -323,7 +366,7 @@
else if( c == "\n" )
{
x += d;
- }
+ }
// Wordwrap phantomSpace movement compensation on max filled lines
if( feeder.wrap && boundary && !hasPhantomSpace && phantomSpace )
@@ -369,10 +412,12 @@
this.moveX( Number.MAX_VALUE, false, phantomSpace, true );
};
+ // Because LineOffset is costly, suppress unnecessary calls
Cursor.prototype.updatePosition = function()
{
- var feeder = this.feeder;
- var P = this.X + LineOffset( feeder.lineBuffers, this.Y ) + this.__off;
+ if( 0 < this.__suppUpdate ) return;
+
+ var P = this.X + LineOffset( this.feeder.lineBuffers, this.Y ) + this.__off;
this.PStart = P;
this.PEnd = P + 1;
@@ -538,6 +583,13 @@
Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; };
Cursor.prototype.unsuppressEvent = function() { -- this.__suppEvt; };
+ Cursor.prototype.__suppressUpdate = function() { ++ this.__suppUpdate; };
+ Cursor.prototype.__unsuppressUpdate = function()
+ {
+ -- this.__suppUpdate;
+ this.updatePosition();
+ };
+
Cursor.prototype.getLine = function( display )
{
var feeder = this.feeder;
@@ -568,20 +620,7 @@
__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 );
+ return this.feeder.line( this.getLine().lineNum - 1 );
} );
// The position offset relative to current line
diff --git a/botanjs/src/Components/Vim/LineFeeder.js b/botanjs/src/Components/Vim/LineFeeder.js
index 4098773..b939daf 100644
--- a/botanjs/src/Components/Vim/LineFeeder.js
+++ b/botanjs/src/Components/Vim/LineFeeder.js
@@ -10,6 +10,7 @@
var Cursor = ns[ NS_INVOKE ]( "Cursor" );
var occurence = __import( "System.utils.Perf.CountSubstr" );
+ var C_LINE = 0;
var Feeder = function( rows, cols )
{
@@ -35,6 +36,7 @@
this.cursor = new Cursor( this );
this.dispatcher = new EventDispatcher();
+ this.__lineCache = [];
this.__clseLine = null;
this.__moreAt = -1;
this.__rows = rows;
@@ -42,7 +44,7 @@
Feeder.prototype.init = function( content, wrap )
{
- this.content = content;
+ this.__content = content;
this.setWrap( wrap );
this.firstBuffer.Push( content, this.wrap, 0 );
@@ -142,7 +144,7 @@
if( Y < 0 ) Y = 0;
// Compensate the last "\n" content placeholder
- var cont = this.content.slice( 0, -1 );
+ var cont = this.__content.slice( 0, -1 );
if( 0 < Y )
{
f = cont.indexOf( "\n" );
@@ -158,7 +160,7 @@
}
}
- this.firstBuffer.Push( this.content.substr( f + 1 ), this.wrap, i );
+ this.firstBuffer.Push( this.__content.substr( f + 1 ), this.wrap, i );
this.panX = X;
this.panY = Y;
@@ -171,8 +173,27 @@
this.__softRender();
};
+ Feeder.prototype.line = function( n )
+ {
+ if( this.__lineCache[ n ] )
+ return this.__lineCache[ n ];
+ var str = this.__content;
+ var i = str.indexOf( "\n" ), j = 0;
+
+ for( ; 0 <= i; i = str.indexOf( "\n", i ), j ++ )
+ {
+ if( n == j ) break;
+ i ++;
+ }
+
+ if( j == 0 && i == -1 ) i = 0;
+
+ var end = str.indexOf( "\n", i + 1 );
+ return ( this.__lineCache[ n ] = str.substring( i + 1, end ) );
+ };
+
__readOnly( Feeder.prototype, "linesTotal", function() {
- return occurence( this.content, "\n" );
+ return occurence( this.__content, "\n" );
} );
__readOnly( Feeder.prototype, "firstBuffer", function() {
@@ -216,7 +237,7 @@
var i = l - X;
do
{
- if( this.content[ i + 1 ] == "\t" ) tabs ++;
+ if( this.__content[ i + 1 ] == "\t" ) tabs ++;
i ++;
}
while( i < l )
@@ -254,6 +275,15 @@
return pos;
} );
+ Object.defineProperty( Feeder.prototype, "content", {
+ get: function() { return this.__content; }
+ , set: function( v )
+ {
+ this.__lineCache = [];
+ this.__content = v;
+ }
+ } );
+
__readOnly( Feeder.prototype, "linesOccupied", function() {
var line = this.firstBuffer;
if( line.placeholder ) return 0;
diff --git a/botanjs/src/Components/Vim/State/Marks.js b/botanjs/src/Components/Vim/State/Marks.js
new file mode 100644
index 0000000..102af97
--- /dev/null
+++ b/botanjs/src/Components/Vim/State/Marks.js
@@ -0,0 +1,31 @@
+(function(){
+ var ns = __namespace( "Components.Vim.State" );
+
+ /** @type {System.Debug} */
+ var debug = __import( "System.Debug" );
+
+ var Keys = "'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy\"[]^.<>";
+
+ var Marks = function()
+ {
+ this.__marks = {};
+ };
+
+ Marks.prototype.set = function( t, line, col )
+ {
+ if( Keys.indexOf( t ) == -1 ) return false;
+
+ this.__marks[ t ] = [ line, col ];
+ return true;
+ };
+
+ Marks.prototype.get = function( t )
+ {
+ return this.__marks[ t ];
+ };
+
+ __readOnly( Marks, "Keys", function() { return Keys; } );
+
+ ns[ NS_EXPORT ]( EX_CLASS, "Marks", Marks );
+
+})();
diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js
index 27e5874..8986ce6 100644
--- a/botanjs/src/Components/Vim/VimArea.js
+++ b/botanjs/src/Components/Vim/VimArea.js
@@ -14,6 +14,8 @@
/** @type {Components.Vim.State.Registers} */
var Registers = __import( "Components.Vim.State.Registers" );
+ /** @type {Components.Vim.State.Marks} */
+ var Marks = __import( "Components.Vim.State.Marks" );
/** @type {Components.Vim.Syntax.Analyzer} */
var SyntaxAnalyzer = __import( "Components.Vim.Syntax.Analyzer" );
@@ -243,6 +245,7 @@
this.statusFeeder = sfeeder;
this.statusBar = statusBar;
this.registers = new Registers();
+ this.marks = new Marks();
this.__cursor = cfeeder.cursor;
diff --git a/botanjs/src/externs/Components.Vim.Cursor.js b/botanjs/src/externs/Components.Vim.Cursor.js
index 2b60b30..634cd47 100644
--- a/botanjs/src/externs/Components.Vim.Cursor.js
+++ b/botanjs/src/externs/Components.Vim.Cursor.js
@@ -13,6 +13,8 @@ Components.Vim.Cursor.rec;
/** @type Function */
Components.Vim.Cursor.moveTo;
/** @type Function */
+Components.Vim.Cursor.gotoLine;
+/** @type Function */
Components.Vim.Cursor.moveX;
/** @type Function */
Components.Vim.Cursor.moveY;
diff --git a/botanjs/src/externs/Components.Vim.LineFeeder.js b/botanjs/src/externs/Components.Vim.LineFeeder.js
index eb500db..5edec59 100644
--- a/botanjs/src/externs/Components.Vim.LineFeeder.js
+++ b/botanjs/src/externs/Components.Vim.LineFeeder.js
@@ -43,6 +43,8 @@ Components.Vim.LineFeeder.linesOccupied;
/** @type String */
Components.Vim.LineFeeder.docPos;
/** @type String */
+Components.Vim.LineFeeder.line;
+/** @type String */
Components.Vim.LineFeeder.lineStat;
/** @type {String} */
Components.Vim.LineFeeder.content;
diff --git a/botanjs/src/externs/Components.Vim.State.Marks.js b/botanjs/src/externs/Components.Vim.State.Marks.js
new file mode 100644
index 0000000..99a4ade
--- /dev/null
+++ b/botanjs/src/externs/Components.Vim.State.Marks.js
@@ -0,0 +1,10 @@
+/** @constructor */
+Components.Vim.State.Marks = function(){};
+
+/** @type Function */
+Components.Vim.State.Marks.set;
+/** @type Function */
+Components.Vim.State.Marks.get;
+
+/** @type String */
+Components.Vim.State.Marks.Keys;
diff --git a/botanjs/src/externs/Components.Vim.VimArea.js b/botanjs/src/externs/Components.Vim.VimArea.js
index 756c6c3..a2286d1 100644
--- a/botanjs/src/externs/Components.Vim.VimArea.js
+++ b/botanjs/src/externs/Components.Vim.VimArea.js
@@ -12,6 +12,11 @@ Components.Vim.VimArea.statusFeeder;
/** @type {Components.Vim.StatusBar} */
Components.Vim.VimArea.statusBar;
+/** @type {Components.Vim.State.Registers} */
+Components.Vim.VimArea.registers;
+/** @type {Components.Vim.State.Marks} */
+Components.Vim.VimArea.marks;
+
/** @type Function */
Components.Vim.VimArea.demo;
/** @type Function */