commit d6bbf245c682048aa723a38257b11c647600681f Author: 斟酌 鵬兄 Date: Sun Mar 13 03:30:33 2016 +0800 Some drafts diff --git a/botanjs/src/Components/Vim/LineFeeder.js b/botanjs/src/Components/Vim/LineFeeder.js new file mode 100644 index 0000000..ae8af80 --- /dev/null +++ b/botanjs/src/Components/Vim/LineFeeder.js @@ -0,0 +1,195 @@ +(function(){ + var ns = __namespace( "Components.Vim" ); + + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + /** @type {Dandelion.IDOMObject} */ + var IDOMObject = __import( "Dandelion.IDOMObject" ); + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + var Line = function( cols, nextLine ) + { + this.cols = cols; + this.next = nextLine; + this.br = false; + this.placeholder = true; + }; + + Line.prototype.Push = function( content, wrap ) + { + if( content == undefined || content === "" ) + { + this.content = "~"; + this.placeholder = true; + if( this.next ) this.next.Push( content, wrap ); + return; + } + + this.placeholder = false; + + var line = ""; + var br = false; + + if( wrap ) + { + for( var i = 0; i < this.cols; i ++ ) + { + var c = content[i]; + if( c === undefined ) break; + + if( c == "\n" ) + { + br = true; + i ++; + break; + } + + line += c; + } + } + else + { + br = true; + for( var i = 0; true; i ++ ) + { + var c = content[i]; + if( c === undefined ) break; + + if( c == "\n" ) + { + i ++; + break; + } + + if( i < this.cols ) + { + line += c; + } + } + } + + if( this.next ) + { + this.next.br = br; + this.next.Push( content.substr( i ), wrap ); + } + + this.content = line; + }; + + Line.prototype.toString = function() + { + return this.content; + }; + + var Feeder = function( rows, cols ) + { + var lines = []; + + // Last line + lines[ rows - 1 ] = new Line( cols ); + + for( var i = rows - 2; 0 <= i; i -- ) + { + lines[i] = new Line( cols, lines[ i + 1 ] ); + } + + this.lines = lines; + this.setRender(); + }; + + Feeder.prototype.init = function( content, wrap ) + { + if( wrap == undefined ) wrap = true; + if( this.lines.length ) + { + this.lines[0].Push( content, wrap ); + } + }; + + // Advance the text to number of lines + Feeder.prototype.feed = function( num ) + { + }; + + Feeder.prototype.wrap = function( setwrap ) + { + }; + + Feeder.prototype.setRender = function( placeholder ) + { + if( placeholder == undefined ) placeholder = true; + + if( placeholder ) + { + this.__render = function( line, steps ) + { + var display = ( line == undefined ? "" : line ) + ""; + + for( var i = 0; + line && i < steps && ( line = line.next ); + i ++ ) + { + display += "\n" + line; + } + + return display; + }; + } + else + { + this.__render = function( line, steps ) + { + var display = ( line == undefined ? "" : line ) + ""; + + for( var i = 0; + line && i < steps && ( line = line.next ) && !line.placeholder; + i ++ ) + { + display += "\n" + line; + } + + return display; + }; + } + } + + Feeder.prototype.cursor = function( direction ) + { + switch( direction ) + { + case 0: + return { start: 0, end: 1 }; + } + }; + + Feeder.prototype.render = function( start, length ) + { + if( start == undefined ) start = 0; + else if( this.lines.length < start ) return ""; + + if( length == undefined || ( this.lines.length - start ) < length ) + length = this.lines.length - start; + + if( length == 0 ) return ""; + + return this.__render( this.lines[ start ], length - 1 ); + }; + + __readOnly( Feeder.prototype, "linesOccupied", function() { + var line = this.lines[0]; + if( line.placeholder ) return 0; + + var i = 0; + do i ++; + while( ( line = line.next ) && !line.placeholder ); + return i; + } ); + + ns[ NS_EXPORT ]( EX_CLASS, "LineFeeder", Feeder ); +})(); diff --git a/botanjs/src/Components/Vim/StatusBar.js b/botanjs/src/Components/Vim/StatusBar.js new file mode 100644 index 0000000..9aa4535 --- /dev/null +++ b/botanjs/src/Components/Vim/StatusBar.js @@ -0,0 +1,50 @@ +(function(){ var ns = __namespace( "Components.Vim" ); + + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + /** @type {Dandelion.IDOMObject} */ + var IDOMObject = __import( "Dandelion.IDOMObject" ); + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + /** @type {Components.VimArea.LineFeeder} */ + var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" ); + + var StatusBar = function( cols ) + { + this.cols = cols; + this.statStamp = {}; + }; + + StatusBar.prototype.stamp = function( pos, func ) + { + this.statStamp[ pos ] = func; + }; + + __readOnly( StatusBar.prototype, "statusText", function() + { + var display = ""; + var l = this.cols; + + for( var i = 0; i < l; i ++ ) + { + var avail = l - i; + var text = this.statStamp[ i ] || this.statStamp[ - avail ]; + if( text ) + { + text = text(); + display += text.substr( 0, avail ); + i = display.length - 1; + } + else display += " "; + } + + return display; + } ); + + ns[ NS_EXPORT ]( EX_CLASS, "StatusBar", StatusBar ); +})(); diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js new file mode 100644 index 0000000..791f511 --- /dev/null +++ b/botanjs/src/Components/Vim/VimArea.js @@ -0,0 +1,163 @@ +(function(){ + var ns = __namespace( "Components.Vim" ); + + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + /** @type {Dandelion.IDOMObject} */ + var IDOMObject = __import( "Dandelion.IDOMObject" ); + /** @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.VimArea.LineFeeder} */ + var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" ); + var StatusBar = ns[ NS_INVOKE ]( "StatusBar" ); + + 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, e ); + }; + }; + + var VimControls = function( sender, e ) + { + e.preventDefault(); + if( e.ctrlKey ) + { + VimComboFunc( sender, e ); + return; + } + + var kCode = e.KeyCode + ( e.shiftKey ? 1000 : 0 ); + switch( e.KeyCode ) + { + case 65: // a + case 1065: // A + break; + case 72: // h + case 1072: // H + break; + case 74: // j + case 1074: // J + break; + case 75: // k + case 1075: // K + break; + case 76: // l + case 1076: // L + break; + case 1053: // % + case 1054: // ^ + break; + } + }; + + /* 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.PosX = 1; + this.PosY = 1; + + stage.addEventListener( "KeyDown", KeyHandler( this, VimControls ) ); + + // Init + this.content = element.value; + this.VisualizeVimFrame(); + }; + + VimArea.prototype.startInput = function( mode ) + { + + }; + + VimArea.prototype.cursor = function( x, y ) + { + return this.__cursor(); + }; + + VimArea.prototype.flashCursor = function() + { + var _self = this; + var textarea = this.stage.element; + Cycle.perma( "VimCursorFlashCycle", function() + { + var cursor = _self.cursor(); + if( cursor ) + { + textarea.selectionStart = cursor.start; + textarea.selectionEnd = cursor.end; + } + }, 600 ); + }; + + VimArea.prototype.VisualizeVimFrame = function() + { + var element = this.stage.element; + var r = this.rows; + var c = this.cols; + + // Content feeder + var cfeeder = new LineFeeder( r, c ); + + cfeeder.init( this.content ); + + // Status feeder + sfeeder = new LineFeeder( r, c ); + sfeeder.setRender( false ); + + var statusBar = new StatusBar( c ); + statusBar.stamp( -18, function(){ + return "1,1-1"; + }); + + statusBar.stamp( -3, function(){ + return "All"; + }); + + sfeeder.init( statusBar.statusText ); + + element.value = cfeeder.render( 0, r - sfeeder.linesOccupied ) + "\n" + sfeeder.render(); + + this.contentFeeder = cfeeder; + this.statusFeeder = sfeeder; + + var f = true; + this.__cursor = function() + { + if( f = !f ) + return this.contentFeeder.cursor( 0 ); + else return { start: 0, end: 0 }; + } + + this.flashCursor(); + }; + + ns[ NS_EXPORT ]( EX_CLASS, "VimArea", VimArea ); +})(); diff --git a/botanjs/src/Components/Vim/_this.css b/botanjs/src/Components/Vim/_this.css new file mode 100644 index 0000000..1716ca4 --- /dev/null +++ b/botanjs/src/Components/Vim/_this.css @@ -0,0 +1,4 @@ +textarea[data-vimarea="1"] { + color: transparent; + text-shadow: 0 0 0 #000; +} diff --git a/botanjs/src/Components/Vim/_this.js b/botanjs/src/Components/Vim/_this.js new file mode 100644 index 0000000..706cf48 --- /dev/null +++ b/botanjs/src/Components/Vim/_this.js @@ -0,0 +1,42 @@ +(function(){ + var ns = __namespace( "Components.Vim" ); + + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + /** @type {Dandelion.IDOMObject} */ + var IDOMObject = __import( "Dandelion.IDOMObject" ); + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + var messages = { + "INSERT": "-- INSERT --" + , "MORE": "-- MORE --" + , "WRITE": "\"%1\" %2L, %3C written" + , "CONTINUE": "Press ENTER or type command to continue" + , "SEARCH_HIT_BOTTOM": "Seach hit BOTTOM, contining at TOP" + , "TOP": "Top" + , "BOTTOM": "Bot" + , "ALL": "All" + , "EXIT": "Type :quit to exit Vim" + }; + + var errors = { + "E486": "E486: Pattern not found: %1" + }; + + var Message = function( key ) + { + var restArgs = Array.prototype.slice.apply( arguments, 1 ); + var i = 0; + return messages[ key ].replace( /%\d+/g, function( e ) + { + return restArgs[ i ++ ]; + } ); + }; + + ns[ NS_EXPORT ]( EX_FUNC, "Message", Message ); +})();