DELETE command in VISUAL, generalized Stator Obj

This commit is contained in:
斟酌 鵬兄 2016-03-23 03:15:02 +08:00
parent 5f5e0604fa
commit 78f8a20a5d
10 changed files with 241 additions and 134 deletions

View File

@ -1,13 +1,24 @@
(function(){ (function(){
var ns = __namespace( "Components.Vim.Actions" ); var ns = __namespace( "Components.Vim.Actions" );
/** @type {System.Debug} */
var debug = __import( "System.Debug" );
/** @type {Components.Vim.State.Stator} */
var Stator = __import( "Components.Vim.State.Stator" );
/** @type {Components.Vim.State.Stack} */
var Stack = __import( "Components.Vim.State.Stack" );
var Mesg = __import( "Components.Vim.Message" ); var Mesg = __import( "Components.Vim.Message" );
var occurence = __import( "System.utils.Perf.CountSubstr" );
/** @type {Components.Vim.Cursor.IAction} */ /** @type {Components.Vim.Cursor.IAction} */
var DELETE = function( Cursor ) var DELETE = function( Cursor )
{ {
/** @type {Components.Vim.Cursor} */ /** @type {Components.Vim.Cursor} */
this.__cursor = Cursor; this.__cursor = Cursor;
this.__nline = 0;
}; };
DELETE.prototype.allowMovement = true; DELETE.prototype.allowMovement = true;
@ -17,15 +28,65 @@
}; };
DELETE.prototype.handler = function( e ) DELETE.prototype.handler = function( e, sp )
{ {
e.preventDefault(); e.preventDefault();
/** @type {Components.Vim.State.Registers} */
var reg = e.target.registers;
var cur = this.__cursor;
var feeder = cur.feeder;
var c = feeder.content;
var s = sp;
var e = cur.aPos;
if( e < s )
{
s = cur.aPos;
e = sp;
}
var removed = c.substring( s, e + 1 );
reg.change( removed );
this.__nline = occurence( removed, "\n" );
feeder.content = c.substring( 0, s ) + c.substring( e + 1 );
var stator = new Stator( cur, s );
var stack = new Stack();
c = c[ e + 1 ];
if( c == "\n" || c == undefined )
{
cur.suppressEvent();
cur.moveX( -1 );
cur.unsuppressEvent();
}
var f = stator.save( 0, removed );
stack.store( function() {
f();
// Offset correction after REDO / UNDO
cur.moveX( 1 );
} );
cur.rec.record( stack );
feeder.pan();
}; };
DELETE.prototype.getMessage = function() DELETE.prototype.getMessage = function()
{ {
return "<TODO> DELETE COMMAND"; if( this.__nline )
{
return Mesg( "LINE_FEWER", this.__nline );
}
return "";
}; };
ns[ NS_EXPORT ]( EX_CLASS, "DELETE", DELETE ); ns[ NS_EXPORT ]( EX_CLASS, "DELETE", DELETE );

View File

@ -3,6 +3,8 @@
/** @type {Components.Vim.State.Stack} */ /** @type {Components.Vim.State.Stack} */
var Stack = __import( "Components.Vim.State.Stack" ); var Stack = __import( "Components.Vim.State.Stack" );
/** @type {Components.Vim.State.Stator} */
var Stator = __import( "Components.Vim.State.Stator" );
/** @type {System.Debug} */ /** @type {System.Debug} */
var debug = __import( "System.Debug" ); var debug = __import( "System.Debug" );
@ -27,7 +29,7 @@
/** @type {Components.Vim.Cursor} */ /** @type {Components.Vim.Cursor} */
this.__cursor = Cursor; this.__cursor = Cursor;
this.__startState = this.__saveCur(); this.__Stator = new Stator( Cursor );
// Initialize this stack // Initialize this stack
this.__rec( "", true ); this.__rec( "", true );
@ -35,66 +37,12 @@
INSERT.prototype.allowMovement = false; INSERT.prototype.allowMovement = false;
INSERT.prototype.__saveCur = function()
{
var c = this.__cursor;
var obj = {
p: c.P
, x: c.X
, y: c.Y
, px: c.feeder.panX
, py: c.feeder.panY
};
if( 0 < obj.x )
{
obj.p -= 1;
obj.x -= 1;
}
return obj;
}
INSERT.prototype.dispose = function() INSERT.prototype.dispose = function()
{ {
this.__cursor.moveX( -1 ); this.__cursor.moveX( -1 );
this.__rec( "", true ); this.__rec( "", true );
}; };
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 sSt = this.__startState;
var eSt = this.__saveCur();
var st = sSt;
// Calling this repeatedly will swap between UNDO / REDO state
return function() {
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;
cur.PStart = st.p;
cur.PEnd = st.p + 1;
cur.X = st.x;
cur.Y = st.y;
feeder.panX = st.px;
feeder.panY = st.py;
feeder.pan();
st = ( st == sSt ) ? eSt : sSt;
};
};
INSERT.prototype.__rec = function( c, newRec ) INSERT.prototype.__rec = function( c, newRec )
{ {
if( newRec || !this.__stack ) if( newRec || !this.__stack )
@ -107,7 +55,7 @@
) return; ) return;
this.__stack.store( this.__stack.store(
this.__storeState() this.__Stator.save( this.__insertLength, this.__contentUndo )
); );
this.__cursor.rec.record( this.__stack ); this.__cursor.rec.record( this.__stack );
@ -116,7 +64,6 @@
this.__insertLength = 0; this.__insertLength = 0;
this.__contentUndo = ""; this.__contentUndo = "";
this.__stack = new Stack(); this.__stack = new Stack();
this.__startPosition = this.__cursor.aPos;
} }
if( c == "\n" ) if( c == "\n" )
@ -132,9 +79,9 @@
var cur = this.__cursor; var cur = this.__cursor;
var feeder = cur.feeder; var feeder = cur.feeder;
switch( e.keyCode ) // Backspace
if( e.kMap( "BS" ) )
{ {
case 8: // Backspace
var oY = feeder.panY + cur.Y; var oY = feeder.panY + cur.Y;
if( cur.X == 0 && feeder.panY == 0 && cur.Y == 0 ) return; if( cur.X == 0 && feeder.panY == 0 && cur.Y == 0 ) return;
@ -145,19 +92,15 @@
if( this.__insertLength <= 0 ) if( this.__insertLength <= 0 )
{ {
this.__contentUndo = feeder.content.substr( f, 1 ) + this.__contentUndo; this.__contentUndo = feeder.content.substr( f, 1 ) + this.__contentUndo;
this.__startPosition --;
}
else
{
this.__insertLength --; this.__insertLength --;
} }
feeder.content = feeder.content =
feeder.content.substring( 0, f ) feeder.content.substring( 0, f )
+ feeder.content.substring( f + 1 ); + feeder.content.substring( f + 1 );
}
break; else if( e.kMap( "Del" ) )
case 46: // Delete {
var f = cur.aPos; var f = cur.aPos;
this.__contentUndo += feeder.content.substr( f, 1 ); this.__contentUndo += feeder.content.substr( f, 1 );
@ -165,12 +108,8 @@
feeder.content = feeder.content =
feeder.content.substring( 0, f ) feeder.content.substring( 0, f )
+ feeder.content.substring( f + 1 ); + feeder.content.substring( f + 1 );
break;
default:
// Do nothing
return;
} }
else return;
feeder.pan(); feeder.pan();
feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );

