AstroJS/botanjs/src/Components/Vim/VimArea.js
2016-03-30 04:32:36 +08:00

172 lines
4.4 KiB
JavaScript

(function(){
var ns = __namespace( "Components.Vim" );
/** @type {Dandelion.IDOMElement} */
var IDOMElement = __import( "Dandelion.IDOMElement" );
/** @type {System.utils.DataKey} */
var DataKey = __import( "System.utils.DataKey" );
/** @type {System.Cycle} */
var Cycle = __import( "System.Cycle" );
/** @type {System.Debug} */
var debug = __import( "System.Debug" );
/** @type {Components.Vim.State.Registers} */
var Registers = __import( "Components.Vim.State.Registers" );
/** @type {Components.Vim.Syntax.Analyzer} */
var SyntaxAnalyzer = __import( "Components.Vim.Syntax.Analyzer" );
/** @type {Components.Vim.LineFeeder} */
var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" );
/** @type {Components.Vim.StatusBar} */
var StatusBar = ns[ NS_INVOKE ]( "StatusBar" );
var VimControls = ns[ NS_INVOKE ]( "Controls" );
var InputEvent = ns[ NS_INVOKE ]( "InputEvent" );
var mesg = ns[ NS_INVOKE ]( "Message" );
var Insts = [];
var KeyHandler = function( sender, handler )
{
return function( e )
{
e = e || window.event;
if ( e.keyCode ) code = e.keyCode;
else if ( e.which ) code = e.which;
handler( sender, new InputEvent( sender, e ) );
};
};
/* stage @param {Dandelion.IDOMElement} */
var VimArea = function( stage )
{
if( !stage ) return;
var element = stage.element;
if( element.nodeName != "TEXTAREA" )
{
debug.Error( "Element is not compatible for VimArea" );
return;
}
stage.setAttribute( new DataKey( "vimarea", 1 ) );
this.stage = stage;
this.rows = element.rows;
this.cols = element.cols;
this.__active = false;
var _self = this;
stage.addEventListener( "Focus", function() { _self.__active = true; } );
stage.addEventListener( "Blur", function() { _self.__active = false; } );
// Init
this.VisualizeVimFrame( element.value );
// Push this instance
Insts.push( this );
};
VimArea.prototype.select = function( sel )
{
if( !this.__active ) return;
var textarea = this.stage.element;
if( sel )
{
textarea.selectionStart = sel.start;
textarea.selectionEnd = sel.end;
}
};
VimArea.prototype.VisualizeVimFrame = function( content )
{
var _self = this;
var element = this.stage.element;
var r = this.rows;
var c = this.cols;
// StatusFeeder always consumes at least 1 line
var cRange = r - 1;
// Content feeder
var cfeeder = new LineFeeder( cRange, c );
var contentAnalyzer = new SyntaxAnalyzer( cfeeder );
// Feed the contents to content feeder
// This "\n" fixes the last line "\n" not displaying
// it will be trimmed after saving
cfeeder.init( content + "\n" );
// Status can consumes up to full screen, I think
sfeeder = new LineFeeder( r, c );
sfeeder.setRender( false );
// Set the Vim instance
cfeeder.cursor.Vim = this;
sfeeder.cursor.Vim = this;
// Set the stamps
var statusBar = new StatusBar( c );
statusBar.stamp( -18, function(){ return cfeeder.lineStat; } );
statusBar.stamp( -3, function(){ return mesg( cfeeder.docPos ); } );
statusBar.stamp( 0, function(){ return cfeeder.cursor.message; } );
sfeeder.init( statusBar.statusText );
var Update = function()
{
sfeeder.init( statusBar.statusText );
element.value =
cfeeder.render( 0, r - sfeeder.linesOccupied )
+ "\n" + sfeeder.render();
_self.__blink = false;
_self.select( cfeeder.cursor.position );
};
cfeeder.dispatcher.addEventListener( "VisualUpdate", Update );
Update();
this.contentFeeder = cfeeder;
this.contentAnalyzer = contentAnalyzer;
this.statusFeeder = sfeeder;
this.statusBar = statusBar;
this.registers = new Registers();
this.__cursor = cfeeder.cursor;
this.__blink = true;
Cycle.perma( "VimCursorBlinkCycle" + element.id, function()
{
_self.select(
!_self.__cursor.blink || ( _self.__blink = !_self.__blink )
? _self.__cursor.position
: { start: 0, end: 0 }
);
}, 600 );
var controls = new VimControls( this );
this.stage.addEventListener(
"KeyDown"
, KeyHandler( this, controls.handler.bind( controls ) )
);
};
__readOnly( VimArea, "Instances", function() {
return Insts.slice();
} );
__readOnly( VimArea.prototype, "content", function() {
return this.contentFeeder.content.slice( 0, -1 );
} );
ns[ NS_EXPORT ]( EX_CLASS, "VimArea", VimArea );
})();