penguin/AstroJS

Javascript framework for my blog

commit a6ccf7e4dbd85b12e792f74ef7aa88564fc7d6ef

author斟酌 鵬兄 <tgckpg@gmail.com>
date2017-01-06T10:05:07Z
subjectQuote in between & PUT impl
commit a6ccf7e4dbd85b12e792f74ef7aa88564fc7d6ef
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2017-01-06T10:05:07Z

    Quote in between & PUT impl
---
 README.md                                          |  2 +-
 botanjs/src/Components/Vim/Actions/PUT.js          | 28 ++++++---
 botanjs/src/Components/Vim/Actions/TO.js           |  4 +-
 botanjs/src/Components/Vim/Actions/VISUAL.js       | 11 +++-
 botanjs/src/Components/Vim/Controls.js             | 16 ++++-
 botanjs/src/Components/Vim/Syntax/Analyzer.js      | 69 ++++++++++++++++++++++
 .../src/externs/Components.Vim.Syntax.Analyzer.js  |  2 +
 7 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/README.md b/README.md
index 02e8606..30265e8 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Visit the demo over [here](https://tgckpg.github.io/VimArea)
 Common commands are now supported. I am now going to list the commands that yet to be made.
 ```
 Commands that are going to implement soon:
-auto indent ( new line from bracket ), [action]i[quote]
+auto indent ( new line from bracket )
 :'<,'>
 
 Commands that are planning to implement in near future:
diff --git a/botanjs/src/Components/Vim/Actions/PUT.js b/botanjs/src/Components/Vim/Actions/PUT.js
index 52a6891..6dacc15 100644
--- a/botanjs/src/Components/Vim/Actions/PUT.js
+++ b/botanjs/src/Components/Vim/Actions/PUT.js
@@ -25,7 +25,7 @@
 		this.__cursor.unsuppressEvent();
 	};
 
-	PUT.prototype.handler = function( e )
+	PUT.prototype.handler = function( e, sp, newLine )
 	{
 		e.preventDefault();
 
@@ -63,20 +63,32 @@
 
 		var stator = new Stator( cur );
 		var aP = cur.aPos;
+		var contentUndo = "";
 
-		feeder.content = feeder.content.substring( 0, aP )
-			+ cput
-			+ feeder.content.substring( aP );
+		if( sp == undefined )
+		{
+			feeder.content = feeder.content.substring( 0, aP )
+				+ cput + feeder.content.substring( aP );
 
-		feeder.pan();
+			feeder.pan();
+			cur.moveTo( 0 < nLines ? aP : aP + clen, true );
+		}
+		else
+		{
+			sp ++;
+			contentUndo = feeder.content.substring( aP, sp );
+			feeder.content = feeder.content.substring( 0, aP )
+				+ cput + feeder.content.substring( sp );
 
-		cur.moveTo( 0 < nLines ? aP : aP + clen, true );
+			feeder.pan();
+			cur.moveTo( aP + clen, true );
+		}
 
 		var stack = new Stack();
 
 		if( newLine )
 		{
-			var f = stator.save( clen, "" );
+			var f = stator.save( clen, contentUndo );
 			stack.store( function()
 			{
 				f();
@@ -85,7 +97,7 @@
 		}
 		else
 		{
-			stack.store( stator.save( clen, "" ) );
+			stack.store( stator.save( clen, contentUndo ) );
 		}
 		cur.rec.record( stack );
 
diff --git a/botanjs/src/Components/Vim/Actions/TO.js b/botanjs/src/Components/Vim/Actions/TO.js
index eb1e00e..83daa03 100644
--- a/botanjs/src/Components/Vim/Actions/TO.js
+++ b/botanjs/src/Components/Vim/Actions/TO.js
@@ -38,7 +38,7 @@
 
 		if( 0 < n ) p ++;
 
-		var lowerLimmit = p;
+		var lowerLimit = p;
 
 		var Char = et.key;
 		if( et.kMap( "Tab" ) )
@@ -64,7 +64,7 @@
 			tX = f.content.lastIndexOf( Char, cur.aPos - 1 );
 		}
 
-		if( lowerLimmit <= tX && tX < upperLimit )
+		if( lowerLimit <= tX && tX < upperLimit )
 		{
 			cur.moveTo( tX );
 		}
diff --git a/botanjs/src/Components/Vim/Actions/VISUAL.js b/botanjs/src/Components/Vim/Actions/VISUAL.js
index 5e0cbea..55aa192 100644
--- a/botanjs/src/Components/Vim/Actions/VISUAL.js
+++ b/botanjs/src/Components/Vim/Actions/VISUAL.js
@@ -12,6 +12,8 @@
 	var DELETE = ns[ NS_INVOKE ]( "DELETE" );
 	/** @type {Components.Vim.IAction} */
 	var SHIFT_LINES = ns[ NS_INVOKE ]( "SHIFT_LINES" );
+	/** @type {Components.Vim.IAction} */
+	var PUT = ns[ NS_INVOKE ]( "PUT" );
 
 	var MODE_NULL = -1;
 	var MODE_VISUAL = 0;
@@ -121,6 +123,10 @@
 		{
 			Action = new DELETE( cur );
 		}
+		else if( e.kMap( "p" ) )
+		{
+			Action = new PUT( cur );
+		}
 		else if( e.kMap( "V" ) )
 		{
 			if( this.__mode == MODE_LINE ) return true;
@@ -180,7 +186,8 @@
 			// this swap the cursor direction from LTR to RTL
 			// i.e. treat all delete as "e<----s" flow
 			// to keep the cursor position as the top on UNDO / REDO
-			if( Action.constructor == DELETE && startLine.aPos < cur.aPos )
+			var IsContMod = ~[ DELETE, PUT ].indexOf( Action.constructor );
+			if( IsContMod && startLine.aPos < cur.aPos )
 			{
 				var o = cur.aPos;
 				cur.moveTo( startLine.aPos, true );
@@ -189,7 +196,7 @@
 
 			Action.handler( e, startLine.aPos, lineMode );
 
-			if( Action.constructor != DELETE )
+			if( !IsContMod )
 			{
 				cur.moveTo( startLine.aPos );
 			}
diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index 36d0e04..cdb320c 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -616,14 +616,26 @@
 					var BracketMatch = analyzer.bracketIn( "[", ccur.aPos );
 					e2.__range = BracketMatch;
 				};
+				var singleQuote = function( e2 ) {
+					var BracketMatch = analyzer.quoteIn( "'", ccur.aPos );
+					e2.__range = BracketMatch;
+				};
+				var doubleQuote = function( e2 ) {
+					var BracketMatch = analyzer.quoteIn( "\"", ccur.aPos );
+					e2.__range = BracketMatch;
+				};
 
 				// Bracket boundaries
-				this.__composite( e, bracket , SHIFT + _0 );
+				this.__composite( e, bracket, SHIFT + _0 );
 				this.__composite( e, bracket, SHIFT + _9 );
 				this.__composite( e, squareBracket, S_BRACKET_L );
 				this.__composite( e, squareBracket, S_BRACKET_R );
 				this.__composite( e, curlyBracket, SHIFT + S_BRACKET_L );
 				this.__composite( e, curlyBracket, SHIFT + S_BRACKET_R );
+
+				// Quote boundaries
+				this.__composite( e, singleQuote, QUOTE );
+				this.__composite( e, doubleQuote, SHIFT + QUOTE );
 				break;
 
 			case G:
@@ -725,7 +737,7 @@
 		var cfeeder = this.__cfeeder;
 		var ccur = this.__ccur;
 
-		if( !ccur.action || ccur.action.allowMovement )
+		if( !this.__cMovement && ( !ccur.action || ccur.action.allowMovement ) )
 		{
 			this.__modCommand( e );
 			if( e.canceled ) return;
diff --git a/botanjs/src/Components/Vim/Syntax/Analyzer.js b/botanjs/src/Components/Vim/Syntax/Analyzer.js
index c10e441..de66e22 100644
--- a/botanjs/src/Components/Vim/Syntax/Analyzer.js
+++ b/botanjs/src/Components/Vim/Syntax/Analyzer.js
@@ -4,6 +4,8 @@
 	/** @type {System.Debug} */
 	var debug                                   = __import( "System.Debug" );
 
+	var beep = __import( "Components.Vim.Beep" );
+
 	/** @type {Components.Vim.Syntax.Word} */
 	var Word = ns[ NS_INVOKE ]( "Word" );
 
@@ -265,6 +267,73 @@
 		return new TokenMatch();
 	};
 
+	Analyzer.prototype.quoteIn = function( Char )
+	{
+		var f = this.__feeder;
+		var cur = f.cursor;
+		var n = cur.getLine().lineNum;
+
+		var p = 0;
+		for( var i = 0; 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 lowerLimit = p;
+
+		// Cursor is at the quote character
+		// Move cursor inside the matching quote
+		if( f.content[ cur.aPos ] == Char )
+		{
+			// Mark all quotes on current line
+			var quotePos = [];
+			var l = 0;
+
+			for( var i = lowerLimit; i < upperLimit; i ++ )
+			{
+				if( f.content[ i ] == Char )
+					quotePos[ l ++ ] = i;
+			}
+
+			var indexQuote = quotePos.indexOf( cur.aPos );
+			var indexEnd = ( indexQuote == ( l - 1 ) );
+
+			// Length is even: Quotes are matched
+			// OR
+			// Length is odd and cursor is not at the last quote
+			if( l % 2 == 0 || !indexEnd )
+			{
+				cur.moveX( indexQuote % 2 == 0 ? 1 : -1 );
+			}
+			// Cursor is at the last quote
+			else
+			{
+				// Beep because last quote of odd length is an unmatch quote
+				beep();
+				return new TokenMatch();
+			}
+
+		}
+
+		// Forward
+		var fX = f.content.indexOf( Char, cur.aPos + 1 );
+		// backward
+		var bX = f.content.lastIndexOf( Char, cur.aPos - 1 );
+
+		if( lowerLimit <= bX && fX < upperLimit )
+		{
+			var tMatch = new TokenMatch();
+			tMatch.__open = bX + 1;
+			tMatch.__close = fX - 1;
+			tMatch.__selected = Char;
+			return tMatch;
+		}
+		else beep();
+
+		return new TokenMatch();
+	};
+
 	Analyzer.prototype.__getPairs = function( def, reload )
 	{
 		if( !reload && this.__tokpairs[ def ] )
diff --git a/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js b/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js
index 24f603c..ae4b31f 100644
--- a/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js
+++ b/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js
@@ -6,6 +6,8 @@ Components.Vim.Syntax.Analyzer.bracketAt;
 /** @type Function */
 Components.Vim.Syntax.Analyzer.bracketIn;
 /** @type Function */
+Components.Vim.Syntax.Analyzer.quoteIn;
+/** @type Function */
 Components.Vim.Syntax.Analyzer.wordAt;
 /** @type Function */
 Components.Vim.Syntax.Analyzer.quoteAt;