View File

@ -23,6 +23,7 @@
this.__leaveMesg = ""; this.__leaveMesg = "";
Cursor.blink = false; Cursor.blink = false;
Cursor.pSpace = true;
}; };
VISUAL.prototype.allowMovement = true; VISUAL.prototype.allowMovement = true;
@ -31,6 +32,7 @@
{ {
this.__msg = this.__leaveMesg; this.__msg = this.__leaveMesg;
this.__cursor.blink = true; this.__cursor.blink = true;
this.__cursor.pSpace = false;
this.__cursor.PStart = this.__selStart; this.__cursor.PStart = this.__selStart;
this.__cursor.PEnd = this.__selStart + 1; this.__cursor.PEnd = this.__selStart + 1;
}; };
@ -41,27 +43,18 @@
if( e.ModKeys ) return; if( e.ModKeys ) return;
var cur = this.__cursor;
var Action = null; var Action = null;
switch( true ) switch( true )
{ {
case e.kMap( "y" ): case e.kMap( "y" ):
Action = new YANK( this.__cursor ); Action = new YANK( cur );
break; break;
case e.kMap( "d" ): case e.kMap( "d" ):
Action = new DELETE( this.__cursor ); Action = new DELETE( cur );
break; break;
} }
if( Action )
{
Action.handler( e );
this.__leaveMesg = Action.getMessage();
Action.dispose();
return true;
}
var cur = this.__cursor;
var prevPos = this.__start; var prevPos = this.__start;
var newPos = cur.PStart; var newPos = cur.PStart;
@ -78,6 +71,18 @@
this.__selStart = prevPos; this.__selStart = prevPos;
} }
if( Action )
{
cur.suppressEvent();
Action.handler( e, this.__startaP );
this.__leaveMesg = Action.getMessage();
Action.dispose();
cur.unsuppressEvent();
this.__selStart = cur.PStart;
return true;
}
cur.PStart = prevPos; cur.PStart = prevPos;
cur.PEnd = newPos; cur.PEnd = newPos;
}; };

