forked from Botanical/BotanJS
Fix wrong position of lines with tab character
This commit is contained in:
parent
5be04d850d
commit
bc3c511c6f
@ -1,10 +1,11 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Components.Vim.Actions" );
|
||||
|
||||
/** @type {System.Debug} */
|
||||
var debug = __import( "System.Debug" );
|
||||
var Mesg = __import( "Components.Vim.Message" );
|
||||
|
||||
/** @type {Components.Vim.State.Stack} */
|
||||
var Stack = __import( "Components.Vim.State.Stack" );
|
||||
|
||||
var Translate = function( c )
|
||||
{
|
||||
switch( c )
|
||||
@ -16,15 +17,75 @@
|
||||
}
|
||||
};
|
||||
|
||||
/* @param {Components.Vim.LineFeeder} */
|
||||
var ContentPosition = function( f )
|
||||
{
|
||||
var line = f.cursor.getLine();
|
||||
var n = line.lineNum;
|
||||
|
||||
var p = 0;
|
||||
if( 0 < n )
|
||||
{
|
||||
p = f.content.indexOf( "\n" );
|
||||
for( i = 1; p != -1 && i < n; i ++ )
|
||||
{
|
||||
p = f.content.indexOf( "\n", p + 1 );
|
||||
}
|
||||
|
||||
if( f.wrap )
|
||||
{
|
||||
// wordwrap offset
|
||||
p ++;
|
||||
}
|
||||
}
|
||||
|
||||
p += f.cursor.aX;
|
||||
return p;
|
||||
};
|
||||
|
||||
/** @type {Components.Vim.Cursor.IAction} */
|
||||
var INSERT = function( Cursor )
|
||||
{
|
||||
/** @type {Components.Vim.Cursor} */
|
||||
this.cursor = Cursor;
|
||||
this.__cursor = Cursor;
|
||||
|
||||
// Initialize this stack
|
||||
this.__rec( "", true );
|
||||
};
|
||||
|
||||
INSERT.prototype.dispose = function()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
INSERT.prototype.__storeState = function( c, pos )
|
||||
{
|
||||
return function() {
|
||||
debug.Inf( pos, c );
|
||||
};
|
||||
};
|
||||
|
||||
INSERT.prototype.__rec = function( c, newRec )
|
||||
{
|
||||
if( newRec || !this.__stack )
|
||||
{
|
||||
if( this.__stack )
|
||||
{
|
||||
var c = this.__content;
|
||||
|
||||
this.__stack.store(
|
||||
this.__storeState( c, this.__startPosition )
|
||||
);
|
||||
|
||||
this.__cursor.rec.store( this.__stack );
|
||||
}
|
||||
|
||||
this.__content = "";
|
||||
this.__stack = new Stack();
|
||||
this.__startPosition = ContentPosition( this.__cursor.feeder );
|
||||
}
|
||||
|
||||
this.__content += c;
|
||||
};
|
||||
|
||||
INSERT.prototype.handler = function( e )
|
||||
@ -34,42 +95,27 @@
|
||||
|
||||
if( inputChar.length != 1 ) return;
|
||||
|
||||
var cur = this.cursor;
|
||||
var cur = this.__cursor;
|
||||
var feeder = cur.feeder;
|
||||
|
||||
var line = cur.getLine();
|
||||
var n = line.lineNum;
|
||||
var f = ContentPosition( feeder );
|
||||
|
||||
var cont = feeder.content;
|
||||
feeder.content =
|
||||
feeder.content.substring( 0, f )
|
||||
+ inputChar
|
||||
+ feeder.content.substring( f );
|
||||
|
||||
var f = 0;
|
||||
if( 0 < n )
|
||||
{
|
||||
f = cont.indexOf( "\n" );
|
||||
for( i = 1; f != -1 && i < n; i ++ )
|
||||
{
|
||||
f = cont.indexOf( "\n", f + 1 );
|
||||
}
|
||||
|
||||
if( this.cursor.feeder.wrap )
|
||||
{
|
||||
// wordwrap offset
|
||||
f ++;
|
||||
}
|
||||
}
|
||||
|
||||
f += cur.aX;
|
||||
|
||||
feeder.content = cont.substring( 0, f ) + inputChar + cont.substring( f );
|
||||
feeder.pan();
|
||||
feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
|
||||
|
||||
this.__rec( inputChar );
|
||||
|
||||
cur.moveX( 1 );
|
||||
};
|
||||
|
||||
INSERT.prototype.getMessage = function()
|
||||
{
|
||||
var l = this.cursor.feeder.firstBuffer.cols;
|
||||
var l = this.__cursor.feeder.firstBuffer.cols;
|
||||
var msg = Mesg( "INSERT" );
|
||||
|
||||
for( var i = msg.length; i < l; i ++ ) msg += " ";
|
||||
|
41
botanjs/src/Components/Vim/Actions/UNDO.js
Normal file
41
botanjs/src/Components/Vim/Actions/UNDO.js
Normal file
@ -0,0 +1,41 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Components.Vim.Actions" );
|
||||
|
||||
var Mesg = __import( "Components.Vim.Message" );
|
||||
|
||||
/** @type {Components.Vim.Cursor.IAction} */
|
||||
var UNDO = function( Cursor )
|
||||
{
|
||||
/** @type {Components.Vim.Cursor} */
|
||||
this.__cursor = Cursor;
|
||||
this.__message = "UNDO COMMAND";
|
||||
};
|
||||
|
||||
UNDO.prototype.dispose = function()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
UNDO.prototype.handler = function( e )
|
||||
{
|
||||
e.preventDefault();
|
||||
|
||||
/** @type {Components.Vim.State.Stack} */
|
||||
var stack = this.__cursor.rec.undo();
|
||||
if( stack )
|
||||
{
|
||||
stack.play();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.__message = Mesg( "UNDO_LIMIT" );
|
||||
}
|
||||
};
|
||||
|
||||
UNDO.prototype.getMessage = function()
|
||||
{
|
||||
return this.__message;
|
||||
};
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "UNDO", UNDO );
|
||||
})();
|
@ -62,10 +62,18 @@
|
||||
case 65: // a
|
||||
cfeeder.cursor.openAction( "INSERT" );
|
||||
break;
|
||||
|
||||
case 73: // i
|
||||
break;
|
||||
case 85: // u, undo
|
||||
cfeeder.cursor.openRunAction( "UNDO", e );
|
||||
break;
|
||||
case 88: // x, del
|
||||
break;
|
||||
case 1065: // A, append at the line end
|
||||
break;
|
||||
case 73: // i
|
||||
case 1088: // X, delete before
|
||||
break;
|
||||
case 1085: // U, undo previous changes in oneline
|
||||
break;
|
||||
case 1073: // I, append before the line start, after spaces
|
||||
break;
|
||||
|
@ -4,6 +4,9 @@
|
||||
/** @type {System.Debug} */
|
||||
var debug = __import( "System.Debug" );
|
||||
|
||||
/** @type {Components.Vim.State.Recorder} */
|
||||
var Recorder = __import( "Components.Vim.State.Recorder" );
|
||||
|
||||
var Actions = __import( "Components.Vim.Actions.*" );
|
||||
|
||||
var GetLine = function( buffs, l )
|
||||
@ -71,6 +74,9 @@
|
||||
// The resulting position
|
||||
this.P = 0;
|
||||
|
||||
// State recorder
|
||||
this.rec = new Recorder();
|
||||
|
||||
this.action = null;
|
||||
};
|
||||
|
||||
@ -210,6 +216,7 @@
|
||||
{
|
||||
if( this.action ) this.action.dispose();
|
||||
this.action = new (Actions[ name ])( this );
|
||||
this.__pulseMsg = null;
|
||||
|
||||
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
|
||||
};
|
||||
@ -219,6 +226,18 @@
|
||||
if( !this.action ) return;
|
||||
this.action.dispose();
|
||||
this.action = null;
|
||||
this.__pulseMsg = null;
|
||||
|
||||
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
|
||||
};
|
||||
|
||||
Cursor.prototype.openRunAction = function( name, e )
|
||||
{
|
||||
/** @type {Components.Vim.IAction} */
|
||||
var action = new (Actions[ name ])( this );
|
||||
action.handler( e );
|
||||
this.__pulseMsg = action.getMessage();
|
||||
action.dispose();
|
||||
|
||||
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
|
||||
};
|
||||
@ -244,23 +263,52 @@
|
||||
var X = this.X;
|
||||
var f = this.feeder;
|
||||
|
||||
var w = 1;
|
||||
|
||||
// Calculate wordwrap offset
|
||||
if( f.wrap )
|
||||
{
|
||||
var cols = f.firstBuffer.cols + 1;
|
||||
var w = X < cols ? 0 : Math.floor( X / cols );
|
||||
var lines = this.getLine().visualLines;
|
||||
|
||||
if( 0 < w )
|
||||
for( var i in lines )
|
||||
{
|
||||
X -= w;
|
||||
/** @type {Components.Vim.LineBuffer} */
|
||||
var vline = lines[ i ];
|
||||
|
||||
// Actual length
|
||||
var aLen = vline.content.toString().length;
|
||||
|
||||
// Visual length
|
||||
var vLen = vline.toString().length;
|
||||
|
||||
// Plus the "\n" character
|
||||
X -= vLen + 1;
|
||||
|
||||
if( 0 <= X )
|
||||
{
|
||||
w += aLen;
|
||||
}
|
||||
else if( X < 0 )
|
||||
{
|
||||
w += X + vLen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return X;
|
||||
return w;
|
||||
} );
|
||||
|
||||
__readOnly( Cursor.prototype, "message", function()
|
||||
{
|
||||
if( this.__pulseMsg )
|
||||
{
|
||||
var m = this.__pulseMsg;
|
||||
this.__pulseMsg = null;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
return this.action && this.action.getMessage();
|
||||
} );
|
||||
|
||||
|
@ -195,7 +195,7 @@
|
||||
} );
|
||||
|
||||
__readOnly( Feeder.prototype, "lineStat", function() {
|
||||
var X = this.cursor.aX;
|
||||
var X = this.cursor.aX + 1;
|
||||
var line = this.cursor.getLine();
|
||||
var tabStat = "";
|
||||
|
||||
|
41
botanjs/src/Components/Vim/State/Recorder.js
Normal file
41
botanjs/src/Components/Vim/State/Recorder.js
Normal file
@ -0,0 +1,41 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Components.Vim.State" );
|
||||
|
||||
var Recorder = function()
|
||||
{
|
||||
this.__steps = [];
|
||||
this.__i = 0;
|
||||
};
|
||||
|
||||
Recorder.prototype.undo = function()
|
||||
{
|
||||
var i = this.__i - 1;
|
||||
if( i == -1 || !this.__steps.length ) return null;
|
||||
|
||||
|
||||
return this.__steps[ this.__i = i ];
|
||||
};
|
||||
|
||||
Recorder.prototype.redo = function()
|
||||
{
|
||||
var i = this.__i + 1;
|
||||
if( i == -1 || !this.__steps.length ) return null;
|
||||
|
||||
var State = this.__steps[ i ];
|
||||
if( State )
|
||||
{
|
||||
this.__i = i;
|
||||
return State;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Recorder.prototype.record = function( StateObj )
|
||||
{
|
||||
this.__steps[ this.__i ] = StateObj;
|
||||
delete this.__steps[ ++ this.__i ];
|
||||
};
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Recorder", Recorder );
|
||||
})();
|
19
botanjs/src/Components/Vim/State/Stack.js
Normal file
19
botanjs/src/Components/Vim/State/Stack.js
Normal file
@ -0,0 +1,19 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Components.Vim.State" );
|
||||
|
||||
var Stack = function()
|
||||
{
|
||||
};
|
||||
|
||||
Stack.prototype.store = function( handler )
|
||||
{
|
||||
this.__handler = handler;
|
||||
};
|
||||
|
||||
Stack.prototype.play = function()
|
||||
{
|
||||
if( this.__handler ) this.__handler();
|
||||
};
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Stack", Stack );
|
||||
})();
|
@ -32,7 +32,7 @@
|
||||
if( text == undefined || text === "" ) continue;
|
||||
|
||||
display += text.substr( 0, avail );
|
||||
i = display.length - 1;
|
||||
i = display.length;
|
||||
}
|
||||
else display += " ";
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
, "BOTTOM": "Bot"
|
||||
, "ALL": "All"
|
||||
, "EXIT": "Type :quit<Enter> to exit Vim"
|
||||
|
||||
, "UNDO_LIMIT": "Already at oldest change"
|
||||
};
|
||||
|
||||
var errors = {
|
||||
|
@ -5,6 +5,8 @@ Components.Vim.Cursor = function(){};
|
||||
Components.Vim.Cursor.feeder;
|
||||
/** @type {Components.Vim.IAction} */
|
||||
Components.Vim.Cursor.action;
|
||||
/** @type {Components.Vim.State.Recorder} */
|
||||
Components.Vim.Cursor.rec;
|
||||
|
||||
/** @type Function */
|
||||
Components.Vim.Cursor.moveX;
|
||||
@ -19,6 +21,8 @@ Components.Vim.Cursor.updatePosition;
|
||||
/** @type Function */
|
||||
Components.Vim.Cursor.openAction;
|
||||
/** @type Function */
|
||||
Components.Vim.Cursor.openRunAction;
|
||||
/** @type Function */
|
||||
Components.Vim.Cursor.closeAction;
|
||||
|
||||
/** @type {Array} */
|
||||
|
9
botanjs/src/externs/Components.Vim.State.Recorder.js
Normal file
9
botanjs/src/externs/Components.Vim.State.Recorder.js
Normal file
@ -0,0 +1,9 @@
|
||||
/** @constructor */
|
||||
Components.Vim.State.Recorder = function(){};
|
||||
|
||||
/** @type Function */
|
||||
Components.Vim.State.undo;
|
||||
/** @type Function */
|
||||
Components.Vim.State.redo;
|
||||
/** @type Function */
|
||||
Components.Vim.State.record;
|
7
botanjs/src/externs/Components.Vim.State.Stack.js
Normal file
7
botanjs/src/externs/Components.Vim.State.Stack.js
Normal file
@ -0,0 +1,7 @@
|
||||
/** @constructor */
|
||||
Components.Vim.State.Stack = function(){};
|
||||
|
||||
/** @type Function */
|
||||
Components.Vim.State.Stack.play;
|
||||
/** @type Function */
|
||||
Components.Vim.State.Stack.store;
|
2
botanjs/src/externs/Components.Vim.State.js
Normal file
2
botanjs/src/externs/Components.Vim.State.js
Normal file
@ -0,0 +1,2 @@
|
||||
/** @object */
|
||||
Components.Vim.State = {};
|
Loading…
Reference in New Issue
Block a user