AstroJS/botanjs/src/Components/Vim/Actions/SHIFT_LINES.js

243 lines
4.8 KiB
JavaScript

(function(){
var ns = __namespace( "Components.Vim.Actions" );
/** @type {System.Debug} */
var debug = __import( "System.Debug" );
var beep = __import( "Components.Vim.Beep" );
/** @type {Components.Vim.State.Stack} */
var Stack = __import( "Components.Vim.State.Stack" );
var VimError = __import( "Components.Vim.Error" );
var Mesg = __import( "Components.Vim.Message" );
var occurence = __import( "System.utils.Perf.CountSubstr" );
var REPL_BEFORE = 0;
var REPL_OFFSET = 1;
var REPL_LENGTH = 2;
/** @type {Components.Vim.IAction}
* Cursor @param {Components.Vim.Cursor}
* e @param {Components.Vim.ActionEvent}
**/
var SHIFT_LINES = function( Cursor, e )
{
/** @type {Components.Vim.Cursor} */
this.__cursor = Cursor;
this.__startX = Cursor.aPos;
this.__msg = "<LINE_SHIFT>";
this.__slineNum = Cursor.getLine().lineNum;
this.__lines = e.count;
debug.Info( "Open shift: " + this.__lines + " line(s) below the cursor" );
this.__direction = e.kMap( ">" ) ? 1 : -1;
debug.Info( "Direction is: " + ( this.__direction == 1 ? ">" : "<" ) );
Cursor.suppressEvent();
};
SHIFT_LINES.prototype.allowMovement = true;
SHIFT_LINES.prototype.dispose = function()
{
this.__cursor.unsuppressEvent();
};
SHIFT_LINES.prototype.handler = function( e, sp )
{
e.preventDefault();
if( e.ModKeys || e.kMap( "i" ) ) return;
var cur = this.__cursor;
var feeder = cur.feeder;
var Triggered = false;
var dir = this.__direction;
var start = this.__slineNum;
var nline = this.__lines;
if( 1 < e.count )
{
nline += e.count;
}
var end = start;
var shiftCount = 1;
if( sp == undefined )
{
Triggered = true;
sp = this.__startX;
var currAp = cur.aPos;
if( this.__startX != currAp )
{
if( e.kMap( "h" ) || e.kMap( "l" ) ){}
else if( e.kMap( "j" ) )
{
end = start + nline;
}
else if( e.kMap( "k" ) )
{
start -= nline;
}
else // TODO: Dectect movement line count
{
}
}
else
{
if( !( ( 0 < dir && ( e.kMap( ">" ) || e.kMap( "l" ) ) )
|| ( dir < 0 && ( e.kMap( "<" ) || e.kMap( "h" ) ) )
) )
{
beep();
return true;
}
}
}
// last "\n" padding
var c = feeder.content.slice( 0, -1 );
var indents = c.match( /^[\t ]+/gm );
var indentChar = "\t";
var tabwidth = feeder.firstBuffer.tabWidth;
if( indents )
{
var l = indents.length - 1;
if( 1 < l )
{
debug.Info( "Guessing the tabstop:" );
var tabOccr = 0;
var spOccr = 0;
// Guess indent
var tabStat = {};
for( var i = 0; i < l; i ++ )
{
var ind = indents[ i ];
var indNext = indents[ i + 1 ];
tabOccr += occurence( ind, "\t" );
spOccr += occurence( ind, " " );
var d = indNext.length - ind.length;
if( d == 0 ) continue;
d = d < 0 ? -d : d;
if( !tabStat[ d ] ) tabStat[ d ] = 0;
tabStat[ d ] ++;
}
var upperDiff = 0;
var indentCLen = 0;
for( var i in tabStat )
{
var p = tabStat[ i ];
if( upperDiff < p )
{
upperDiff = p;
indentCLen = i;
}
}
spOccr /= indentCLen;
if( tabOccr < spOccr )
{
indentChar = "";
for( var i = 0; i < indentCLen; i ++ ) indentChar += " ";
}
tabwidth = indentCLen;
debug.Info( "\tTab count: " + tabOccr );
debug.Info( "\tSpace count: " + spOccr );
debug.Info( "\ti.e. indent using " + JSON.stringify( indentChar ) );
}
else
{
debug.Info( "Not enough tabs to determine the tabstop, using default" );
}
}
debug.Info( "Start: " + start, "End: " + end );
var rBlock = "";
var started = false;
var indentTimes = 1;
feeder.content = "";
nline = 0;
for( var i = 0, j = 0; 0 <= i; i = c.indexOf( "\n", i ), j ++ )
{
i ++;
if( j < start ) continue;
else if( !started )
{
started = true;
feeder.content = c.substring( 0, i - 1 );
}
if( end < j ) break;
var line = c.substring( 1 < i ? i : i - 1, c.indexOf( "\n", i ) );
if( 1 < i ) feeder.content += "\n";
if( line !== "" )
{
if( 0 < dir )
{
feeder.content += indentChar + line;
}
else
{
for( var si = 0, sj = 1; si < indentTimes; si ++ )
{
var startC = line[ si ];
if( startC == " " )
{
for( ; sj < tabwidth; sj ++ )
{
if( !~"\t ".indexOf( line[ si + sj ] ) ) break;
}
}
else if( startC != "\t" ) break;
}
feeder.content += line.substring( si + sj - 1 );
}
nline ++;
}
}
feeder.content += "\n" + c.substring( i ) + "\n";
feeder.pan();
this.__msg = Mesg( "LINES_SHIFTED", nline, dir < 0 ? "<" : ">", 1 );
return Triggered;
};
SHIFT_LINES.prototype.getMessage = function()
{
return this.__msg;
};
ns[ NS_EXPORT ]( EX_CLASS, "SHIFT_LINES", SHIFT_LINES );
})();