View File

@ -14,6 +14,7 @@
var KEY_ALT = 18; var KEY_ALT = 18;
var BACKSPACE = 8; var BACKSPACE = 8;
var DELETE = 46;
var _0 = 48; var _1 = 49; var _2 = 50; var _3 = 51; var _4 = 52; 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 _5 = 53; var _6 = 54; var _7 = 55; var _8 = 56; var _9 = 57;
@ -31,6 +32,8 @@
var F6 = 117; var F7 = 118; var F8 = 119; var F9 = 120; var F10 = 121; var F6 = 117; var F7 = 118; var F8 = 119; var F9 = 120; var F10 = 121;
var F11 = 122; var F12 = 123; var F11 = 122; var F12 = 123;
var COMMA = 188; var FULLSTOP = 190;
var __maps = {}; var __maps = {};
var Map = function( str ) var Map = function( str )
{ {
@ -62,6 +65,9 @@
var kCode; var kCode;
switch( sCode ) switch( sCode )
{ {
case "BS": kCode = Mod + BACKSPACE; break;
case "Del": kCode = Mod + DELETE; break;
case "A": Mod = SHIFT; case "a": kCode = Mod + A; break; case "A": Mod = SHIFT; case "a": kCode = Mod + A; break;
case "B": Mod = SHIFT; case "b": kCode = Mod + B; break; case "B": Mod = SHIFT; case "b": kCode = Mod + B; break;
case "C": Mod = SHIFT; case "c": kCode = Mod + C; break; case "C": Mod = SHIFT; case "c": kCode = Mod + C; break;
@ -99,8 +105,11 @@
case "*": Mod = SHIFT; case "8": kCode = Mod + _8; break; case "*": Mod = SHIFT; case "8": kCode = Mod + _8; break;
case "(": Mod = SHIFT; case "9": kCode = Mod + _9; break; case "(": Mod = SHIFT; case "9": kCode = Mod + _9; break;
case ")": Mod = SHIFT; case "0": kCode = Mod + _0; break; case ")": Mod = SHIFT; case "0": kCode = Mod + _0; break;
case "<": Mod = SHIFT; case ",": kCode = Mod + COMMA; break;
case ">": Mod = SHIFT; case ".": kCode = Mod + FULLSTOP; break;
default: default:
throw new Error( "No such keys: " + str ); throw new Error( "Unsupport keys: " + str );
} }
return __maps[ str ] = kCode; return __maps[ str ] = kCode;
@ -209,7 +218,7 @@
var ccur = this.__ccur; var ccur = this.__ccur;
var x = ccur.X; var x = ccur.X;
ccur.moveX( a, b, c ); ccur.moveX( a, b, c || ccur.pSpace );
if( ccur.X == x ) beep(); if( ccur.X == x ) beep();
}; };
@ -245,7 +254,7 @@
var cursorHandled = true; var cursorHandled = true;
switch( kCode ) switch( kCode )
{ {
case BACKSPACE: this.__cMoveX( -1, true ); break; // Backspace, go back 1 char, regardless of line case BACKSPACE: this.__cMoveX( -1, true ); break; // Backspace, go back 1 char
case H: this.__cMoveX( -1 ); break; // Left case H: this.__cMoveX( -1 ); break; // Left
case L: this.__cMoveX( 1 ); break; // Right case L: this.__cMoveX( 1 ); break; // Right
case K: this.__cMoveY( -1 ); break; // Up case K: this.__cMoveY( -1 ); break; // Up
@ -259,7 +268,7 @@
ccur.lineStart(); ccur.lineStart();
break; break;
case SHIFT + _4: // $, End case SHIFT + _4: // $, End
ccur.lineEnd(); ccur.lineEnd( ccur.pSpace );
break; break;
case SHIFT + G: // Goto last line case SHIFT + G: // Goto last line
ccur.moveY( Number.MAX_VALUE ); ccur.moveY( Number.MAX_VALUE );
@ -293,10 +302,10 @@
* */ * */
Controls.prototype.handler = function( sender, e ) Controls.prototype.handler = function( sender, e )
{ {
// Neve capture these keys // Never capture these keys
if( e.ModKeys if( e.keyCode == ( ALT + D )
// F2 - F12 // F2 - F12
|| ( F1 < e.keyCode && e.keyCode < 124 ) || ( F1 < e.keyCode && e.keyCode <= F12 )
) return; ) return;
// Clear composite command // Clear composite command
@ -334,34 +343,30 @@
return; return;
} }
if( this.__cursorCommand( e ) )
{
e.preventDefault(); e.preventDefault();
return;
}
if( this.__actionCommand( e ) ) if( this.__cursorCommand( e ) ) return;
{ if( this.__actionCommand( e ) ) return;
e.preventDefault();
return;
}
}; };
var InputEvent = function( e ) var InputEvent = function( sender, e )
{ {
this.__e = e; this.__e = e;
this.__target = sender;
var c = this.__e.keyCode; var c = this.__e.keyCode;
this.__escape = c == ESC || ( e.ctrlKey && c == C ); this.__escape = c == ESC || ( e.ctrlKey && c == C );
this.__kCode = c this.__kCode = c
+ ( e.shiftKey || e.getModifierState( "CapsLock" ) ? SHIFT : 0 ) + ( e.shiftKey || e.getModifierState( "CapsLock" ) ? SHIFT : 0 )
+ ( e.ctrlKey ? CTRL : 0 ); + ( e.ctrlKey ? CTRL : 0 )
+ ( e.altKey ? ALT : 0 );
this.__modKeys = c == KEY_SHIFT || c == KEY_CTRL || c == KEY_ALT; this.__modKeys = c == KEY_SHIFT || c == KEY_CTRL || c == KEY_ALT;
this.__key = e.key; this.__key = e.key;
}; };
__readOnly( InputEvent.prototype, "target", function() { return this.__target; } );
__readOnly( InputEvent.prototype, "key", function() { return this.__key; } ); __readOnly( InputEvent.prototype, "key", function() { return this.__key; } );
__readOnly( InputEvent.prototype, "keyCode", function() { return this.__kCode; } ); __readOnly( InputEvent.prototype, "keyCode", function() { return this.__kCode; } );
__readOnly( InputEvent.prototype, "ModKeys", function() { return this.__modKeys; } ); __readOnly( InputEvent.prototype, "ModKeys", function() { return this.__modKeys; } );

