commit 3ed7d2be846607d28ebdc417711d45a1d99b416d
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2016-04-02T10:35:12Z |
| subject | History stacks |
commit 3ed7d2be846607d28ebdc417711d45a1d99b416d
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2016-04-02T10:35:12Z
History stacks
---
botanjs/src/Components/Vim/Controls.js | 15 ++-
.../Components/Vim/Ex/{Search.js => Command.js} | 105 +++++++++++++++++----
botanjs/src/Components/Vim/State/History.js | 96 +++++++++++++++++++
botanjs/src/Components/Vim/VimArea.js | 16 ++--
.../externs/Components.Vim.Controls.InputEvent.js | 4 +
.../src/externs/Components.Vim.State.History.js | 9 ++
6 files changed, 212 insertions(+), 33 deletions(-)
diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index e129357..631d736 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -4,8 +4,8 @@
/** @type {System.Debug} */
var debug = __import( "System.Debug" );
- /** @type {Components.Vim.Ex.Search} */
- var ExSearch = __import( "Components.Vim.Ex.Search" );
+ /** @type {Components.Vim.Ex.Command} */
+ var ExCommand = __import( "Components.Vim.Ex.Command" );
var beep = ns[ NS_INVOKE ]( "Beep" );
@@ -441,10 +441,10 @@
}, _8 );
break;
- case SLASH: // "/" Seach movement
+ case SLASH: // "/" Search movement
this.__cMovement = true;
- this.__divedCCmd = new ExSearch( ccur );
+ this.__divedCCmd = new ExCommand( ccur, "/" );
this.__divedCCmd.handler( e );
break;
default:
@@ -499,7 +499,8 @@
this.__cMovement = false;
this.__divedCCmd = null;
}
- else return;
+
+ if( e.canceled ) return;
}
var cfeeder = this.__cfeeder;
@@ -545,6 +546,7 @@
var InputEvent = function( sender, e )
{
this.__target = sender;
+ this.__canceled = false;
if( typeof( e ) == "string" )
{
@@ -572,11 +574,14 @@
this.__range = null;
};
+ InputEvent.prototype.cancel = function() { this.__canceled = true; };
+
__readOnly( InputEvent.prototype, "target", function() { return this.__target; } );
__readOnly( InputEvent.prototype, "key", function() { return this.__key; } );
__readOnly( InputEvent.prototype, "keyCode", function() { return this.__kCode; } );
__readOnly( InputEvent.prototype, "ModKeys", function() { return this.__modKeys; } );
__readOnly( InputEvent.prototype, "Escape", function() { return this.__escape; } );
+ __readOnly( InputEvent.prototype, "canceled", function() { return this.__canceled; } );
__readOnly( InputEvent.prototype, "range", function() {
diff --git a/botanjs/src/Components/Vim/Ex/Search.js b/botanjs/src/Components/Vim/Ex/Command.js
similarity index 55%
rename from botanjs/src/Components/Vim/Ex/Search.js
rename to botanjs/src/Components/Vim/Ex/Command.js
index 169f5a5..cd8600b 100644
--- a/botanjs/src/Components/Vim/Ex/Search.js
+++ b/botanjs/src/Components/Vim/Ex/Command.js
@@ -8,27 +8,37 @@
/** @type {System.utils.Perf} */
var Perf = __import( "System.utils.Perf" );
- var Mesg = __import( "Components.Vim.Message" );
+ /**j@type {Components.Vim.State.History} */
+ var History = __import( "Components.Vim.State.History" );
+ var Mesg = __import( "Components.Vim.Message" );
+ var beep = __import( "Components.Vim.Beep" );
+
+ // This is for security & privacy concerns?
+ var ZMap = {
+ "/": Perf.uuid
+ , ":" : Perf.uuid
+ };
/** @type {Components.Vim.Cursor.IAction} */
- var Search = function( Cursor )
+ var Command = function( Cursor, Mode )
{
var _self = this;
+ if( !ZMap[ Mode ] ) throw new Error( "Unsupport mode: " + Mode );
/** @type {Components.Vim.Cursor} */
this.__cursor = Cursor;
this.__statusBar = Cursor.Vim.statusBar;
+ this.__mode = Mode;
+ this.__hist = new History( ZMap[ Mode ] );
+
this.__command = [];
- this.__blinkId = "ExSearchBlinkCycle" + Perf.uuid;
+ this.__currentCommand = null;
+ this.__blinkId = "ExCommandBlinkCycle" + Perf.uuid;
this.__curPos = 0;
- this.__disp = function()
- {
- };
-
- var feeder = Cursor.feeder;
+ var feeder = Cursor.feeder;
var __blink = false;
var __holdBlink = false;
@@ -77,7 +87,7 @@
this.__statusBar.override = this.__doBlink;
};
- Search.prototype.dispose = function()
+ Command.prototype.dispose = function()
{
this.__statusBar.override = null;
@@ -86,7 +96,7 @@
feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
};
- Search.prototype.handler = function( e )
+ Command.prototype.handler = function( e )
{
e.preventDefault();
@@ -96,6 +106,8 @@
var InputKey = null;
+ var histNav = false;
+
if( e.kMap( "Tab" ) )
{
InputKey = "^I";
@@ -106,8 +118,15 @@
}
else if( e.kMap( "BS" ) )
{
+ if( this.__curPos == 1 && 1 < this.__command.length )
+ return false;
+
this.__command.splice( --this.__curPos, 1 );
- if( this.__command.length == 0 ) return true;
+ if( this.__command.length == 0 )
+ {
+ e.cancel();
+ return true;
+ }
}
else if( e.kMap( "Del" ) )
{
@@ -115,23 +134,56 @@
}
else if( e.kMap( "Enter" ) )
{
+ this.__process();
return true;
}
- else if( e.kMap( "Up" ) ) // History navigations
- {
- }
- else if( e.kMap( "Down" ) )
- {
- }
else if( e.kMap( "Left" ) )
{
- if( 0 < this.__curPos ) this.__curPos --;
+ if( 1 < this.__curPos ) this.__curPos --;
}
else if( e.kMap( "Right" ) )
{
if( this.__curPos < this.__command.length )
this.__curPos ++;
}
+
+ // History stepping
+ else if( histNav = e.kMap( "Up" ) ) // History navigations
+ {
+ if( !this.__currentCommand )
+ {
+ this.__currentCommand = this.__command;
+ }
+
+ var n = this.__hist.prev( this.__currentCommand );
+
+ if( n )
+ {
+ this.__command = n;
+ this.__curPos = n.length;
+ }
+ else
+ {
+ beep();
+ }
+ }
+ else if( histNav = e.kMap( "Down" ) )
+ {
+ var n = this.__hist.next( this.__currentCommand );
+
+ if( n )
+ {
+ this.__command = n;
+ this.__curPos = n.length;
+ }
+ else if( this.__currentCommand )
+ {
+ this.__command = this.__currentCommand;
+ this.__currentCommand = null;
+ }
+
+ else beep();
+ }
else
{
InputKey = e.key;
@@ -142,9 +194,22 @@
this.__command.splice( this.__curPos ++, 0, InputKey );
}
+ if( !histNav )
+ {
+ this.__hist.reset();
+ if( this.__currentCommand ) this.__currentCommand = this.__command;
+ }
+
+ e.cancel();
+
var feeder = this.__cursor.feeder;
feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
- }
+ };
+
+ Command.prototype.__process = function()
+ {
+ this.__hist.push( this.__command );
+ };
- ns[ NS_EXPORT ]( EX_CLASS, "Search", Search );
+ ns[ NS_EXPORT ]( EX_CLASS, "Command", Command );
})();
diff --git a/botanjs/src/Components/Vim/State/History.js b/botanjs/src/Components/Vim/State/History.js
new file mode 100644
index 0000000..18c67be
--- /dev/null
+++ b/botanjs/src/Components/Vim/State/History.js
@@ -0,0 +1,96 @@
+(function(){
+ var ns = __namespace( "Components.Vim.State" );
+
+ /** @type {System.Debug} */
+ var debug = __import( "System.Debug" );
+
+ // private static
+ var Zones = {};
+
+ var PartialBA = function( a, b )
+ {
+ var l = b.length;
+ if( a.length < l ) return false;
+
+ for( var i = 0; i < l; i ++ )
+ {
+ if( a[ i ] != b[ i ] ) return false;
+ }
+
+ return true;
+ };
+
+ var ExactAB = function( a, b )
+ {
+ var l = a.length < b.length ? b.length : a.length;
+ for( var i = 0; i < l; i ++ )
+ {
+ if( a[ i ] != b[ i ] ) return false;
+ }
+
+ return true;
+ }
+
+ var History = function( z )
+ {
+ if( !Zones[ z ] ) Zones[ z ] = [];
+
+ this.__pi = 0;
+ this.__zone = Zones[ z ];
+ this.reset();
+ };
+
+ History.prototype.push = function( stack )
+ {
+ if( this.__zone.length
+ && ExactAB( this.__zone[ this.__zone.length - 1 ], stack )
+ ) {
+ debug.Info( "This is the previous command, skipping" );
+ return;
+ }
+ this.__zone.push( stack );
+ };
+
+ History.prototype.prev = function( stack )
+ {
+ if( this.__zone.length <= this.__i ) this.reset();
+
+ while( -1 < this.__i )
+ {
+ var st = this.__zone[ this.__i -- ];
+ if( st && PartialBA( st, stack ) )
+ {
+ return st.slice();
+ }
+ }
+
+ return null;
+ };
+
+ History.prototype.next = function( stack )
+ {
+ if( this.__i < 0 )
+ {
+ this.__i ++;
+ this.next( stack );
+ }
+
+ while( this.__i < this.__zone.length )
+ {
+ var st = this.__zone[ this.__i ++ ];
+ if( st && PartialBA( st, stack ) )
+ {
+ return st.slice();
+ }
+ }
+
+ return null;
+ };
+
+ History.prototype.reset = function()
+ {
+ this.__i = this.__zone.length - 1;
+ };
+
+ ns[ NS_EXPORT ]( EX_CLASS, "History", History );
+})();
diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js
index c5480ec..ee76302 100644
--- a/botanjs/src/Components/Vim/VimArea.js
+++ b/botanjs/src/Components/Vim/VimArea.js
@@ -2,18 +2,18 @@
var ns = __namespace( "Components.Vim" );
/** @type {Dandelion.IDOMElement} */
- var IDOMElement = __import( "Dandelion.IDOMElement" );
+ var IDOMElement = __import( "Dandelion.IDOMElement" );
/** @type {System.utils.DataKey} */
- var DataKey = __import( "System.utils.DataKey" );
+ var DataKey = __import( "System.utils.DataKey" );
/** @type {System.Cycle} */
- var Cycle = __import( "System.Cycle" );
+ var Cycle = __import( "System.Cycle" );
/** @type {System.Debug} */
- var debug = __import( "System.Debug" );
+ var debug = __import( "System.Debug" );
/** @type {Components.Vim.State.Registers} */
- var Registers = __import( "Components.Vim.State.Registers" );
+ var Registers = __import( "Components.Vim.State.Registers" );
/** @type {Components.Vim.Syntax.Analyzer} */
- var SyntaxAnalyzer = __import( "Components.Vim.Syntax.Analyzer" );
+ var SyntaxAnalyzer = __import( "Components.Vim.Syntax.Analyzer" );
/** @type {Components.Vim.LineFeeder} */
var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" );
@@ -96,7 +96,7 @@
// Content feeder
var cfeeder = new LineFeeder( cRange, c );
- var contentAnalyzer = new SyntaxAnalyzer( cfeeder );
+ var contentAnalyzer = new SyntaxAnalyzer( cfeeder );
// Feed the contents to content feeder
// This "\n" fixes the last line "\n" not displaying
@@ -136,7 +136,7 @@
Update();
this.contentFeeder = cfeeder;
- this.contentAnalyzer = contentAnalyzer;
+ this.contentAnalyzer = contentAnalyzer;
this.statusFeeder = sfeeder;
this.statusBar = statusBar;
this.registers = new Registers();
diff --git a/botanjs/src/externs/Components.Vim.Controls.InputEvent.js b/botanjs/src/externs/Components.Vim.Controls.InputEvent.js
index afe109d..6678a27 100644
--- a/botanjs/src/externs/Components.Vim.Controls.InputEvent.js
+++ b/botanjs/src/externs/Components.Vim.Controls.InputEvent.js
@@ -11,7 +11,11 @@ Components.Vim.Controls.InputEvent.key;
Components.Vim.Controls.InputEvent.ModKeys;
/** @type Boolean */
Components.Vim.Controls.InputEvent.Escape;
+/** @type Boolean */
+Components.Vim.Controls.InputEvent.canceled;
/** @type Number */
Components.Vim.Controls.InputEvent.keyCode;
/** @type Function */
Components.Vim.Controls.InputEvent.kMap;
+/** @type Function */
+Components.Vim.Controls.InputEvent.cancel;
diff --git a/botanjs/src/externs/Components.Vim.State.History.js b/botanjs/src/externs/Components.Vim.State.History.js
new file mode 100644
index 0000000..f28f348
--- /dev/null
+++ b/botanjs/src/externs/Components.Vim.State.History.js
@@ -0,0 +1,9 @@
+/** @constructor */
+Components.Vim.State.History = function(){};
+
+/** @type Function */
+Components.Vim.State.History.push;
+/** @type Function */
+Components.Vim.State.History.prev;
+/** @type Function */
+Components.Vim.State.History.next;