diff --git a/botanjs/src/Components/Vim/Actions/INSERT.js b/botanjs/src/Components/Vim/Actions/INSERT.js index e082baf1..0628330f 100644 --- a/botanjs/src/Components/Vim/Actions/INSERT.js +++ b/botanjs/src/Components/Vim/Actions/INSERT.js @@ -1,10 +1,12 @@ (function(){ var ns = __namespace( "Components.Vim.Actions" ); - var Mesg = __import( "Components.Vim.Message" ); - /** @type {Components.Vim.State.Stack} */ - var Stack = __import( "Components.Vim.State.Stack" ); + var Stack = __import( "Components.Vim.State.Stack" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + var Mesg = __import( "Components.Vim.Message" ); var Translate = function( c ) { @@ -12,56 +14,50 @@ { case "Tab": return "\t"; + case "Enter": + return "\n"; default: return c; } }; - /* @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.__startX = Cursor.aPos; + // Initialize this stack this.__rec( "", true ); }; INSERT.prototype.dispose = function() { - + this.__cursor.moveX( -1 ); + this.__rec( "", true ); }; - INSERT.prototype.__storeState = function( c, pos ) + INSERT.prototype.__storeState = function() { + var cur = this.__cursor; + var feeder = cur.feeder; + var insertLength = this.__insertLength; + var contentUndo = this.__contentUndo; + var startPos = this.__startPosition; + var startX = this.__startX; + return function() { - debug.Inf( pos, c ); + var contentRedo = feeder.content.substr( startPos, insertLength ); + feeder.content = + feeder.content.substring( 0, startPos ) + + contentUndo + + feeder.content.substring( startPos + insertLength ); + insertLength = contentUndo.length; + contentUndo = contentRedo; + + feeder.pan(); }; }; @@ -71,21 +67,79 @@ { if( this.__stack ) { - var c = this.__content; + // If nothings changed + if( this.__insertLength == 0 + && this.__contentUndo === "" + ) return; this.__stack.store( - this.__storeState( c, this.__startPosition ) + this.__storeState() ); - this.__cursor.rec.store( this.__stack ); + this.__cursor.rec.record( this.__stack ); } - this.__content = ""; + this.__insertLength = 0; + this.__contentUndo = ""; this.__stack = new Stack(); - this.__startPosition = ContentPosition( this.__cursor.feeder ); + this.__startPosition = this.__cursor.aPos; } - this.__content += c; + if( c == "\n" ) + { + // todo + } + + this.__insertLength += c.length; + }; + + INSERT.prototype.__specialKey = function( e, inputChar ) + { + var cur = this.__cursor; + var feeder = cur.feeder; + + switch( e.keyCode ) + { + case 8: // Backspace + var oY = feeder.panY + cur.Y; + if( cur.X == 0 && feeder.panY == 0 && cur.Y == 0 ) return; + + cur.moveX( -1, true, true ); + + var f = cur.aPos; + + if( this.__insertLength <= 0 ) + { + this.__contentUndo = feeder.content.substr( f, 1 ) + this.__contentUndo; + this.__startPosition --; + } + else + { + this.__insertLength --; + } + + feeder.content = + feeder.content.substring( 0, f ) + + feeder.content.substring( f + 1 ); + + break; + case 46: // Delete + var f = cur.aPos; + + this.__contentUndo += feeder.content.substr( f, 1 ); + + feeder.content = + feeder.content.substring( 0, f ) + + feeder.content.substring( f + 1 ); + + break; + default: + // Do nothing + return; + } + + feeder.pan(); + feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); }; INSERT.prototype.handler = function( e ) @@ -93,12 +147,16 @@ e.preventDefault(); var inputChar = Translate( e.key ); - if( inputChar.length != 1 ) return; + if( inputChar.length != 1 ) + { + this.__specialKey( e, inputChar ); + return; + } var cur = this.__cursor; var feeder = cur.feeder; - var f = ContentPosition( feeder ); + var f = cur.aPos; feeder.content = feeder.content.substring( 0, f ) diff --git a/botanjs/src/Components/Vim/Actions/REDO.js b/botanjs/src/Components/Vim/Actions/REDO.js new file mode 100644 index 00000000..da241d92 --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/REDO.js @@ -0,0 +1,42 @@ +(function(){ + var ns = __namespace( "Components.Vim.Actions" ); + + var Mesg = __import( "Components.Vim.Message" ); + + /** @type {Components.Vim.Cursor.IAction} */ + var REDO = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + this.__message = "REDO COMMAND"; + }; + + REDO.prototype.dispose = function() + { + + }; + + REDO.prototype.handler = function( e ) + { + e.preventDefault(); + + /** @type {Components.Vim.State.Stack} */ + var stack = this.__cursor.rec.redo(); + if( stack ) + { + stack.play(); + this.__message = "<>; before #" + stack.id + " " + stack.time; + } + else + { + this.__message = Mesg( "REDO_LIMIT" ); + } + }; + + REDO.prototype.getMessage = function() + { + return this.__message; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "REDO", REDO ); +})(); diff --git a/botanjs/src/Components/Vim/Actions/UNDO.js b/botanjs/src/Components/Vim/Actions/UNDO.js index d7a76f8c..0e47a00a 100644 --- a/botanjs/src/Components/Vim/Actions/UNDO.js +++ b/botanjs/src/Components/Vim/Actions/UNDO.js @@ -25,6 +25,7 @@ if( stack ) { stack.play(); + this.__message = "<>; before #" + stack.id + " " + stack.time; } else { diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index 7e13dc63..dcaa9dce 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -2,8 +2,75 @@ var ns = __namespace( "Components.Vim" ); var debug = __import( "System.Debug" ); + var beep = ns[ NS_INVOKE ]( "Beep" ); - var Controls = function( sender, e ) + var SHIFT = 1 << 9; + var CTRL = 1 << 10; + + var BACKSPACE = 8; + + var _0 = 48; var _1 = 49; var _2 = 50; var _3 = 51; var _4 = 52; + var _5 = 53; var _6 = 54; var _7 = 55; var _8 = 56; var _9 = 57; + + var A = 65; var B = 66; var C = 67; var D = 68; var E = 69; + var F = 70; var G = 71; var H = 72; var I = 73; var J = 74; + var K = 75; var L = 76; var M = 77; var N = 78; var O = 79; + var P = 80; var Q = 81; var R = 82; var S = 83; var T = 84; + var U = 85; var V = 86; var W = 87; var X = 88; var Y = 89; + var Z = 90; + + var Controls = function( vimArea ) + { + /** @type {Components.Vim.VimArea} */ + this.__vimArea = vimArea + this.__keyChains = []; + }; + + Controls.prototype.__comboG = function( keyCode ) + { + var keyON = this.__keyChains[ 0 ] == G; + if( keyON ) + { + var cursor = this.__vimArea.contentFeeder.cursor; + switch( keyCode ) + { + case G: + cursor.moveY( -Number.MAX_VALUE ); + cursor.moveX( -Number.MAX_VALUE, true ); + this.__keyChains = []; + return true; + default: + this.__keyChains = []; + beep(); + return true; + } + } + else if( keyCode == G ) + { + this.__keyChains[ 0 ] = G; + return true; + } + + return false; + }; + + Controls.prototype.__comboT = function( e ) { return false; }; + + // < + Controls.prototype.__comboLeftShift = function( e ) { return false; }; + + // > + Controls.prototype.__comboRightShift = function( e ) { return false; }; + + Controls.prototype.__comboKey = function( e ) + { + return this.__comboG( e ) + || this.__comboT( e ) + || this.__comboLeftShift( e ) + || this.__comboRightShift( e ); + }; + + Controls.prototype.handler = function( sender, e ) { // Neve capture these keys if( e.altKey @@ -11,12 +78,24 @@ || ( 112 < e.keyCode && e.keyCode < 124 ) ) return; + var vArea = this.__vimArea; // Action Mode handled by the actions themselves - var cfeeder = sender.contentFeeder; + var cfeeder = vArea.contentFeeder; + + // Esc OR Ctrl + c + var Escape = e.keyCode == 27 || ( e.ctrlKey && e.keyCode == 67 ); + + // Clear the keychains in combo commands + if( Escape && this.__keyChains.length ) + { + this.__keyChains = []; + beep(); + return; + } + if( cfeeder.cursor.action ) { - // Esc OR Ctrl+c - if( e.keyCode == 27 || ( e.ctrlKey && e.keyCode == 67 ) ) + if( Escape ) { e.preventDefault(); cfeeder.cursor.closeAction(); @@ -29,81 +108,110 @@ } e.preventDefault(); + var kCode = e.keyCode + + ( e.shiftKey || e.getModifierState( "CapsLock" ) ? SHIFT : 0 ) + + ( e.ctrlKey ? CTRL : 0 ); - if( e.ctrlKey ) + // Handles long commands + + if( this.__comboKey( kCode ) ) return; + + var cfeeder = vArea.contentFeeder; + var sfeeder = vArea.statusFeeder; + + var ccur = cfeeder.cursor; + + var cMoveX = function( a, b, c ) { - VimComboFunc( sender, e ); - return; - } + var x = ccur.X; + ccur.moveX( a, b, c ); + if( ccur.X == x ) beep(); + }; - var kCode = e.keyCode + ( e.shiftKey ? 1000 : 0 ); + var cMoveY = function( a ) + { + var y = ccur.Y + cfeeder.panY; + ccur.moveY( a ); + if( y == ( ccur.Y + cfeeder.panY ) ) + { + if( 0 < a && !cfeeder.EOF ) return; + beep(); + } + }; - var cfeeder = sender.contentFeeder; - var sfeeder = sender.statusFeeder; switch( kCode ) { // Cursor movements - case 8: // Backspace, go back 1 char, regardless of line + case BACKSPACE: // Backspace, go back 1 char, regardless of line + cMoveX( -1, true ); break; - case 72: // h - cfeeder.cursor.moveX( -1 ); + case H: // Left + cMoveX( -1 ); break; - case 74: // j - cfeeder.cursor.moveY( 1 ); + case L: // Right + cMoveX( 1 ); break; - case 75: // k - cfeeder.cursor.moveY( -1 ); + case K: // Up + cMoveY( -1 ); break; - case 76: // l - cfeeder.cursor.moveX( 1 ); + case J: // Down + cMoveY( 1 ); break; // Insert - case 65: // a - cfeeder.cursor.openAction( "INSERT" ); + case A: // Append + cMoveX( 1, true, true ); + ccur.openAction( "INSERT" ); break; - case 73: // i + case I: // Insert break; - case 85: // u, undo - cfeeder.cursor.openRunAction( "UNDO", e ); + case U: // Undo + ccur.openRunAction( "UNDO", e ); break; - case 88: // x, del + case CTRL + R: // Redo + ccur.openRunAction( "REDO", e ); break; - case 1065: // A, append at the line end + case X: // Del break; - case 1088: // X, delete before + case SHIFT + A: // Append at the line end break; - case 1085: // U, undo previous changes in oneline + case SHIFT + X: // Delete before break; - case 1073: // I, append before the line start, after spaces + case SHIFT + U: // Undo previous changes in oneline + break; + case SHIFT + I: // Append before the line start, after spaces break; + case SHIFT + G: // Goto last line + ccur.moveY( Number.MAX_VALUE ); + ccur.moveX( Number.MAX_VALUE, true ); + break; // remove characters - case 88: // x, remove in cursor + case X: // Remove in cursor break; - case 1088: // X, remove before cursor + case SHIFT + X: // Remove before cursor break; - case 1072: // H, First line buffer + case SHIFT + H: // First line buffer break; - case 1076: // L, Last line buffer + case SHIFT + L: // Last line buffer break; - case 1052: // $ - cfeeder.cursor.lineEnd(); + case SHIFT + _4: // $, End + ccur.lineEnd(); break; - case 1053: // % + case SHIFT + _5: // %, Find next item break; - case 1054: // ^ - cfeeder.cursor.lineStart(); + case SHIFT + _6: // ^, Start + ccur.lineStart(); break; - case 1074: // J, Join lines + case SHIFT + J: // Join lines break; - case 1075: // K, manual entry + case SHIFT + K: // manual entry break; case 112: // F1, help } }; - ns[ NS_EXPORT ]( EX_FUNC, "Controls", Controls ); + ns[ NS_EXPORT ]( EX_CLASS, "Controls", Controls ); })(); diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js index abb5f1b7..fc3d4e12 100644 --- a/botanjs/src/Components/Vim/Cursor.js +++ b/botanjs/src/Components/Vim/Cursor.js @@ -82,7 +82,7 @@ // Can only be 1, -1 // 0 will be treated as undefined - Cursor.prototype.moveX = function( d ) + Cursor.prototype.moveX = function( d, penentrate, phantomSpace ) { var x = this.pX; @@ -93,15 +93,29 @@ var buffs = this.feeder.lineBuffers; + if( penentrate && x < 0 && ( 0 < this.feeder.panY || 0 < this.Y ) ) + { + this.moveY( -1 ); + this.lineEnd( phantomSpace ); + return; + } + /** @type {Components.Vim.LineBuffer} */ var line = GetLine( buffs, this.Y ); var content = line.visualLines.join( "\n" ); + var cLen = content.length; var c = content[ x ]; - if( c == undefined ) + // Include empty lines befor cursor end + if( ( phantomSpace && cLen - 1 <= x ) || ( cLen == 1 && c == undefined ) ) { - x = d > 0 ? content.length - 1 : 0; + x = d > 0 ? cLen - 1 : 0; + } + // ( 2 < cLen ) Exclude empty lines at cursor end + else if( ( 2 < cLen && x == cLen - 1 && c == " " ) || c == undefined ) + { + x = d > 0 ? cLen - 2 : 0; } else if( c == "\n" ) { @@ -124,9 +138,9 @@ this.updatePosition(); }; - Cursor.prototype.lineEnd = function() + Cursor.prototype.lineEnd = function( phantomSpace ) { - this.moveX( Number.MAX_VALUE ); + this.moveX( Number.MAX_VALUE, false, phantomSpace ); }; Cursor.prototype.updatePosition = function() @@ -135,7 +149,7 @@ this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); }; - Cursor.prototype.moveY = function( d ) + Cursor.prototype.moveY = function( d, penentrate ) { var Y = this.Y + d; var line; @@ -158,7 +172,7 @@ var lineShift = Y - feeder.moreAt; var i = 0; - while( true ) + while( !feeder.EOF ) { feeder.pan( undefined, lineShift + i ); @@ -182,7 +196,7 @@ line = line.next ) { if( line.br ) i ++; - if( line.lineNum == Y ) break; + if( line.lineNum == Y || line.next.placeholder ) break; } this.Y = i; @@ -299,6 +313,33 @@ return w; } ); + // The absolute content position + __readOnly( Cursor.prototype, "aPos", function() + { + var f = this.feeder; + var line = this.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 += this.aX; + return p; + } ); + __readOnly( Cursor.prototype, "message", function() { if( this.__pulseMsg ) diff --git a/botanjs/src/Components/Vim/DateTime/String.js b/botanjs/src/Components/Vim/DateTime/String.js new file mode 100644 index 00000000..d17e847b --- /dev/null +++ b/botanjs/src/Components/Vim/DateTime/String.js @@ -0,0 +1,59 @@ +(function(){ + var ns = __namespace( "Components.Vim.DateTime" ); + + var messages = { + "AboutAMinuteAgo" : "about a minute ago" + , "AboutAMonthAgo" : "about a month ago" + , "AboutAnHourAgo" : "about an hour ago" + , "AboutAWeekAgo" : "about a week ago" + , "last Friday" : "last Friday" + , "last Monday" : "last Monday" + , "last Saturday" : "last Saturday" + , "last Sunday" : "last Sunday" + , "last Thursday" : "last Thursday" + , "last Tuesday" : "last Tuesday" + , "last Wednesday" : "last Wednesday" + , "on Friday" : "on Friday" + , "on Monday" : "on Monday" + , "on Saturday" : "on Saturday" + , "on Sunday" : "on Sunday" + , "on Thursday" : "on Thursday" + , "on Tuesday" : "on Tuesday" + , "on Wednesday" : "on Wednesday" + , "OverAYearAgo" : "over a year ago" + , "XHoursAgo_2To4" : "%1 hours ago" + , "XHoursAgo_EndsIn1Not11" : "%1 hours ago" + , "XHoursAgo_EndsIn2To4Not12To14" : "%1 hours ago" + , "XHoursAgo_Other" : "%1 hours ago" + , "XMinutesAgo_2To4" : "%1 minutes ago" + , "XMinutesAgo_EndsIn1Not11" : "%1 minutes ago" + , "XMinutesAgo_EndsIn2To4Not12To14" : "%1 minutes ago" + , "XMinutesAgo_Other" : "%1 minutes ago" + , "XMonthsAgo_2To4" : "%1 months ago" + , "XMonthsAgo_5To12" : "%1 months ago" + , "XSecondsAgo_2To4" : "%1 seconds ago" + , "XSecondsAgo_EndsIn1Not11" : "%1 seconds ago" + , "XSecondsAgo_EndsIn2To4Not12To14" : "%1 seconds ago" + , "XSecondsAgo_Other" : "%1 seconds ago" + , "XWeeksAgo_2To4" : "%1 weeks ago" + }; + + var GetString = function( arr, key, restArgs ) + { + if( arr[ key ] == undefined ) return key; + + var i = 0; + return arr[ key ].replace( /%\d+/g, function( e ) + { + return restArgs[ i ++ ]; + } ); + }; + + var DateTimeString = function( key ) + { + var restArgs = Array.prototype.slice.call( arguments, 1 ); + return GetString( messages, key, restArgs ); + }; + + ns[ NS_EXPORT ]( EX_FUNC, "String", DateTimeString ); +})(); diff --git a/botanjs/src/Components/Vim/DateTime/_this.js b/botanjs/src/Components/Vim/DateTime/_this.js new file mode 100644 index 00000000..1a9312c5 --- /dev/null +++ b/botanjs/src/Components/Vim/DateTime/_this.js @@ -0,0 +1,213 @@ +(function(){ + var ns = __namespace( "Components.Vim.DateTime" ); + + var Minute = 60; + var Hour = 60 * Minute; + var Day = 24 * Hour; + var Week = 7 * Day; + var Month = 30.5 * Day; + var Year = 365 * Day; + + var Mesg = ns[ NS_INVOKE ]( "String" ); + + var PluralHourStrings = [ + "XHoursAgo_2To4", + "XHoursAgo_EndsIn1Not11", + "XHoursAgo_EndsIn2To4Not12To14", + "XHoursAgo_Other" + ]; + + var PluralMinuteStrings = [ + "XMinutesAgo_2To4", + "XMinutesAgo_EndsIn1Not11", + "XMinutesAgo_EndsIn2To4Not12To14", + "XMinutesAgo_Other" + ]; + + var PluralSecondStrings = [ + "XSecondsAgo_2To4", + "XSecondsAgo_EndsIn1Not11", + "XSecondsAgo_EndsIn2To4Not12To14", + "XSecondsAgo_Other" + ]; + + var DayOfWeek = { Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6 }; + + var GetPluralMonth = function( month ) + { + if ( month >= 2 && month <= 4 ) + { + return Mesg( "XMonthsAgo_2To4", month ); + } + else if ( month >= 5 && month <= 12 ) + { + return Mesg( "XMonthsAgo_5To12", month ); + } + else + { + throw new Error( "Invalid number of Months" ); + } + }; + + var GetLastDayOfWeek = function( dow ) + { + var result; + switch ( dow ) + { + case DayOfWeek.Monday: + result = Mesg( "last Monday" ); + break; + case DayOfWeek.Tuesday: + result = Mesg( "last Tuesday" ); + break; + case DayOfWeek.Wednesday: + result = Mesg( "last Wednesday" ); + break; + case DayOfWeek.Thursday: + result = Mesg( "last Thursday" ); + break; + case DayOfWeek.Friday: + result = Mesg( "last Friday" ); + break; + case DayOfWeek.Saturday: + result = Mesg( "last Saturday" ); + break; + case DayOfWeek.Sunday: + result = Mesg( "last Sunday" ); + break; + default: + result = Mesg( "last Sunday" ); + break; + } + + return result; + }; + + var GetOnDayOfWeek = function( dow ) + { + var result; + + switch( dow ) + { + case DayOfWeek.Monday: + result = Mesg( "on Monday" ); + break; + case DayOfWeek.Tuesday: + result = Mesg( "on Tuesday" ); + break; + case DayOfWeek.Wednesday: + result = Mesg( "on Wednesday" ); + break; + case DayOfWeek.Thursday: + result = Mesg( "on Thursday" ); + break; + case DayOfWeek.Friday: + result = Mesg( "on Friday" ); + break; + case DayOfWeek.Saturday: + result = Mesg( "on Saturday" ); + break; + case DayOfWeek.Sunday: + result = Mesg( "on Sunday" ); + break; + default: + result = Mesg( "on Sunday" ); + break; + } + + return result; + }; + + var GetPluralTimeUnits = function( units, resources ) + { + var modTen = units % 10; + var modHundred = units % 100; + + if ( units <= 1 ) + { + throw new Error( "Invalid number of Time units" ); + } + else if ( 2 <= units && units <= 4 ) + { + return Mesg( resources[ 0 ], units ); + } + else if ( modTen == 1 && modHundred != 11 ) + { + return Mesg( resources[ 1 ], units ); + } + else if ( ( 2 <= modTen && modTen <= 4 ) && !( 12 <= modHundred && modHundred <= 14 ) ) + { + return Mesg( resources[ 2 ], units ); + } + else + { + return Mesg( resources[ 3 ], units ); + } + }; + + var RelativeTime = function( given ) + { + var diffSecs = Math.round( 0.001 * ( new Date().getTime() - given.getTime() ) ); + + if( Year < diffSecs ) + { + result = Mesg( "OverAYearAgo" ); + } + else if( ( 1.5 * Month ) < diffSecs ) + { + var nMonths = Math.round( ( diffSecs + Month / 2 ) / Month ); + result = GetPluralMonth( nMonths ); + } + else if( ( 3.5 * Week ) <= diffSecs ) + { + result = Mesg( "AboutAMonthAgo" ); + } + else if( Week <= diffSecs ) + { + var nWeeks = Math.round( diffSecs / Week ); + if ( 1 < nWeeks ) + { + result = Mesg( "XWeeksAgo_2To4", nWeeks ); + } + else + { + result = Mesg( "AboutAWeekAgo" ); + } + } + else if ( ( 5 * Day ) <= diffSecs ) + { + result = GetLastDayOfWeek( given.getDay() ); + } + else if ( Day <= diffSecs ) + { + result = GetOnDayOfWeek( given.getDay() ); + } + else if ( ( 2 * Hour ) <= diffSecs ) + { + var nHours = Math.round( diffSecs / Hour ); + result = GetPluralTimeUnits( nHours, PluralHourStrings ); + } + else if ( Hour <= diffSecs ) + { + result = Mesg( "AboutAnHourAgo" ); + } + else if ( ( 2 * Minute ) <= diffSecs ) + { + var nMinutes = Math.round( diffSecs / Minute ); + result = GetPluralTimeUnits( nMinutes, PluralMinuteStrings ); + } + else if ( Minute <= diffSecs ) + { + result = Mesg( "AboutAMinuteAgo" ); + } + else + { + var nSeconds = 1 < diffSecs ? diffSecs : 2; + result = GetPluralTimeUnits( nSeconds, PluralSecondStrings ); + } + + return result; + }; + + ns[ NS_EXPORT ]( EX_FUNC, "RelativeTime", RelativeTime ); +})(); diff --git a/botanjs/src/Components/Vim/LineBuffer.js b/botanjs/src/Components/Vim/LineBuffer.js index 2eccb0dc..238cfb33 100644 --- a/botanjs/src/Components/Vim/LineBuffer.js +++ b/botanjs/src/Components/Vim/LineBuffer.js @@ -97,6 +97,11 @@ LineBuffer.prototype.toString = function() { + if( this.content.length < this.cols ) + { + return this.content + " "; + } + return this.content || " "; }; diff --git a/botanjs/src/Components/Vim/LineFeeder.js b/botanjs/src/Components/Vim/LineFeeder.js index 58258b4f..3d0ca713 100644 --- a/botanjs/src/Components/Vim/LineFeeder.js +++ b/botanjs/src/Components/Vim/LineFeeder.js @@ -144,7 +144,13 @@ f = this.content.indexOf( "\n" ); for( i = 1; f != -1 && i < Y; i ++ ) { - f = this.content.indexOf( "\n", f + 1 ); + var a = this.content.indexOf( "\n", f + 1 ); + if( a == -1 ) + { + Y = i; + break; + } + f = a; } } @@ -163,6 +169,10 @@ this.__softRender(); }; + __readOnly( Feeder.prototype, "linesTotal", function() { + return this.content.match( "\n" ); + } ); + __readOnly( Feeder.prototype, "firstBuffer", function() { return this.lineBuffers[ 0 ]; } ); diff --git a/botanjs/src/Components/Vim/State/Recorder.js b/botanjs/src/Components/Vim/State/Recorder.js index e6cfe6b2..8e095f4e 100644 --- a/botanjs/src/Components/Vim/State/Recorder.js +++ b/botanjs/src/Components/Vim/State/Recorder.js @@ -4,7 +4,9 @@ var Recorder = function() { this.__steps = []; + this.__stacks = []; this.__i = 0; + this.__j = 0; }; Recorder.prototype.undo = function() @@ -18,13 +20,11 @@ Recorder.prototype.redo = function() { - var i = this.__i + 1; - if( i == -1 || !this.__steps.length ) return null; + var State = this.__steps[ this.__i ]; - var State = this.__steps[ i ]; if( State ) { - this.__i = i; + this.__i ++; return State; } @@ -33,8 +33,12 @@ Recorder.prototype.record = function( StateObj ) { - this.__steps[ this.__i ] = StateObj; - delete this.__steps[ ++ this.__i ]; + this.__steps[ this.__i ++ ] = StateObj; + this.__stacks[ this.__j ++ ] = StateObj; + + delete this.__steps[ this.__i ]; + + StateObj.id = this.__j; }; ns[ NS_EXPORT ]( EX_CLASS, "Recorder", Recorder ); diff --git a/botanjs/src/Components/Vim/State/Stack.js b/botanjs/src/Components/Vim/State/Stack.js index a58e99d9..5096ccc8 100644 --- a/botanjs/src/Components/Vim/State/Stack.js +++ b/botanjs/src/Components/Vim/State/Stack.js @@ -1,13 +1,16 @@ (function(){ var ns = __namespace( "Components.Vim.State" ); - var Stack = function() - { - }; + /** @type {Components.Vim.DateTime} */ + var RelativeTime = __import( "Components.Vim.DateTime.RelativeTime" ); + + var Stack = function() { }; Stack.prototype.store = function( handler ) { this.__handler = handler; + this.__time = new Date(); + this.id = 0; }; Stack.prototype.play = function() @@ -15,5 +18,10 @@ if( this.__handler ) this.__handler(); }; + __readOnly( Stack.prototype, "time", function() + { + return RelativeTime( this.__time ); + } ); + ns[ NS_EXPORT ]( EX_CLASS, "Stack", Stack ); })(); diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index 847ca78a..b9a76e46 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -53,7 +53,12 @@ var _self = this; - stage.addEventListener( "KeyDown", KeyHandler( this, VimControls ) ); + var controls = new VimControls( this ); + stage.addEventListener( + "KeyDown" + , KeyHandler( this, controls.handler.bind( controls ) ) + ); + stage.addEventListener( "Focus", function() { _self.__active = true; } ); stage.addEventListener( "Blur", function() { _self.__active = false; } ); diff --git a/botanjs/src/Components/Vim/_this.js b/botanjs/src/Components/Vim/_this.js index b568ced1..5b263b9b 100644 --- a/botanjs/src/Components/Vim/_this.js +++ b/botanjs/src/Components/Vim/_this.js @@ -15,6 +15,7 @@ , "EXIT": "Type :quit to exit Vim" , "UNDO_LIMIT": "Already at oldest change" + , "REDO_LIMIT": "Already at newest change" }; var errors = { @@ -44,6 +45,178 @@ return GetString( errors, key, restArgs ); }; + var bAudio = new Audio( + /*{{{ Audio Data */ + "data:audio/ogg;base64," + + "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" + + "wNE0QBM9QBNFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAcTQM0UQQ0UQQAAAAAAAAATRQB0VQB0TQBAAAAAAAAQBNFwDNFQDRVAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAcTQM0UQQ0UQQAAAAAAAAATRQBUTUBTzQBAAAAAAAAQBNFQDRNQFRNAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "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" + + "AADA+zAAAAAwBVztbAIODg4=" + /*}}}*/ + ); + + var Beep = function() + { + // Beep Async + setTimeout(function() { + bAudio.pause(); + bAudio.currentTime = 0; + bAudio.play(); + }, 0 ); + }; + ns[ NS_EXPORT ]( EX_FUNC, "Message", Message ); ns[ NS_EXPORT ]( EX_FUNC, "Error", Error ); + ns[ NS_EXPORT ]( EX_FUNC, "Beep", Beep ); })(); diff --git a/botanjs/src/System/utils/Perf.js b/botanjs/src/System/utils/Perf.js index 4b0c82e6..4e2f933f 100644 --- a/botanjs/src/System/utils/Perf.js +++ b/botanjs/src/System/utils/Perf.js @@ -22,7 +22,7 @@ /* }}}*/ // Reverse an array using XOR swap - var Array_Reverse = function( array ) + var ArrayReverse = function( array ) { var i = null; var l = array.length; @@ -39,6 +39,26 @@ } }; + // Count Occurance of a string + var CountSubString = function ( str, search ) + { + if ( search.length <= 0 ) + { + return str.length + 1; + } + + var c = 0; + + for( var i = str.indexOf( search ); 0 <= i ; i = str.indexOf( search, i ) ) + { + c ++; + i ++; + } + + return c; + }; + ns[ NS_EXPORT ]( EX_READONLY_GETTER, "uuid", UUID ); - ns[ NS_EXPORT ]( EX_FUNC, "ArrayReverse", Array_Reverse ); + ns[ NS_EXPORT ]( EX_FUNC, "CountSubstr", CountSubString ); + ns[ NS_EXPORT ]( EX_FUNC, "ArrayReverse", ArrayReverse ); })(); diff --git a/botanjs/src/externs/Components.Vim.Cursor.js b/botanjs/src/externs/Components.Vim.Cursor.js index 13b5624b..ec39afcb 100644 --- a/botanjs/src/externs/Components.Vim.Cursor.js +++ b/botanjs/src/externs/Components.Vim.Cursor.js @@ -38,6 +38,8 @@ Components.Vim.Cursor.X; /** @type Number */ Components.Vim.Cursor.Y; /** @type Number */ +Components.Vim.Cursor.aPos; +/** @type Number */ Components.Vim.Cursor.cols; /** @type message */ Components.Vim.Cursor.string; diff --git a/botanjs/src/externs/Components.Vim.DateTime.js b/botanjs/src/externs/Components.Vim.DateTime.js new file mode 100644 index 00000000..9498299a --- /dev/null +++ b/botanjs/src/externs/Components.Vim.DateTime.js @@ -0,0 +1,7 @@ +/** @constructor */ +Components.Vim.DateTime = function(){}; + +/** @type Function */ +Components.Vim.DateTime.RelativeTime; +/** @type Function */ +Components.Vim.DateTime.String; diff --git a/botanjs/src/externs/Components.Vim.State.Stack.js b/botanjs/src/externs/Components.Vim.State.Stack.js index c5720817..ea74dc2d 100644 --- a/botanjs/src/externs/Components.Vim.State.Stack.js +++ b/botanjs/src/externs/Components.Vim.State.Stack.js @@ -5,3 +5,5 @@ Components.Vim.State.Stack = function(){}; Components.Vim.State.Stack.play; /** @type Function */ Components.Vim.State.Stack.store; +/** @type Function */ +Components.Vim.State.Stack.time; diff --git a/botanjs/src/externs/System.utils.Perf.js b/botanjs/src/externs/System.utils.Perf.js index 756699f1..8b7b6edd 100644 --- a/botanjs/src/externs/System.utils.Perf.js +++ b/botanjs/src/externs/System.utils.Perf.js @@ -6,3 +6,5 @@ System.utils.Perf.uuid; /** @type {Function} */ System.utils.Perf.ArrayReverse; +/** @type {Function} */ +System.utils.Perf.CountSubstr;