From 593462f1e5b678707ac33ff027f9cc466b447671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sun, 3 Apr 2016 08:01:48 +0800 Subject: [PATCH 1/9] what?? --- botanjs/src/Components/Vim/Actions/BUFFERS.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/botanjs/src/Components/Vim/Actions/BUFFERS.js b/botanjs/src/Components/Vim/Actions/BUFFERS.js index e02dc78..9248877 100644 --- a/botanjs/src/Components/Vim/Actions/BUFFERS.js +++ b/botanjs/src/Components/Vim/Actions/BUFFERS.js @@ -40,6 +40,9 @@ var cur = this.__cursor; var Vim = cur.Vim; + + /** @type {Components.Vim.VimArea} */ + var VimArea = shadowImport( "Components.Vim.VimArea" ); var Insts = VimArea.Instances; From 2b3eb9db31385a85e68932bad58415fb6809ba15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sun, 3 Apr 2016 09:24:14 +0800 Subject: [PATCH 2/9] JOIN_LINES for single action --- .../src/Components/Vim/Actions/JOIN_LINES.js | 89 +++++++++++++++++++ botanjs/src/Components/Vim/Controls.js | 1 + 2 files changed, 90 insertions(+) create mode 100644 botanjs/src/Components/Vim/Actions/JOIN_LINES.js diff --git a/botanjs/src/Components/Vim/Actions/JOIN_LINES.js b/botanjs/src/Components/Vim/Actions/JOIN_LINES.js new file mode 100644 index 0000000..4f21af6 --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/JOIN_LINES.js @@ -0,0 +1,89 @@ +(function(){ + 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 beep = __import( "Components.Vim.Beep" ); + var Mesg = __import( "Components.Vim.Message" ); + + var occurance = __import( "System.utils.Perf.CountSubstr" ); + + /** @type {Components.Vim.IAction} */ + var JOIN_LINES = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + this.__msg = ""; + Cursor.suppressEvent(); + }; + + JOIN_LINES.prototype.dispose = function() + { + this.__cursor.unsuppressEvent(); + }; + + JOIN_LINES.prototype.handler = function( e, range ) + { + e.preventDefault(); + + var cur = this.__cursor; + var feeder = cur.feeder; + + var start; + var end; + + var stack; + var stator; + + var contentUndo; + if( range ) + { + start = range.start; + end = range.close; + } + else + { + var oPos = cur.aPos; + cur.lineEnd( true ); + stator = new Stator( cur ); + start = cur.aPos; + cur.moveY( 1 ); + cur.lineStart(); + end = cur.aPos; + + // This happens on the last line + if( end < start ) + { + cur.moveTo( oPos ); + beep(); + return true; + } + + var content = feeder.content; + + contentUndo = feeder.content.substring( start, end ); + feeder.content = content.substring( 0, start ) + " " + content.substr( end ); + } + + feeder.pan(); + + cur.moveTo( start ); + + var stack = new Stack(); + stack.store( stator.save( 1, contentUndo ) ); + + cur.rec.record( stack ); + }; + + JOIN_LINES.prototype.getMessage = function() + { + return this.__msg; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "JOIN_LINES", JOIN_LINES ); +})(); diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index b52b7c2..2ee60c4 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -262,6 +262,7 @@ case SHIFT + I: // Append before the line start, after spaces break; case SHIFT + J: // Join lines + ccur.openRunAction( "JOIN_LINES", e ); break; case SHIFT + K: // Find the manual entry break; From 4529f4b4a1c3292ccc9eb05f81d2c6576a6475ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sun, 3 Apr 2016 19:46:35 +0800 Subject: [PATCH 3/9] Added f, t movements --- botanjs/src/Components/Vim/Actions/TO.js | 82 ++++++++++++++++++++++++ botanjs/src/Components/Vim/Controls.js | 35 +++++++++- botanjs/src/Components/Vim/Cursor.js | 1 - 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 botanjs/src/Components/Vim/Actions/TO.js diff --git a/botanjs/src/Components/Vim/Actions/TO.js b/botanjs/src/Components/Vim/Actions/TO.js new file mode 100644 index 0000000..b1a0dbc --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/TO.js @@ -0,0 +1,82 @@ +(function(){ + var ns = __namespace( "Components.Vim.Actions" ); + + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + var beep = __import( "Components.Vim.Beep" ); + + /** @type {Components.Vim.IAction} */ + var TO = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + this.__msg = ""; + Cursor.suppressEvent(); + }; + + TO.prototype.dispose = function() + { + this.__cursor.unsuppressEvent(); + }; + + TO.prototype.handler = function( em, et ) + { + et.preventDefault(); + + var cur = this.__cursor; + var f = cur.feeder; + var n = cur.getLine().lineNum; + + var p = f.content.indexOf( "\n" ); + for( i = 1; p != -1 && i < n; i ++ ) + { + p = f.content.indexOf( "\n", p + 1 ); + } + + var upperLimit = f.content.indexOf( "\n", p + 1 ); + + if( 0 < n ) p ++; + + var lowerLimmit = p; + + var cX = cur.X; + var tX = cX; + + var Char = et.key; + if( et.kMap( "Tab" ) ) + { + Char = "\t"; + } + + if( 1 < Char.length ) + { + beep(); + return; + } + + // Forward + if( em.kMap( "t" ) || em.kMap( "f" ) ) + { + tX = f.content.indexOf( Char, p + cX + 1 ); + } + // backward + else + { + tX = f.content.lastIndexOf( Char, p + cX - 1 ); + } + + if( lowerLimmit <= tX && tX < upperLimit ) + { + cur.moveX( tX - lowerLimmit - cX ); + } + else beep(); + }; + + TO.prototype.getMessage = function() + { + return this.__msg; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "TO", TO ); +})(); diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index 2ee60c4..6b9efe6 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -47,6 +47,8 @@ var COMMA = 188; var FULLSTOP = 190; var SLASH = 191; var BACK_SLASH = 220; + var ANY_KEY = -1; + var __maps = {}; var Map = function( str ) { @@ -169,8 +171,9 @@ { var compReg = this.__compositeReg[i]; var keys = compReg.keys; + var key = keys[ compReg.i ++ ]; - if( keys[ compReg.i ++ ] == kCode ) + if( key == ANY_KEY || key == kCode ) { if( compReg.i == keys.length ) { @@ -405,8 +408,38 @@ ); break; + + + case SHIFT + T: // To case T: // To + this.__cMovement = true; + + this.__composite( e, function( e2 ) { + var oX = ccur.X; + ccur.openRunAction( "TO", e, e2 ); + + if( ccur.X < oX ) + { + ccur.moveX( 1 ); + } + else if( oX < ccur.X ) + { + ccur.moveX( -1 ); + } + }, ANY_KEY ); + break; + case SHIFT + F: // To + case F: // To + this.__cMovement = true; + + this.__composite( e, function( e2 ) { + ccur.openRunAction( "TO", e, e2 ); + }, ANY_KEY ); + + break; + + case I: // In between boundary if( !ccur.action ) { diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js index 2fd9833..3eaaac0 100644 --- a/botanjs/src/Components/Vim/Cursor.js +++ b/botanjs/src/Components/Vim/Cursor.js @@ -137,7 +137,6 @@ this.moveX( - Number.MAX_VALUE ); this.moveX( jumpX, false, phantomSpace ); - }; // 0 will be treated as default ( 1 ) From 3d2f3b889a8456a6fad1c353e3a1faea1ba9fe3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sun, 3 Apr 2016 20:19:45 +0800 Subject: [PATCH 4/9] Used the wrong movement function --- botanjs/src/Components/Vim/Actions/TO.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/botanjs/src/Components/Vim/Actions/TO.js b/botanjs/src/Components/Vim/Actions/TO.js index b1a0dbc..1ff0bcd 100644 --- a/botanjs/src/Components/Vim/Actions/TO.js +++ b/botanjs/src/Components/Vim/Actions/TO.js @@ -28,8 +28,8 @@ var f = cur.feeder; var n = cur.getLine().lineNum; - var p = f.content.indexOf( "\n" ); - for( i = 1; p != -1 && i < n; i ++ ) + var p = 0; + for( i = 0; p != -1 && i < n; i ++ ) { p = f.content.indexOf( "\n", p + 1 ); } @@ -68,7 +68,7 @@ if( lowerLimmit <= tX && tX < upperLimit ) { - cur.moveX( tX - lowerLimmit - cX ); + cur.moveTo( tX ); } else beep(); }; From fbb4bae316c4015b217a3f2f24045919a12232ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sun, 3 Apr 2016 20:55:36 +0800 Subject: [PATCH 5/9] Added b & w --- botanjs/src/Components/Vim/Actions/WORD.js | 74 ++++++++++++++++++++++ botanjs/src/Components/Vim/Controls.js | 13 +++- botanjs/src/Components/Vim/Syntax/Word.js | 4 ++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 botanjs/src/Components/Vim/Actions/WORD.js diff --git a/botanjs/src/Components/Vim/Actions/WORD.js b/botanjs/src/Components/Vim/Actions/WORD.js new file mode 100644 index 0000000..7d69be4 --- /dev/null +++ b/botanjs/src/Components/Vim/Actions/WORD.js @@ -0,0 +1,74 @@ +(function(){ + var ns = __namespace( "Components.Vim.Actions" ); + + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + + /** @type {Components.Vim.IAction} */ + var WORD = function( Cursor ) + { + /** @type {Components.Vim.Cursor} */ + this.__cursor = Cursor; + this.__msg = ""; + Cursor.suppressEvent(); + }; + + WORD.prototype.dispose = function() + { + this.__cursor.unsuppressEvent(); + }; + + WORD.prototype.handler = function( e ) + { + e.preventDefault(); + + var cur = this.__cursor; + var feeder = cur.feeder; + + var analyzer = cur.Vim.contentAnalyzer; + var p = cur.aPos; + + + var d = 1; + // forward + if( e.kMap( "w" ) || e.kMap( "W" ) ) + { + if( feeder.content[ p + 1 ] == "\n" ) + { + p ++; + } + + var wordRange = analyzer.wordAt( p ); + if( wordRange.open != -1 ) + { + p = wordRange.close + 1; + } + } + // Backward + if( e.kMap( "b" ) || e.kMap( "B" ) ) + { + if( p == 0 ) return; + d = -1; + + var wordRange = analyzer.wordAt( p - 1 ); + if( wordRange.open != -1 ) + { + p = wordRange.open; + } + } + + while( " \t".indexOf( feeder.content[ p ] ) != -1 ) + { + p += d; + } + + cur.moveTo( p ); + }; + + WORD.prototype.getMessage = function() + { + return this.__msg; + }; + + ns[ NS_EXPORT ]( EX_CLASS, "WORD", WORD ); +})(); diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js index 6b9efe6..f38b847 100644 --- a/botanjs/src/Components/Vim/Controls.js +++ b/botanjs/src/Components/Vim/Controls.js @@ -378,7 +378,11 @@ break; case SHIFT + L: // Last line buffer break; - case SHIFT + _6: // ^, Start + + case _0: // Really - line Start + ccur.lineStart(); + break; + case SHIFT + _6: // ^, line Start, XXX: skip tabs ccur.lineStart(); break; case SHIFT + _4: // $, End @@ -439,6 +443,13 @@ break; + case W: // word + case SHIFT + W: + case B: + case SHIFT + B: + ccur.openRunAction( "WORD", e ); + break + case I: // In between boundary if( !ccur.action ) diff --git a/botanjs/src/Components/Vim/Syntax/Word.js b/botanjs/src/Components/Vim/Syntax/Word.js index d879e59..e76818b 100644 --- a/botanjs/src/Components/Vim/Syntax/Word.js +++ b/botanjs/src/Components/Vim/Syntax/Word.js @@ -199,6 +199,10 @@ // C1 Controls and Latin-1 Supplement (Extended ASCII) [ 0x00A1, 0x00AC ], [ 0x00AE, 0x00BF ] ] + , + [ // Spaces & tabs + [ 0x0020, 0x0020 ], [ 0x0009, 0x0009 ] + ] ]; var NUM_KINGDOM = KINGDOMS.length; From a72dcd8ca985ad99b9aa7bea364c9d097476723a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Sun, 3 Apr 2016 23:35:26 +0800 Subject: [PATCH 6/9] Guarding for infinite loop --- botanjs/src/Components/Vim/Actions/FIND.js | 16 ++++++++++++++-- botanjs/src/Components/Vim/_this.js | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/botanjs/src/Components/Vim/Actions/FIND.js b/botanjs/src/Components/Vim/Actions/FIND.js index 86db51d..461ddc4 100644 --- a/botanjs/src/Components/Vim/Actions/FIND.js +++ b/botanjs/src/Components/Vim/Actions/FIND.js @@ -39,7 +39,7 @@ } // The root bracket as back ref 0 - var RegEx = new RegExp( "(" + parsed + ")", "g" ); + var RegEx = new RegExp( "(" + parsed + ")", "gm" ); return RegEx; }; @@ -104,9 +104,20 @@ var FirstHit; var PrevStack = []; + var LoopGuard; while( ( r = search.exec( content ) ) !== null ) { - if( !FirstHit ) FirstHit = r.index; + if( FirstHit == undefined ) + { + FirstHit = r.index; + } + + if( LoopGuard == r.index ) + { + this.__msg = VimError( "EX2", PATTERN.slice( 1 ).join( "" ) ); + return true; + } + if( p < r.index ) { Hit = r.index; @@ -114,6 +125,7 @@ } PrevStack.push( r.index ); + LoopGuard = r.index; } if( e.kMap( "N" ) ) diff --git a/botanjs/src/Components/Vim/_this.js b/botanjs/src/Components/Vim/_this.js index d55ec63..ab26706 100644 --- a/botanjs/src/Components/Vim/_this.js +++ b/botanjs/src/Components/Vim/_this.js @@ -38,6 +38,7 @@ VIMRE_VERSION = "1.0.0b"; // EXtended Errors , "EX1": "Pattern Error( %1 )" + , "EX2": "This pattern is causing infinite loop: %1" , "TODO": "%1 is not implemented yet" , "MISSING_FEATURE": "Sorry, I thought this command wasn't useful enough to implement. Please file a feature request titled \"Implement %1\" in github if you think this is important." From cde4dd8c601226a5fe77c197342a7aa9652a0d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Mon, 4 Apr 2016 00:35:59 +0800 Subject: [PATCH 7/9] Prevent instance init collision --- botanjs/src/Components/Vim/VimArea.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index 3614809..767a4ff 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -44,14 +44,25 @@ /* stage @param {Dandelion.IDOMElement} */ var VimArea = function( stage ) { - if( !stage ) return; + if( !stage ) throw new Error( "Invalid argument" ); + + stage = IDOMElement( stage ); var element = stage.element; - if( element.nodeName != "TEXTAREA" ) + if(!( element && element.nodeName == "TEXTAREA" )) { - debug.Error( "Element is not compatible for VimArea" ); - return; + throw new Error( "This element is not compatible for VimArea" ); + } + + for( var i in Insts ) + { + var inst = Insts[ i ]; + if( inst.stage.element == element ) + { + debug.Info( "Instance exists" ); + return inst; + } } stage.setAttribute( new DataKey( "vimarea", 1 ) ); From 21221a6e4ecffa7d0133e5bb5be6ec229fb8672f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Mon, 4 Apr 2016 02:05:27 +0800 Subject: [PATCH 8/9] Added ability to detect the screen size --- botanjs/src/Components/Vim/VimArea.js | 76 +++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js index 767a4ff..1817deb 100644 --- a/botanjs/src/Components/Vim/VimArea.js +++ b/botanjs/src/Components/Vim/VimArea.js @@ -42,7 +42,7 @@ }; /* stage @param {Dandelion.IDOMElement} */ - var VimArea = function( stage ) + var VimArea = function( stage, detectScreenSize ) { if( !stage ) throw new Error( "Invalid argument" ); @@ -80,10 +80,16 @@ , new EventKey( "Blur", function() { _self.__active = false; } ) ]; - this.__removeText - // Init - this.VisualizeVimFrame( element.value ); + if( detectScreenSize ) + { + var val = element.value; + this.__testScreen(function() { _self.VisualizeVimFrame( val ); }); + } + else + { + this.VisualizeVimFrame( element.value ); + } // Set buffer index this.__instIndex = InstIndex ++; @@ -92,6 +98,68 @@ Insts[ this.__instIndex ] = this; }; + VimArea.prototype.__testScreen = function( handler ) + { + var area = this.stage.element; + area.value = ""; + + var msg = "Please wait while Vim;Re is testing for screen dimensions"; + var m = function() { return msg[ i ++ ] || "."; }; + + var i = 0; + + var oX = area.style.overflowX; + var oY = area.style.overflowY; + + area.style.whiteSpace = "nowrap"; + + var oWidth = area.scrollWidth; + var testWidth = function() + { + area.value += m(); + if( oWidth == area.scrollWidth ) + { + Cycle.next( testWidth ); + } + else + { + var t = ""; + i -= 3; + for( var k = 0; k < i; k ++ ) t += "."; + area.value = t; + + area.style.whiteSpace = ""; + m = function() { return "\n" + t; }; + testHeight(); + } + }; + + testWidth(); + + var oHeight = area.scrollHeight; + + var l = 0; + + var _self = this; + + var testHeight = function() { + area.value += m(); + l ++; + + if( oHeight == area.scrollHeight ) + { + Cycle.next( testHeight ); + } + else + { + _self.rows = l; + _self.cols = i; + + handler(); + } + }; + }; + VimArea.prototype.select = function( sel ) { if( !this.__active ) return; From 05b28e85264368ec0e9df73e78d132665ad6dd32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=9F=E9=85=8C=20=E9=B5=AC=E5=85=84?= Date: Mon, 4 Apr 2016 02:06:57 +0800 Subject: [PATCH 9/9] Human friendly var names --- botanjs/src/System/Cycle/_this.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/botanjs/src/System/Cycle/_this.js b/botanjs/src/System/Cycle/_this.js index f9431a1..f31bb5c 100644 --- a/botanjs/src/System/Cycle/_this.js +++ b/botanjs/src/System/Cycle/_this.js @@ -10,6 +10,12 @@ var tList = []; + var C_CALLBACK = 0; + var C_TIME = 1; + var C_ONCE = 2; + var C_ID = 3; + var C_INTVL = 4; + var stepper = function() { var thisTime = new Date().getTime(); @@ -21,11 +27,11 @@ for ( var i in tList ) { var f = tList[i]; - if( f && thisTime > f[1] ) + if( f && thisTime > f[ C_TIME ] ) { try { - f[0](); + f[ C_CALLBACK ](); } catch(e) { @@ -34,13 +40,13 @@ continue; } - if( f[2] ) + if( f[ C_ONCE ] ) { delete tList[i]; } else { - f[1] = thisTime + f[4]; + f[ C_TIME ] = thisTime + f[ C_INTVL ]; } } } @@ -56,7 +62,7 @@ { for ( var i in tList ) { - if( tList[i][3] == id ) + if( tList[i][ C_ID ] == id ) return false; } @@ -68,14 +74,19 @@ // 3: id for ( var i in tList ) { - if( tList[i][3] == id ) + if( tList[i][ C_ID ] == id ) delete tList[i]; } }; var next = function( func ) { - tList[ tList.length ] = [ func, 0, true ]; + var a = []; + a[ C_CALLBACK ] = func; + a[ C_TIME ] = 0; + a[ C_ONCE ] = true; + + tList[ tList.length ] = a; }; var ourTick = new Tick();