View File

@ -80,6 +80,9 @@
this.action = null; this.action = null;
this.blink = true; this.blink = true;
this.pSpace = false;
this.__suppEvt = 0;
}; };
// Set by VimArea // Set by VimArea
@ -118,12 +121,12 @@
// Include empty lines befor cursor end // Include empty lines befor cursor end
if( ( phantomSpace && cLen - 1 <= x ) || ( cLen == 1 && c == undefined ) ) if( ( phantomSpace && cLen - 1 <= x ) || ( cLen == 1 && c == undefined ) )
{ {
x = d > 0 ? cLen - 1 : 0; x = 0 < d ? cLen - 1 : 0;
} }
// ( 2 < cLen ) Exclude empty lines at cursor end // ( 2 < cLen ) Exclude empty lines at cursor end
else if( ( 2 < cLen && x == cLen - 1 && c == " " ) || c == undefined ) else if( ( 2 <= cLen && x == cLen - 1 && c == " " ) || c == undefined )
{ {
x = d > 0 ? cLen - 2 : 0; x = 0 < d ? cLen - 2 : 0;
} }
else if( c == "\n" ) else if( c == "\n" )
{ {
@ -158,6 +161,16 @@
this.PEnd = P + 1; this.PEnd = P + 1;
this.__p = P; this.__p = P;
this.__fireUpdate();
};
Cursor.prototype.__fireUpdate = function()
{
if( 0 < this.__suppEvt )
{
debug.Info( "Event suppressed, suppression level is: " + this.__suppEvt );
return;
}
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
}; };
@ -270,7 +283,7 @@
this.action = new (Actions[ name ])( this ); this.action = new (Actions[ name ])( this );
this.__pulseMsg = null; this.__pulseMsg = null;
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); this.__fireUpdate();
}; };
Cursor.prototype.closeAction = function() Cursor.prototype.closeAction = function()
@ -280,7 +293,7 @@
this.__pulseMsg = this.action.getMessage(); this.__pulseMsg = this.action.getMessage();
this.action = null; this.action = null;
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); this.__fireUpdate();
}; };
// Open, Run, then close an action // Open, Run, then close an action
@ -292,9 +305,12 @@
this.__pulseMsg = action.getMessage(); this.__pulseMsg = action.getMessage();
action.dispose(); action.dispose();
this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) ); this.__fireUpdate();
}; };
Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; };
Cursor.prototype.unsuppressEvent = function() { -- this.__suppEvt; };
Cursor.prototype.getLine = function() Cursor.prototype.getLine = function()
{ {
var feeder = this.feeder; var feeder = this.feeder;

View File

@ -0,0 +1,71 @@
(function(){
var ns = __namespace( "Components.Vim.State" );
var Stator = function( cur, start )
{
this.__cursor = cur;
this.__startPosition = start == undefined ? cur.aPos : start;
this.__startState = this.__saveCur();
};
Stator.prototype.save = function( insertLength, contentUndo )
{
var cur = this.__cursor;
var feeder = cur.feeder;
var startPos = this.__startPosition;
if( insertLength < 0 )
{
startPos += insertLength;
insertLength = 0;
}
var sSt = this.__startState;
var eSt = this.__saveCur();
var st = sSt;
// Calling this repeatedly will swap between UNDO / REDO state
return function() {
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;
cur.PStart = st.p;
cur.PEnd = st.p + 1;
cur.X = st.x;
cur.Y = st.y;
feeder.panX = st.px;
feeder.panY = st.py;
feeder.pan();
st = ( st == sSt ) ? eSt : sSt;
};
};
Stator.prototype.__saveCur = function()
{
var c = this.__cursor;
var obj = {
p: c.PStart
, x: c.X
, y: c.Y
, px: c.feeder.panX
, py: c.feeder.panY
};
if( 0 < obj.x )
{
obj.p -= 1;
obj.x -= 1;
}
return obj;
};
ns[ NS_EXPORT ]( EX_CLASS, "Stator", Stator );
})();

View File

@ -32,7 +32,7 @@
if ( e.keyCode ) code = e.keyCode; if ( e.keyCode ) code = e.keyCode;
else if ( e.which ) code = e.which; else if ( e.which ) code = e.which;
handler( sender, new InputEvent( e ) ); handler( sender, new InputEvent( sender, e ) );
}; };
}; };

