forked from Botanical/BotanJS
298 lines
5.9 KiB
JavaScript
298 lines
5.9 KiB
JavaScript
(function(){
|
|
var ns = __namespace( "Components.Vim.Actions" );
|
|
|
|
/** @type {Components.Vim.State.Stack} */
|
|
var Stack = __import( "Components.Vim.State.Stack" );
|
|
/** @type {Components.Vim.State.Stator} */
|
|
var Stator = __import( "Components.Vim.State.Stator" );
|
|
/** @type {System.Debug} */
|
|
var debug = __import( "System.Debug" );
|
|
|
|
var Mesg = __import( "Components.Vim.Message" );
|
|
|
|
// Phantom indent
|
|
var IN_START = 0;
|
|
var IN_END = 1;
|
|
var IN_DEL = 2;
|
|
|
|
var Translate = function( c )
|
|
{
|
|
switch( c )
|
|
{
|
|
case "Tab":
|
|
return "\t";
|
|
case "Enter":
|
|
return "\n";
|
|
default:
|
|
return c;
|
|
}
|
|
};
|
|
|
|
/** @type {Components.Vim.IAction} */
|
|
var INSERT = function( Cursor )
|
|
{
|
|
/** @type {Components.Vim.Cursor} */
|
|
this.__cursor = Cursor;
|
|
|
|
this.__stator = new Stator( Cursor );
|
|
this.__minReach = 0;
|
|
this.__insertLen = 0;
|
|
|
|
// Initialize this stack
|
|
this.__rec( "", true );
|
|
|
|
var l = this.__cursor.feeder.firstBuffer.cols;
|
|
var msg = Mesg( "INSERT" );
|
|
|
|
for( var i = msg.length; i < l; i ++ ) msg += " ";
|
|
this.__msg = msg;
|
|
};
|
|
|
|
INSERT.prototype.allowMovement = false;
|
|
|
|
INSERT.prototype.dispose = function()
|
|
{
|
|
if( this.__cancelIndent() )
|
|
{
|
|
this.__cursor.feeder.pan();
|
|
}
|
|
this.__msg = "";
|
|
this.__rec( "", true );
|
|
this.__cursor.moveX( -1 );
|
|
};
|
|
|
|
INSERT.prototype.__rec = function( c, newRec )
|
|
{
|
|
if( newRec || !this.__stack )
|
|
{
|
|
if( this.__stack )
|
|
{
|
|
// If nothings changed
|
|
if( this.__minReach == 0
|
|
&& this.__punch == 0
|
|
&& this.__contentUndo === ""
|
|
) return;
|
|
|
|
if( this.__punch < this.__minReach )
|
|
{
|
|
this.__minReach = this.__punch;
|
|
}
|
|
|
|
this.__stack.store(
|
|
this.__stator.save(
|
|
this.__insertLen
|
|
, this.__contentUndo
|
|
, -this.__minReach )
|
|
);
|
|
|
|
this.__cursor.rec.record( this.__stack );
|
|
}
|
|
|
|
this.__punch = 0;
|
|
this.__contentUndo = "";
|
|
this.__stack = new Stack();
|
|
}
|
|
|
|
if( c == "\n" )
|
|
{
|
|
// todo
|
|
}
|
|
|
|
if( this.__punch < this.__minReach )
|
|
{
|
|
this.__insertLen = 0;
|
|
this.__minReach = this.__punch;
|
|
}
|
|
|
|
this.__punch += c.length;
|
|
this.__insertLen += c.length;
|
|
};
|
|
|
|
INSERT.prototype.__specialKey = function( e, inputChar )
|
|
{
|
|
var cur = this.__cursor;
|
|
var feeder = cur.feeder;
|
|
|
|
// Backspace
|
|
if( e.kMap( "BS" ) || e.kMap( "S-BS" ) )
|
|
{
|
|
this.__realizeIndent();
|
|
var oY = feeder.panY + cur.Y;
|
|
if( cur.X == 0 && feeder.panY == 0 && cur.Y == 0 ) return;
|
|
|
|
var f = cur.aPos - 1;
|
|
|
|
if( this.__punch <= this.__minReach )
|
|
{
|
|
this.__contentUndo = feeder.content.substr( f, 1 ) + this.__contentUndo;
|
|
}
|
|
|
|
feeder.content =
|
|
feeder.content.substring( 0, f )
|
|
+ feeder.content.substring( f + 1 );
|
|
|
|
feeder.pan();
|
|
|
|
cur.moveX( -1, true, true );
|
|
|
|
if( 0 < this.__insertLen ) this.__insertLen --;
|
|
this.__punch --;
|
|
}
|
|
else if( e.kMap( "Del" ) || e.kMap( "S-Del" ) )
|
|
{
|
|
this.__realizeIndent();
|
|
var f = cur.aPos;
|
|
|
|
this.__contentUndo += feeder.content.substr( f, 1 );
|
|
|
|
feeder.content =
|
|
feeder.content.substring( 0, f )
|
|
+ feeder.content.substring( f + 1 );
|
|
|
|
feeder.pan();
|
|
}
|
|
else return;
|
|
|
|
feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
|
|
};
|
|
|
|
INSERT.prototype.handler = function( e )
|
|
{
|
|
e.preventDefault();
|
|
|
|
if( e.ModKeys ) return;
|
|
|
|
var inputChar = Translate( e.key );
|
|
|
|
if( inputChar.length != 1 )
|
|
{
|
|
this.__specialKey( e, inputChar );
|
|
return;
|
|
}
|
|
|
|
var cur = this.__cursor;
|
|
var feeder = cur.feeder;
|
|
|
|
var f = cur.aPos;
|
|
|
|
feeder.content =
|
|
feeder.content.substring( 0, f )
|
|
+ inputChar
|
|
+ feeder.content.substring( f );
|
|
|
|
if( inputChar == "\n" )
|
|
{
|
|
feeder.softReset();
|
|
feeder.pan();
|
|
cur.moveY( 1 );
|
|
cur.lineStart();
|
|
this.__autoIndent( e );
|
|
}
|
|
else
|
|
{
|
|
this.__realizeIndent();
|
|
feeder.pan();
|
|
cur.moveX( 1, false, true );
|
|
}
|
|
|
|
feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
|
|
|
|
this.__rec( inputChar );
|
|
};
|
|
|
|
INSERT.prototype.__realizeIndent = function()
|
|
{
|
|
var ind = this.__phantomIndent;
|
|
if( !this.__phantomIndent ) return;
|
|
|
|
debug.Info( "Realize Indentation: " + ind );
|
|
|
|
l = ind[ IN_END ];
|
|
for( var i = ind[ IN_START ]; i < l; i ++ )
|
|
{
|
|
this.__rec( this.__cursor.feeder.content[ i ] );
|
|
}
|
|
this.__contentUndo = ind[ IN_DEL ] + this.__contentUndo;
|
|
this.__phantomIndent = null;
|
|
};
|
|
|
|
INSERT.prototype.__autoIndent = function( e )
|
|
{
|
|
var carried = this.__cancelIndent();
|
|
|
|
var cur = this.__cursor;
|
|
var feeder = cur.feeder;
|
|
|
|
var f = cur.aPos;
|
|
|
|
// Get the last indent
|
|
var i = feeder.content.lastIndexOf( "\n", f - 2 );
|
|
var line = feeder.content.substring( i + 1, f - 1 ) || carried;
|
|
|
|
// Find Last indent
|
|
while( line == "" && 0 < i )
|
|
{
|
|
var j = i;
|
|
i = feeder.content.lastIndexOf( "\n", j - 2 );
|
|
line = feeder.content.substring( i + 1, j - 1 );
|
|
}
|
|
|
|
var inDel = "";
|
|
// Indent removed
|
|
for( var ir = f; "\t ".indexOf( feeder.content[ ir ] ) != -1; ir ++ )
|
|
{
|
|
inDel += feeder.content[ ir ];
|
|
}
|
|
|
|
// Copy the indentation
|
|
for( i = 0; "\t ".indexOf( line[i] ) != -1; i ++ );
|
|
|
|
if( line )
|
|
{
|
|
feeder.content =
|
|
feeder.content.substring( 0, f )
|
|
+ line.substr( 0, i )
|
|
+ feeder.content.substring( ir );
|
|
|
|
feeder.softReset();
|
|
feeder.pan();
|
|
cur.moveX( i, false, true );
|
|
|
|
var a = [];
|
|
a[ IN_START ] = f;
|
|
a[ IN_END ] = f + i;
|
|
a[ IN_DEL ] = inDel;
|
|
|
|
this.__phantomIndent = a;
|
|
debug.Info( "Phantom indent: " + a );
|
|
}
|
|
};
|
|
|
|
INSERT.prototype.__cancelIndent = function()
|
|
{
|
|
var ind = this.__phantomIndent;
|
|
if( !ind ) return "";
|
|
|
|
debug.Info( "Erase phantom indent: " + ind );
|
|
|
|
var cur = this.__cursor;
|
|
var feeder = cur.feeder;
|
|
|
|
var canceled = feeder.content.substring( ind[ IN_START ], ind[ IN_END ] );
|
|
feeder.content =
|
|
feeder.content.substring( 0, ind[ IN_START ] )
|
|
+ feeder.content.substring( ind[ IN_END ] );
|
|
|
|
this.__phantomIndent = null;
|
|
|
|
return canceled;
|
|
}
|
|
|
|
INSERT.prototype.getMessage = function()
|
|
{
|
|
return this.__msg;
|
|
};
|
|
|
|
ns[ NS_EXPORT ]( EX_CLASS, "INSERT", INSERT );
|
|
})();
|