commit f1653727f2c458dfaeb168566611d9b06fe27965
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2016-03-16T20:57:43Z |
| subject | Some sort of UNDO / REDO ( not functional yet ) |
commit f1653727f2c458dfaeb168566611d9b06fe27965
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2016-03-16T20:57:43Z
Some sort of UNDO / REDO ( not functional yet )
---
botanjs/src/Components/Vim/Actions/INSERT.js | 96 ++++++++--
botanjs/src/Components/Vim/Actions/REDO.js | 42 +++++
botanjs/src/Components/Vim/Actions/UNDO.js | 1 +
botanjs/src/Components/Vim/Controls.js | 80 ++++----
botanjs/src/Components/Vim/DateTime/String.js | 59 ++++++
botanjs/src/Components/Vim/DateTime/_this.js | 213 ++++++++++++++++++++++
botanjs/src/Components/Vim/State/Recorder.js | 7 +-
botanjs/src/Components/Vim/State/Stack.js | 11 ++
botanjs/src/Components/Vim/_this.js | 1 +
botanjs/src/externs/Components.Vim.DateTime.js | 7 +
botanjs/src/externs/Components.Vim.State.Stack.js | 2 +
11 files changed, 472 insertions(+), 47 deletions(-)
diff --git a/botanjs/src/Components/Vim/Actions/INSERT.js b/botanjs/src/Components/Vim/Actions/INSERT.js
index e082baf..367e6b0 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 )
{
@@ -55,13 +57,33 @@
INSERT.prototype.dispose = function()
{
-
+ 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;
+
+ if( insertLength < 0 )
+ {
+ startPos += insertLength;
+ insertLength = 0;
+ }
+
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 +93,67 @@
{
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.__content += c;
+ this.__insertLength += c.length;
+ };
+
+ INSERT.prototype.__specialKey = function( e, inputChar )
+ {
+ var cur = this.__cursor;
+ var feeder = cur.feeder;
+
+ switch( e.keyCode )
+ {
+ case 8: // Backspace
+ if( cur.X == 0 ) return;
+
+ cur.moveX( -1 );
+
+ var f = ContentPosition( feeder );
+
+ this.__contentUndo = feeder.content.substr( f, 1 ) + this.__contentUndo;
+ this.__insertLength --;
+
+ feeder.content =
+ feeder.content.substring( 0, f )
+ + feeder.content.substring( f + 1 );
+
+ break;
+ case 46: // Delete
+ var f = ContentPosition( feeder );
+
+ this.__contentUndo += feeder.content.substr( f, 1 );
+ this.__insertLength ++;
+
+ 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,7 +161,11 @@
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;
diff --git a/botanjs/src/Components/Vim/Actions/REDO.js b/botanjs/src/Components/Vim/Actions/REDO.js
new file mode 100644
index 0000000..da241d9
--- /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 = "<<TODO>>; 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 d7a76f8..0e47a00 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 = "<<TODO>>; before #" + stack.id + " " + stack.time;
}
else
{
diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index 7e13dc6..eacb150 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -3,6 +3,21 @@
var debug = __import( "System.Debug" );
+ 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( sender, e )
{
// Neve capture these keys
@@ -15,7 +30,7 @@
var cfeeder = sender.contentFeeder;
if( cfeeder.cursor.action )
{
- // Esc OR Ctrl+c
+ // Esc OR Ctrl + c
if( e.keyCode == 27 || ( e.ctrlKey && e.keyCode == 67 ) )
{
e.preventDefault();
@@ -29,76 +44,75 @@
}
e.preventDefault();
-
- if( e.ctrlKey )
- {
- VimComboFunc( sender, e );
- return;
- }
-
- var kCode = e.keyCode + ( e.shiftKey ? 1000 : 0 );
+ var kCode = e.keyCode
+ + ( e.shiftKey ? SHIFT : 0 )
+ + ( e.ctrlKey ? CTRL : 0 );
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
break;
- case 72: // h
+ case H: // Left
cfeeder.cursor.moveX( -1 );
break;
- case 74: // j
- cfeeder.cursor.moveY( 1 );
+ case L: // Right
+ cfeeder.cursor.moveX( 1 );
break;
- case 75: // k
+ case K: // Up
cfeeder.cursor.moveY( -1 );
break;
- case 76: // l
- cfeeder.cursor.moveX( 1 );
+ case J: // Down
+ cfeeder.cursor.moveY( 1 );
break;
// Insert
- case 65: // a
+ case A: // Append
+ cfeeder.cursor.moveX( 1 );
cfeeder.cursor.openAction( "INSERT" );
break;
- case 73: // i
+ case I: // Insert
break;
- case 85: // u, undo
+ case U: // Undo
cfeeder.cursor.openRunAction( "UNDO", e );
break;
- case 88: // x, del
+ case CTRL + R: // Redo
+ cfeeder.cursor.openRunAction( "REDO", e );
+ break;
+ case X: // Del
break;
- case 1065: // A, append at the line end
+ case SHIFT + A: // Append at the line end
break;
- case 1088: // X, delete before
+ case SHIFT + X: // Delete before
break;
- case 1085: // U, undo previous changes in oneline
+ case SHIFT + U: // Undo previous changes in oneline
break;
- case 1073: // I, append before the line start, after spaces
+ case SHIFT + I: // Append before the line start, after spaces
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: // $
+ case SHIFT + _4: // $, End
cfeeder.cursor.lineEnd();
break;
- case 1053: // %
+ case SHIFT + _5: // %, Find next item
break;
- case 1054: // ^
+ case SHIFT + _6: // ^, Start
cfeeder.cursor.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
}
diff --git a/botanjs/src/Components/Vim/DateTime/String.js b/botanjs/src/Components/Vim/DateTime/String.js
new file mode 100644
index 0000000..d17e847
--- /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 0000000..1a9312c
--- /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/State/Recorder.js b/botanjs/src/Components/Vim/State/Recorder.js
index e6cfe6b..2fe9081 100644
--- a/botanjs/src/Components/Vim/State/Recorder.js
+++ b/botanjs/src/Components/Vim/State/Recorder.js
@@ -13,7 +13,8 @@
if( i == -1 || !this.__steps.length ) return null;
- return this.__steps[ this.__i = i ];
+ this.__i -= 2;
+ return this.__steps[ i ];
};
Recorder.prototype.redo = function()
@@ -24,7 +25,7 @@
var State = this.__steps[ i ];
if( State )
{
- this.__i = i;
+ this.__i += 2;
return State;
}
@@ -34,6 +35,8 @@
Recorder.prototype.record = function( StateObj )
{
this.__steps[ this.__i ] = StateObj;
+ StateObj.id = this.__i;
+
delete this.__steps[ ++ this.__i ];
};
diff --git a/botanjs/src/Components/Vim/State/Stack.js b/botanjs/src/Components/Vim/State/Stack.js
index a58e99d..0e7d561 100644
--- a/botanjs/src/Components/Vim/State/Stack.js
+++ b/botanjs/src/Components/Vim/State/Stack.js
@@ -1,13 +1,19 @@
(function(){
var ns = __namespace( "Components.Vim.State" );
+ /** @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 +21,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/_this.js b/botanjs/src/Components/Vim/_this.js
index b568ced..4c51246 100644
--- a/botanjs/src/Components/Vim/_this.js
+++ b/botanjs/src/Components/Vim/_this.js
@@ -15,6 +15,7 @@
, "EXIT": "Type :quit<Enter> to exit Vim"
, "UNDO_LIMIT": "Already at oldest change"
+ , "REDO_LIMIT": "Already at newest change"
};
var errors = {
diff --git a/botanjs/src/externs/Components.Vim.DateTime.js b/botanjs/src/externs/Components.Vim.DateTime.js
new file mode 100644
index 0000000..9498299
--- /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 c572081..ea74dc2 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;