View File

@ -17,6 +17,8 @@
, "UNDO_LIMIT": "Already at oldest change" , "UNDO_LIMIT": "Already at oldest change"
, "REDO_LIMIT": "Already at newest change" , "REDO_LIMIT": "Already at newest change"
, "LINE_FEWER": "%1 fewer lines"
}; };
var errors = { var errors = {

View File

@ -1,6 +1,8 @@
/** @constructor */ /** @constructor */
Components.Vim.Controls.InputEvent = function(){}; Components.Vim.Controls.InputEvent = function(){};
/** @type {Components.Vim.VimArea} */
Components.Vim.Controls.InputEvent.target;
/** @type String */ /** @type String */
Components.Vim.Controls.InputEvent.key; Components.Vim.Controls.InputEvent.key;
/** @type Boolean */ /** @type Boolean */

View File

@ -26,9 +26,15 @@ Components.Vim.Cursor.openAction;
Components.Vim.Cursor.openRunAction; Components.Vim.Cursor.openRunAction;
/** @type Function */ /** @type Function */
Components.Vim.Cursor.closeAction; Components.Vim.Cursor.closeAction;
/** @type Function */
Components.Vim.Cursor.suppressEvent;
/** @type Function */
Components.Vim.Cursor.unsuppressEvent;
/** @type {Boolean} */ /** @type {Boolean} */
Components.Vim.Cursor.blink; Components.Vim.Cursor.blink;
/** @type {Boolean} */
Components.Vim.Cursor.pSpace;
/** @type {Array} */ /** @type {Array} */
Components.Vim.Cursor.lineBuffers; Components.Vim.Cursor.lineBuffers;
/** @type Number */ /** @type Number */