diff --git a/botanjs/src/Components/Vim/Actions/DELETE.js b/botanjs/src/Components/Vim/Actions/DELETE.js
index 922f703f..b509fb55 100644
--- a/botanjs/src/Components/Vim/Actions/DELETE.js
+++ b/botanjs/src/Components/Vim/Actions/DELETE.js
@@ -41,19 +41,22 @@
 		var feeder = cur.feeder;
 
 		var Triggered = false;
-		if( sp == undefined && this.__startX != cur.aPos )
+
+		if( sp == undefined )
 		{
-			Triggered = true;
-
-			if( e.kMap( "l" ) )
+			if( this.__startX != cur.aPos )
 			{
-				cur.moveX( -1 );
+				Triggered = true;
+
+				if( e.kMap( "l" ) )
+				{
+					cur.moveX( -1 );
+				}
+
+				sp = this.__startX;
 			}
-
-			sp = this.__startX;
+			else return;
 		}
-		else if( sp == undefined ) return;
-
 
 		var c = feeder.content;
 
diff --git a/botanjs/src/Components/Vim/Actions/INSERT.js b/botanjs/src/Components/Vim/Actions/INSERT.js
index e67f083c..7eb38ebd 100644
--- a/botanjs/src/Components/Vim/Actions/INSERT.js
+++ b/botanjs/src/Components/Vim/Actions/INSERT.js
@@ -39,8 +39,8 @@
 
 	INSERT.prototype.dispose = function()
 	{
-		this.__cursor.moveX( -1 );
 		this.__rec( "", true );
+		this.__cursor.moveX( -1 );
 	};
 
 	INSERT.prototype.__rec = function( c, newRec )
@@ -92,12 +92,13 @@
 			if( this.__insertLength <= 0 )
 			{
 				this.__contentUndo = feeder.content.substr( f, 1 ) + this.__contentUndo;
-				this.__insertLength --;
 			}
 
 			feeder.content =
 				feeder.content.substring( 0, f )
 				+ feeder.content.substring( f + 1 );
+
+			this.__insertLength --;
 		}
 		else if( e.kMap( "Del" ) )
 		{
diff --git a/botanjs/src/Components/Vim/Actions/VISUAL.js b/botanjs/src/Components/Vim/Actions/VISUAL.js
index 8072e6b1..7cac7892 100644
--- a/botanjs/src/Components/Vim/Actions/VISUAL.js
+++ b/botanjs/src/Components/Vim/Actions/VISUAL.js
@@ -14,12 +14,7 @@
 	/** @type {Components.Vim.Cursor.IAction} */
 	var VISUAL = function( Cursor )
 	{
-		/** @type {Components.Vim.Cursor} */
-		this.__cursor = Cursor;
-		this.__startaP = Cursor.aPos;
-		this.__startP = { x: Cursor.X, y: Cursor.Y, p: Cursor.P };
-		this.__start = Cursor.PStart;
-		this.__selStart = Cursor.PStart;
+		this.__reset( Cursor );
 		this.__msg = Mesg( "VISUAL" );
 		this.__leaveMesg = "";
 
@@ -27,6 +22,15 @@
 		Cursor.pSpace = true;
 	};
 
+	VISUAL.prototype.__reset = function( Cursor )
+	{
+		/** @type {Components.Vim.Cursor} */
+		this.__cursor = Cursor;
+		this.__startaP = Cursor.aPos;
+		this.__start = Cursor.PStart;
+		this.__selStart = Cursor.PStart;
+	};
+
 	VISUAL.prototype.allowMovement = true;
 
 	VISUAL.prototype.dispose = function()
@@ -66,10 +70,9 @@
 			// to keep the cursor position as the top on UNDO / REDO
 			if( Action.constructor == DELETE && this.__startaP < cur.aPos )
 			{
-				this.__startaP = cur.aPos;
-				cur.X = this.__startP.x;
-				cur.Y = this.__startP.y;
-				cur.P = this.__startP.p;
+				var o = cur.aPos;
+				cur.moveTo( this.__startaP, true );
+				this.__startaP = o;
 			}
 
 			Action.handler( e, this.__startaP );
@@ -84,6 +87,22 @@
 		}
 		else
 		{
+			if( e.range )
+			{
+				cur.suppressEvent();
+
+				var r = e.range;
+
+				if( cur.aPos == this.__startaP )
+				{
+					cur.moveTo( r.open, true );
+					this.__reset( cur );
+				}
+
+				cur.unsuppressEvent();
+				cur.moveTo( r.close, true );
+			}
+
 			var prevPos = this.__start;
 			var newPos = cur.PStart;
 
diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index 8dba252c..950ddbc9 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -128,7 +128,7 @@
 		this.__ccur = this.__cfeeder.cursor;
 	};
 
-	Controls.prototype.__comp = function( kCode, handler )
+	Controls.prototype.__comp = function( e, handler )
 	{
 		if( handler )
 		{
@@ -141,6 +141,8 @@
 			return true;
 		}
 
+		var kCode = e.keyCode;
+
 		for( var i = 0; i < this.__compReg.length; i ++ )
 		{
 			var compReg = this.__compReg[i];
@@ -150,7 +152,7 @@
 			{
 				if( compReg.i == keys.length )
 				{
-					compReg.handler();
+					compReg.handler( e );
 					this.__compReg = null;
 					this.__cMovement = false;
 				}
@@ -249,12 +251,14 @@
 		{
 			if( !e.ModKeys )
 			{
-				this.__comp( kCode );
+				this.__comp( e );
 				return true;
 			}
 		}
 
 		var ccur = this.__ccur;
+		var vima = this.__vimArea;
+		var cfeeder = ccur.feeder;
 
 		var cursorHandled = true;
 		switch( kCode )
@@ -265,6 +269,29 @@
 			case K: this.__cMoveY( -1 ); break; // Up
 			case J: this.__cMoveY( 1 ); break; // Down
 
+			case CTRL + F: // Page Down
+				if( cfeeder.firstBuffer.next.placeholder )
+				{
+					beep();
+					break;
+				}
+
+				var oPan = cfeeder.panY;
+				cfeeder.pan( undefined, vima.rows - 1 );
+				ccur.moveY( -ccur.Y );
+
+				break;
+			case CTRL + B: // Page Up
+				if( cfeeder.panY == 0 )
+				{
+					beep();
+					break;
+				}
+				cfeeder.pan( undefined, -vima.rows + 1 );
+				ccur.moveY( -ccur.Y );
+				if( !cfeeder.EOF ) ccur.moveY( cfeeder.moreAt );
+				break;
+
 			case SHIFT + H: // First line buffer
 				break;
 			case SHIFT + L: // Last line buffer
@@ -281,6 +308,23 @@
 				break
 
 			case SHIFT + _5: // %, Find next item
+				var analyzer = this.__vimArea.contentAnalyzer;
+
+				/** @type {Components.Vim.Syntax.TokenMatch} */
+				var bracketMatch = analyzer.bracketAt( ccur.aPos );
+
+				if( bracketMatch.open == -1 )
+				{
+					beep();
+					break;
+				}
+
+				ccur.moveTo(
+					bracketMatch.selected == bracketMatch.close
+						? bracketMatch.open
+						: bracketMatch.close
+				);
+
 				break;
 			case T: // To
 				break;
@@ -291,32 +335,45 @@
 					break;
 				}
 
+				var analyzer = this.__vimArea.contentAnalyzer;
+
 				this.__cMovement = true;
+
 				// Word boundary
-				this.__comp( kCode, function(){
-					debug.Info( "Word boundary" );
+				this.__comp( e, function( e2 ) {
+					var WordMatch = analyzer.wordAt( ccur.aPos );
+					e2.__range = WordMatch;
 				}, W );
-				this.__comp( kCode, function(){
-					debug.Info( "Bracket boundary [" );
-				}, S_BRACKET_L );
-				this.__comp( kCode, function(){
-					debug.Info( "Bracket boundary ]" );
-				}, S_BRACKET_R );
-				this.__comp( kCode, function(){
-					debug.Info( "Bracket boundary {" );
-				}, SHIFT + S_BRACKET_L );
-				this.__comp( kCode, function(){
-					debug.Info( "Bracket boundary }" );
-				}, SHIFT + S_BRACKET_R );
+
+				var bracket = function( e2 ) {
+					var BracketMatch = analyzer.bracketIn( "(", ccur.aPos );
+					e2.__range = BracketMatch;
+				};
+				var curlyBracket = function( e2 ) {
+					var BracketMatch = analyzer.bracketIn( "{", ccur.aPos );
+					e2.__range = BracketMatch;
+				};
+				var squareBracket = function( e2 ) {
+					var BracketMatch = analyzer.bracketIn( "[", ccur.aPos );
+					e2.__range = BracketMatch;
+				};
+
+				// Bracket boundaries
+				this.__comp( e, bracket , SHIFT + _0 );
+				this.__comp( e, bracket, SHIFT + _9 );
+				this.__comp( e, squareBracket, S_BRACKET_L );
+				this.__comp( e, squareBracket, S_BRACKET_R );
+				this.__comp( e, curlyBracket, SHIFT + S_BRACKET_L );
+				this.__comp( e, curlyBracket, SHIFT + S_BRACKET_R );
 				break;
 
 			case G: // Go to top
 				this.__cMovement = true;
-				this.__comp( kCode, function(){
+				this.__comp( e, function(){
 					ccur.moveY( -Number.MAX_VALUE );
 					ccur.moveX( -Number.MAX_VALUE, true );
 				}, G );
-				this.__comp( kCode, function(){
+				this.__comp( e, function(){
 					ccur.openRunAction( "PRINT_HEX", e );
 				}, _8 );
 				break;
@@ -396,6 +453,8 @@
 
 		this.__modKeys = c == KEY_SHIFT || c == KEY_CTRL || c == KEY_ALT;
 		this.__key = e.key;
+
+		this.__range = null;
 	};
 
 	__readOnly( InputEvent.prototype, "target", function() { return this.__target; } );
@@ -404,6 +463,19 @@
 	__readOnly( InputEvent.prototype, "ModKeys", function() { return this.__modKeys; } );
 	__readOnly( InputEvent.prototype, "Escape", function() { return this.__escape; } );
 
+	__readOnly( InputEvent.prototype, "range", function() {
+
+		/** @type {Components.Vim.Syntax.TokenMatch} */
+		var r = this.__range;
+
+		if( r && r.open == -1 && r.close == -1 )
+		{
+			return null;
+		}
+
+		return r;
+	} );
+
 	InputEvent.prototype.kMap = function( map )
 	{
 		return this.__kCode == Map( map );
diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js
index 5f99f5da..ce66bd86 100644
--- a/botanjs/src/Components/Vim/Cursor.js
+++ b/botanjs/src/Components/Vim/Cursor.js
@@ -88,9 +88,39 @@
 	// Set by VimArea
 	Cursor.prototype.Vim;
 
-	// Can only be 1, -1
-	// 0 will be treated as undefined
-	Cursor.prototype.moveX = function( d, penentrate, phantomSpace )
+	// Move to an absolute position
+	Cursor.prototype.moveTo = function( aPos, phantomSpace )
+	{
+		var content = this.feeder.content;
+		var lastLineNum = this.getLine().lineNum;
+
+		var expLineNum = 0;
+		var lineStart = 0;
+		for( var i = content.indexOf( "\n" ); 0 <= i ; i = content.indexOf( "\n", i ) )
+		{
+			if( aPos <= i )
+			{
+				break;
+			}
+
+			lineStart = i;
+			i ++;
+			expLineNum ++;
+		}
+
+		var jumpY = expLineNum - lastLineNum;
+		var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart;
+
+		if( jumpY ) this.moveY( jumpY );
+		if( 0 < this.getLine().lineNum && lineStart <= aPos ) jumpX --;
+
+		this.moveX( - Number.MAX_VALUE );
+		this.moveX( jumpX, false, phantomSpace );
+
+	};
+
+	// 0 will be treated as default ( 1 )
+	Cursor.prototype.moveX = function( d, penetrate, phantomSpace )
 	{
 		var x = this.pX;
 
@@ -101,7 +131,7 @@
 
 		var buffs = this.feeder.lineBuffers;
 
-		if( penentrate )
+		if( penetrate )
 		{
 			if( x < 0 && ( 0 < this.feeder.panY || 0 < this.Y ) )
 			{
@@ -118,12 +148,12 @@
 
 		var c = content[ x ];
 
-		// Include empty lines befor cursor end
+		// Motion includes empty lines before cursor end
 		if( ( phantomSpace && cLen - 1 <= x ) || ( cLen == 1 && c == undefined ) )
 		{
 			x = 0 < d ? cLen - 1 : 0;
 		}
-		// ( 2 < cLen ) Exclude empty lines at cursor end
+		// ( 2 < cLen ) motion excludes empty lines at cursor end
 		else if( ( 2 <= cLen && x == cLen - 1 && c == " " ) || c == undefined )
 		{
 			x = 0 < d ? cLen - 2 : 0;
@@ -161,10 +191,10 @@
 		this.PEnd = P + 1;
 		this.__p = P;
 
-		this.__fireUpdate();
+		this.__visualUpdate();
 	};
 
-	Cursor.prototype.__fireUpdate = function()
+	Cursor.prototype.__visualUpdate = function()
 	{
 		if( 0 < this.__suppEvt )
 		{
@@ -174,7 +204,7 @@
 		this.feeder.dispatcher.dispatchEvent( new BotanEvent( "VisualUpdate" ) );
 	};
 
-	Cursor.prototype.moveY = function( d, penentrate )
+	Cursor.prototype.moveY = function( d )
 	{
 		var i;
 		var Y = this.Y + d;
@@ -183,7 +213,7 @@
 
 		if( Y < 0 )
 		{
-			feeder.pan( undefined, d );
+			feeder.pan( undefined, Y );
 
 			this.Y = 0;
 			this.moveX();
@@ -197,11 +227,7 @@
 		{
 			var feeder = this.feeder;
 
-			if( penentrate )
-			{
-				feeder.pan( undefined, Y - moreAt );
-			}
-			else if( feeder.linesTotal < Y )
+			if( feeder.linesTotal < Y )
 			{
 				while( !feeder.EOF )
 				{
@@ -219,18 +245,22 @@
 				if( !feeder.EOF )
 					feeder.pan( undefined, lineShift );
 
+				// The line number cursor need to be in
+				Y = thisLine + d;
+
 				// if it turns out to be the same line
+				// OR the cursor can not reside on the needed line
 				// before after panning
 				// we keep scrolling it ( panning )
 				// until the entire line cosumes the screen
-				while( !feeder.EOF && feeder.lastBuffer.lineNum == lastLine )
+				while( !feeder.EOF && (
+					feeder.lastBuffer.lineNum == lastLine
+					||  feeder.lastBuffer.lineNum < Y
+				) )
 				{
 					feeder.pan( undefined, 1 );
 				}
 
-				// The line number cursor need to be in
-				Y = thisLine + d;
-
 				i = this.Y;
 				this.Y = 0;
 				// Calculate the visual line position "i"
@@ -283,7 +313,7 @@
 		this.action = new (Actions[ name ])( this );
 		this.__pulseMsg = null;
 
-		this.__fireUpdate();
+		this.__visualUpdate();
 	};
 
 	Cursor.prototype.closeAction = function()
@@ -293,7 +323,10 @@
 		this.__pulseMsg = this.action.getMessage();
 		this.action = null;
 
-		this.__fireUpdate();
+		// Reset the analyzed content
+		this.Vim.contentAnalyzer.reset();
+
+		this.__visualUpdate();
 	};
 
 	// Open, Run, then close an action
@@ -305,7 +338,9 @@
 		this.__pulseMsg = action.getMessage();
 		action.dispose();
 
-		this.__fireUpdate();
+		this.Vim.contentAnalyzer.reset();
+
+		this.__visualUpdate();
 	};
 
 	Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; };
diff --git a/botanjs/src/Components/Vim/LineFeeder.js b/botanjs/src/Components/Vim/LineFeeder.js
index e50f4acd..b27779f1 100644
--- a/botanjs/src/Components/Vim/LineFeeder.js
+++ b/botanjs/src/Components/Vim/LineFeeder.js
@@ -149,7 +149,9 @@
 				var a = this.content.indexOf( "\n", f + 1 );
 				if( a == -1 )
 				{
-					Y = i;
+					Y = i - 1;
+					// -2 to compensate the last "\n" content placeholder
+					f -= 2;
 					break;
 				}
 				f = a;
diff --git a/botanjs/src/Components/Vim/Syntax/Analyzer.js b/botanjs/src/Components/Vim/Syntax/Analyzer.js
new file mode 100644
index 00000000..54014ce9
--- /dev/null
+++ b/botanjs/src/Components/Vim/Syntax/Analyzer.js
@@ -0,0 +1,337 @@
+(function(){
+	var ns = __namespace( "Components.Vim.Syntax" );
+
+	/** @type {System.Debug} */
+	var debug                                   = __import( "System.Debug" );
+
+	/** @type {Components.Vim.Syntax.Word} */
+	var Word = ns[ NS_INVOKE ]( "Word" );
+
+	var TOK_OPEN = 0;
+	var TOK_CLOSED = 1;
+	var TOK_LEVEL = 2;
+	var TOK_PARENT = 3;
+
+	var TOK_SEP = "\n";
+
+	var TOK_JOIN = function( a, b ) { return a + TOK_SEP + b; };
+
+	/*{{{ Private Class */
+	var TokenPairs = function( tok, content, esc )
+	{
+		var l = content.length;
+		var toks = tok.split( TOK_SEP );
+		var openToken = toks[0];
+		var closeToken = toks[1];
+
+		var opStack = [];
+
+		var unmatchedEd = [];
+
+		var lv = 0;
+
+		var pairs = [];
+
+		var lvUp = function( i )
+		{
+			opStack[ lv ] = i;
+			lv ++;
+		};
+
+		var lvDown = function( i )
+		{
+			if( lv == 0 )
+			{
+				// Cannot level down. i.e. Unmatched tokens
+				unmatchedEd.push( i );
+				return;
+			}
+
+			var Token = [];
+			Token[ TOK_OPEN ] = opStack[ -- lv ];
+			Token[ TOK_CLOSED ] = i;
+			Token[ TOK_LEVEL ] = lv;
+			Token[ TOK_PARENT ] =  0 < lv ? opStack[ lv - 1 ] : -1;
+
+			pairs.push( Token );
+		};
+
+		var opLen = openToken.length;
+		var edLen = closeToken.length;
+		for( var i = 0; i < l; i ++ )
+		{
+			var opTok = content.substr( i, opLen );
+			var edTok = content.substr( i, edLen );
+			if( opTok == openToken )
+			{
+				lvUp( i );
+				i += opLen - 1;
+			}
+			else if( edTok == closeToken )
+			{
+				lvDown( i );
+				i += edLen - 1;
+			}
+		}
+
+		if( unmatchedEd.length )
+		{
+			debug.Info( "Unmatched opening \"" + openToken + "\"@" + unmatchedEd.join( ", " ) );
+		}
+
+		if( 0 < lv )
+		{
+			debug.Info( "Unmatched closing \"" + closeToken + "\"@" + opStack.slice( 0, lv ) );
+		}
+
+		this.__pairs = pairs;
+		this.token = toks;
+	};
+
+	TokenPairs.prototype.token = "";
+
+	TokenPairs.prototype.matched = function()
+	{
+		return this.__pairs.sort(
+				function( a, b ) { return a[ TOK_OPEN ] - b[ TOK_OPEN ]; }
+				);
+	};
+
+	TokenPairs.prototype.find = function( pos, state )
+	{
+		if( state == undefined ) state = TOK_OPEN;
+
+		var pairs = this.__pairs;
+		var l = pairs.length;
+
+		for( var i = 0; i < l; i ++ )
+		{
+			var pair = pairs[i];
+			if( pair[ state ] == pos )
+			{
+				return pair;
+			}
+		}
+
+		return null;
+	};
+	/* End Private Class }}}*/
+
+	var SetParent = function( BracketPairs, pair )
+	{
+		if( !pair ) throw new Error( "Parent not found" );
+
+		var tMatch = new TokenMatch();
+		tMatch.__level = pair[ TOK_LEVEL ];
+		tMatch.__open = pair[ TOK_OPEN ];
+		tMatch.__close = pair[ TOK_CLOSED ];
+
+		if( -1 < pair[ TOK_PARENT ] )
+		{
+			var rPair = BracketPairs.find( pair[ TOK_PARENT ] );
+			tMatch.__parent = SetParent( BracketPairs, rPair );
+		}
+
+		return tMatch;
+	};
+
+	var Analyzer = function( feeder )
+	{
+		/* @type {Components.Vim.LineFeeder} */
+		this.__feeder = feeder;
+		this.__tokpairs = {};
+	};
+
+	Analyzer.prototype.bracketAt = function( p )
+	{
+		var c = this.__feeder.content;
+		var tokState = TOK_CLOSED;
+
+		var BracketPairs = null;
+		var cTok = c[ p ];
+
+		switch( cTok )
+		{
+			case "{": tokState = TOK_OPEN;
+			case "}":
+					  BracketPairs = this.__getPairs( TOK_JOIN( "{", "}" ) );
+				break;
+
+			case "[": tokState = TOK_OPEN;
+			case "]":
+				BracketPairs = this.__getPairs( TOK_JOIN( "[", "]" ) );
+				break;
+
+			case "(": tokState = TOK_OPEN;
+			case ")":
+				BracketPairs = this.__getPairs( TOK_JOIN( "(", ")" ) );
+				break;
+
+			case "/":
+				if( c[ p - 1 ] == "*" )
+				{
+					cTok = "*/";
+					p --;
+					break;
+				}
+				else if( c[ p + 1 ] == "*" )
+				{
+					cTok = "/*";
+					break;
+				}
+				return new TokenMatch();
+
+			case "*":
+				if( c[ p - 1 ] == "/" )
+				{
+					cTok = "/*";
+					p --;
+					break;
+				}
+				else if( c[ p + 1 ] == "/" )
+				{
+					cTok = "*/";
+					break;
+				}
+				return new TokenMatch();
+
+			default:
+				return new TokenMatch();
+		}
+
+		// Long Switch
+		if( !BracketPairs ) switch( cTok )
+		{
+			case "/*": tokState = TOK_OPEN;
+			case "*/":
+				BracketPairs = this.__getPairs( TOK_JOIN( "/*", "*/" ) );
+				break;
+
+			default:
+				return new TokenMatch();
+		}
+
+		var rPair = BracketPairs.find( p, tokState );
+		var tMatch = SetParent( BracketPairs, rPair )
+		tMatch.__selected = p;
+
+		return tMatch;
+	};
+
+	Analyzer.prototype.bracketIn = function( b, p )
+	{
+		var bro = "{[(";
+		var brc = "}])";
+
+		var i = bro.indexOf( b );
+		if( i < 0 ) i = brc.indexOf( b );
+		if( i < 0 ) throw new Error( "Unsupported bracket: " + b );
+
+		var tokPairs = this.__getPairs( TOK_JOIN( bro[i], brc[i] ) );
+		var pairs = tokPairs.__pairs;
+
+		var l = pairs.length;
+
+		var highest = null;
+
+		// Find the range of highest level
+		for( var i = 0; i < l; i ++ )
+		{
+			var pair = pairs[ i ];
+
+			if( pair[ TOK_OPEN ] <= p && p <= pair[ TOK_CLOSED ] )
+			{
+				if( ( highest && highest[ TOK_LEVEL ] < pair[ TOK_LEVEL ] ) || !highest )
+				{
+					highest = pair;
+				}
+			}
+
+		}
+
+		var tMatch = SetParent( tokPairs, highest );
+		var oMatch = tMatch;
+
+		do {
+			oMatch.__open ++;
+			oMatch.__close --;
+		} while( oMatch = oMatch.parent )
+
+		if( highest ) return tMatch;
+
+		return new TokenMatch();
+	};
+
+	Analyzer.prototype.__getPairs = function( def, reload )
+	{
+		if( !reload && this.__tokpairs[ def ] )
+		{
+			return this.__tokpairs[ def ];
+		}
+
+		var c = this.__feeder.content;
+		var pairs = new TokenPairs( def, c );
+
+		this.__tokpairs[ def ] = pairs;
+
+		return pairs;
+	};
+
+	Analyzer.prototype.reset = function()
+	{
+		this.__tokpairs = {};
+	};
+
+	Analyzer.prototype.quoteAt = function( p )
+	{
+		var c = this.__feeder.content;
+		switch( c[ p ] )
+		{
+			case "`":
+			case "\"":
+			case "\'":
+			default:
+				return {
+					level: 0
+					, open: -1
+					, close: -1
+				};
+		}
+	};
+
+	Analyzer.prototype.wordAt = function( p )
+	{
+		var c = this.__feeder.content;
+		var Len = c.length;
+		var i = p, j = p;
+
+		var word = new Word( c[ p ] );
+
+		if( 0 < p ) while( word.test( c[ -- i ] ) );
+		if( p < Len ) while( word.test( c[ ++ j ] ) );
+
+		var tMatch = new TokenMatch();
+		tMatch.__open = 0 < i ? i + 1 : 0;
+		tMatch.__close = j - 1;
+
+		return tMatch;
+	};
+
+	var TokenMatch = function()
+	{
+		this.__open = -1;
+		this.__close = -1;
+		this.__selected = -1;
+		this.__level = -1;
+		this.__parent = null;
+	};
+
+	__readOnly( TokenMatch.prototype, "parent", function() { return this.__parent; } );
+	__readOnly( TokenMatch.prototype, "open", function() { return this.__open; } );
+	__readOnly( TokenMatch.prototype, "close", function() { return this.__close; } );
+	__readOnly( TokenMatch.prototype, "level", function() { return this.__level; } );
+	__readOnly( TokenMatch.prototype, "selected", function() { return this.__selected; } );
+
+	ns[ NS_EXPORT ]( EX_CLASS, "Analyzer", Analyzer );
+	ns[ NS_EXPORT ]( EX_CLASS, "TokenMatch", TokenMatch );
+})();
diff --git a/botanjs/src/Components/Vim/Syntax/Word.js b/botanjs/src/Components/Vim/Syntax/Word.js
new file mode 100644
index 00000000..d879e595
--- /dev/null
+++ b/botanjs/src/Components/Vim/Syntax/Word.js
@@ -0,0 +1,255 @@
+(function(){
+	var ns = __namespace( "Components.Vim.Syntax" );
+
+	var KINGDOMS = [
+		[ // Numbers
+			[ 0x0030, 0x0039 ]
+		]
+		,
+		[ // Latin
+			[ 0x0041, 0x005A ], [ 0x0061, 0x007A ] // Basic Latin
+			, [ 0x00C0, 0x00FF ] // Latin-1 Supplement
+			, [ 0x0100, 0x017F ] // Latin Extended-A
+			, [ 0x0180, 0x024F ] // Latin Extended-B
+		// Latin-2 supplement
+			, [ 0x1D00, 0x1D7F ] // Phonetic Extensions
+			, [ 0x1D80, 0x1DBF ] // Phonetic Extensions Supplement
+			, [ 0x1DC0, 0x1DFF ] // Combining Diacritical Marks Supplement
+			, [ 0x1E00, 0x1EFF ] // Latin extended additional
+			, [ 0x1F00, 0x1FFF ] // Greek Extended
+		]
+		,
+		[
+			[ 0x0250, 0x02AF ] // IPA Extensions
+			, [ 0x02B0, 0x02FF ] // Spacing Modifier Letters
+			, [ 0x0300, 0x036F ] // Combining Diacritical Marks
+			, [ 0x0370, 0x03FF ] // Greek and Coptic
+			, [ 0x0400, 0x04FF ] // Cyrillic
+			, [ 0x0500, 0x052F ] // Cyrillic Supplement
+			, [ 0x0530, 0x058F ] // Armenian
+		]
+		,
+		[ // Aramaic Scripts
+			[ 0x0590, 0x05FF ] // Hebrew
+			, [ 0x0600, 0x06FF ] // Arabic
+			, [ 0x0700, 0x074F ] // Syriac
+			, [ 0x0750, 0x077F ] // Arabic Supplement
+			, [ 0x0780, 0x07BF ] // Thaana
+			, [ 0x07C0, 0x07FF ] // N'Ko
+			, [ 0x0800, 0x083F ] // Samaritan
+			, [ 0x0840, 0x085F ] // Mandaic
+			, [ 0x08A0, 0x08FF ] // Arabic Extended-A
+		]
+		,
+		[ // Brahmic scripts
+			[ 0x0900, 0x097F ] // Devanagari
+			, [ 0x0980, 0x09FF ] // Bengali
+			, [ 0x0A00, 0x0A7F ] // Gurmukhi
+			, [ 0x0A80, 0x0AFF ] // Gujarati
+			, [ 0x0B00, 0x0B7F ] // Oriya
+			, [ 0x0B80, 0x0BFF ] // Tamil
+			, [ 0x0C00, 0x0C7F ] // Telugu
+			, [ 0x0C80, 0x0CFF ] // Kannada
+			, [ 0x0D00, 0x0D7F ] // Malayalam
+			, [ 0x0D80, 0x0DFF ] // Sinhala
+			, [ 0x0E00, 0x0E7F ] // Thai
+			, [ 0x0E80, 0x0EFF ] // Lao
+			, [ 0x0F00, 0x0FFF ] // Tibetan
+			, [ 0x1000, 0x109F ] // Myanmar
+			, [ 0x10A0, 0x10FF ] // Georgian
+			, [ 0x1100, 0x11FF ] // Hangul Jamo
+			, [ 0x1200, 0x137F ] // Ethiopic
+			, [ 0x1380, 0x139F ] // Ethiopic Supplement
+			, [ 0x13A0, 0x13FF ] // Cherokee
+			, [ 0x1400, 0x167F ] // Unified Canadian Aboriginal Syllabics
+			, [ 0x1680, 0x169F ] // Ogham
+			, [ 0x16A0, 0x16FF ] // Runic
+		]
+		,
+		[ // Philippine scripts
+			[ 0x1700, 0x171F ] // Tagalog
+			, [ 0x1720, 0x173F ] // Hanunoo
+			, [ 0x1740, 0x175F ] // Buhid
+			, [ 0x1760, 0x177F ] // Tagbanwa
+			, [ 0x1780, 0x17FF ] // Khmer
+			, [ 0x1800, 0x18AF ] // Mongolian
+			, [ 0x18B0, 0x18FF ] // Unified Canadian Aboriginal Syllabics Extended
+			, [ 0x1900, 0x194F ] // Limbu
+		]
+		,
+		[ // Tai scripts
+			[ 0x1950, 0x197F ] // Tai Le
+			, [ 0x1980, 0x19DF ] // Tai Lue
+			, [ 0x19E0, 0x19FF ] // Khmer Symbols
+			, [ 0x1A00, 0x1A1F ] // Buginese
+			, [ 0x1A20, 0x1AAF ] // Tai Tham
+			, [ 0x1AB0, 0x1AFF ] // Combining Diacritical Marks Extended
+			, [ 0x1B00, 0x1B7F ] // Balinese
+			, [ 0x1B80, 0x1BBF ] // Sundanese
+			, [ 0x1BC0, 0x1BFF ] // Batak
+			, [ 0x1C00, 0x1C4F ] // Lepcha
+			, [ 0x1C50, 0x1C7F ] // Ol Chiki
+			, [ 0x1CC0, 0x1CCF ] // Sundanese Supplement
+			, [ 0x1CD0, 0x1CFF ] // Vedic Extensions
+		]
+		,
+		[ // Symbols
+			[ 0x2000, 0x206F ] // General Punctuation
+			, [ 0x2070, 0x209F ] // Superscripts and Subscripts
+			, [ 0x20A0, 0x20CF ] // Currency Symbols
+			, [ 0x20D0, 0x20FF ] // Combining Diacritical Marks for Symbols
+			, [ 0x2100, 0x214F ] // Letterlike Symbols
+			, [ 0x2150, 0x218F ] // Number Forms
+			, [ 0x2190, 0x21FF ] // Arrows
+			, [ 0x2200, 0x22FF ] // Mathematical Operators
+			, [ 0x2300, 0x23FF ] // Miscellaneous Technical
+			, [ 0x2400, 0x243F ] // Control Pictures
+			, [ 0x2440, 0x245F ] // Optical Character Recognition
+			, [ 0x2460, 0x24FF ] // Enclosed Alphanumerics
+			, [ 0x2500, 0x257F ] // Box Drawing
+			, [ 0x2580, 0x259F ] // Block Elements
+			, [ 0x25A0, 0x25FF ] // Geometric Shapes
+			, [ 0x2600, 0x26FF ] // Miscellaneous Symbols
+			, [ 0x2700, 0x27BF ] // Dingbats
+			, [ 0x27C0, 0x27EF ] // Miscellaneous Mathematical Symbols-A
+			, [ 0x27F0, 0x27FF ] // Supplemental Arrows-A
+			, [ 0x2800, 0x28FF ] // Braille Patterns
+			, [ 0x2900, 0x297F ] // Supplemental Arrows-B
+			, [ 0x2980, 0x29FF ] // Miscellaneous Mathematical Symbols-B
+			, [ 0x2A00, 0x2AFF ] // Supplemental Mathematical Operators
+			, [ 0x2B00, 0x2BFF ] // Miscellaneous Symbols and Arrows
+			, [ 0x2C00, 0x2C5F ] // Glagolitic
+			, [ 0x2C60, 0x2C7F ] // Latin Extended-C
+			, [ 0x2C80, 0x2CFF ] // Coptic
+			, [ 0x2D00, 0x2D2F ] // Georgian Supplement
+			, [ 0x2D30, 0x2D7F ] // Tifinagh
+			, [ 0x2D80, 0x2DDF ] // Ethiopic Extended
+			, [ 0x2DE0, 0x2DFF ] // Cyrillic Extended-A
+			, [ 0x2E00, 0x2E7F ] // Supplemental Punctuation
+		]
+		,
+		[ // CJK scripts and symbols
+			[ 0x2E80, 0x2EFF ] // CJK Radicals Supplement
+			, [ 0x2F00, 0x2FDF ] // Kangxi Radicals
+			, [ 0x2FF0, 0x2FFF ] // Ideographic Description Characters
+			, [ 0x3000, 0x303F ] // CJK Symbols and Punctuation
+			, [ 0x3040, 0x309F ] // Hiragana
+			, [ 0x30A0, 0x30FF ] // Katakana
+			, [ 0x3100, 0x312F ] // Bopomofo
+			, [ 0x3130, 0x318F ] // Hangul Compatibility Jamo
+			, [ 0x3190, 0x319F ] // Kanbun
+			, [ 0x31A0, 0x31BF ] // Bopomofo Extended
+			, [ 0x31C0, 0x31EF ] // CJK Strokes
+			, [ 0x31F0, 0x31FF ] // Katakana Phonetic Extensions
+			, [ 0x3200, 0x32FF ] // Enclosed CJK Letters and Months
+			, [ 0x3300, 0x33FF ] // CJK Compatibility
+			, [ 0x3400, 0x4DBF ] // CJK Unified Ideographs Extension A
+			, [ 0x4DC0, 0x4DFF ] // Yijing Hexagram Symbols
+			, [ 0x4E00, 0x9FFF ] // CJK Unified Ideographs
+			, [ 0xA000, 0xA48F ] // Yi Syllables
+			, [ 0xA490, 0xA4CF ] // Yi Radicals
+			, [ 0xA4D0, 0xA4FF ] // Lisu
+			, [ 0xA500, 0xA63F ] // Vai
+			, [ 0xA640, 0xA69F ] // Cyrillic Extended-B
+			, [ 0xA6A0, 0xA6FF ] // Bamum
+			, [ 0xA700, 0xA71F ] // Modifier Tone Letters
+			, [ 0xA720, 0xA7FF ] // Latin Extended-D
+			, [ 0xA800, 0xA82F ] // Syloti Nagri
+			, [ 0xA830, 0xA83F ] // Common Indic Number Forms
+			, [ 0xA840, 0xA87F ] // Phags-pa
+			, [ 0xA880, 0xA8DF ] // Saurashtra
+			, [ 0xA8E0, 0xA8FF ] // Devanagari Extended
+			, [ 0xA900, 0xA92F ] // Kayah Li
+			, [ 0xA930, 0xA95F ] // Rejang
+			, [ 0xA960, 0xA97F ] // Hangul Jamo Extended-A
+			, [ 0xA980, 0xA9DF ] // Javanese
+			, [ 0xA9E0, 0xA9FF ] // Myanmar Extended-B
+			, [ 0xAA00, 0xAA5F ] // Cham
+			, [ 0xAA60, 0xAA7F ] // Myanmar Extended-A
+			, [ 0xAA80, 0xAADF ] // Tai Viet
+			, [ 0xAAE0, 0xAAFF ] // Meetei Mayek Extensions
+			, [ 0xAB00, 0xAB2F ] // Ethiopic Extended-A
+			, [ 0xAB30, 0xAB6F ] // Latin Extended-E
+			, [ 0xAB70, 0xABBF ] // Cherokee Supplement
+			, [ 0xABC0, 0xABFF ] // Meetei Mayek
+			, [ 0xAC00, 0xD7AF ] // Hangul Syllables
+			, [ 0xD7B0, 0xD7FF ] // Hangul Jamo Extended-B
+		]
+		,
+		[ // Surrogates
+			[ 0xD800, 0xDBFF ] // High Surrogates
+			, [ 0xDC00, 0xDFFF ] // Low Surrogates
+			, [ 0xE000, 0xF8FF ] // Private Use Area
+			, [ 0xF900, 0xFAFF ] // CJK Compatibility Ideographs
+			, [ 0xFB00, 0xFB4F ] // Alphabetic Presentation Forms
+			, [ 0xFB50, 0xFDFF ] // Arabic Presentation Forms-A
+			, [ 0xFE00, 0xFE0F ] // Variation Selectors
+			, [ 0xFE10, 0xFE1F ] // Vertical Forms
+			, [ 0xFE20, 0xFE2F ] // Combining Half Marks
+			, [ 0xFE30, 0xFE4F ] // CJK Compatibility Forms
+			, [ 0xFE50, 0xFE6F ] // Small Form Variants
+			, [ 0xFE70, 0xFEFF ] // Arabic Presentation Forms-B
+			, [ 0xFF00, 0xFFEF ] // Halfwidth and Fullwidth Forms
+			, [ 0xFFF0, 0xFFFF ] // Specials
+		]
+		,
+		[ // Symbols
+			// Basic Latin
+			[ 0x0021, 0x002F ], [ 0x003A, 0x0040 ], [ 0x005B, 0x0060 ], [ 0x007B, 0x007E ],
+			// C1 Controls and Latin-1 Supplement (Extended ASCII)
+			[ 0x00A1, 0x00AC ], [ 0x00AE, 0x00BF ]
+		]
+	];
+
+	var NUM_KINGDOM = KINGDOMS.length;
+
+	var START = 0;
+	var END = 1;
+
+	var GetKingdom = function( Char )
+	{
+		var charCode = Char.charCodeAt( 0 );
+		for( var i = 0; i < NUM_KINGDOM; i ++ )
+		{
+			var kingdom = KINGDOMS[ i ];
+			var zLen = kingdom.length;
+			for( var j = 0; j < zLen; j ++ )
+			{
+				var zone = kingdom[ j ];
+				if( zone[ START ] <= charCode && charCode <= zone[ END ] )
+				{
+					return kingdom;
+				}
+			}
+		}
+
+		return [];
+	};
+
+	var Word = function( p )
+	{
+		this.kingdom = GetKingdom( p );
+	};
+
+	Word.prototype.test = function( p )
+	{
+		if( p == undefined || p == null || !p.charCodeAt ) return false;
+
+		var kingdom = this.kingdom;
+		var zLen = kingdom.length;
+		var charCode = p.charCodeAt( 0 );
+
+		for( var j = 0; j < zLen; j ++ )
+		{
+			var zone = kingdom[ j ];
+			if( zone[ START ] <= charCode && charCode <= zone[ END ] )
+			{
+				return true;
+			}
+		}
+
+		return false;
+	};
+
+	ns[ NS_EXPORT ]( EX_CLASS, "Word", Word );
+})();
diff --git a/botanjs/src/Components/Vim/VimArea.js b/botanjs/src/Components/Vim/VimArea.js
index 54c78649..116bd46a 100644
--- a/botanjs/src/Components/Vim/VimArea.js
+++ b/botanjs/src/Components/Vim/VimArea.js
@@ -11,7 +11,9 @@
 	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" );
 
 	/** @type {Components.Vim.LineFeeder} */
 	var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" );
@@ -94,6 +96,7 @@
 
 		// Content feeder
 		var cfeeder = new LineFeeder( cRange, c );
+        var contentAnalyzer = new SyntaxAnalyzer( cfeeder );
 
 		// Feed the contents to content feeder
 		// This "\n" fixes the last line "\n" not displaying
@@ -132,6 +135,7 @@
 		Update();
 
 		this.contentFeeder = cfeeder;
+        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 a8e1bdb0..afe109df 100644
--- a/botanjs/src/externs/Components.Vim.Controls.InputEvent.js
+++ b/botanjs/src/externs/Components.Vim.Controls.InputEvent.js
@@ -3,6 +3,8 @@ Components.Vim.Controls.InputEvent = function(){};
 
 /** @type {Components.Vim.VimArea} */
 Components.Vim.Controls.InputEvent.target;
+/** @type {Components.Vim.Syntax.TokenMatch} */
+Components.Vim.Controls.InputEvent.range;
 /** @type String */
 Components.Vim.Controls.InputEvent.key;
 /** @type Boolean */
diff --git a/botanjs/src/externs/Components.Vim.Cursor.js b/botanjs/src/externs/Components.Vim.Cursor.js
index 2f42cdb4..8cf84f8d 100644
--- a/botanjs/src/externs/Components.Vim.Cursor.js
+++ b/botanjs/src/externs/Components.Vim.Cursor.js
@@ -10,6 +10,8 @@ Components.Vim.Cursor.action;
 /** @type {Components.Vim.State.Recorder} */
 Components.Vim.Cursor.rec;
 
+/** @type Function */
+Components.Vim.Cursor.moveTo;
 /** @type Function */
 Components.Vim.Cursor.moveX;
 /** @type Function */
diff --git a/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js b/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js
new file mode 100644
index 00000000..24f603cc
--- /dev/null
+++ b/botanjs/src/externs/Components.Vim.Syntax.Analyzer.js
@@ -0,0 +1,13 @@
+/** @constructor */
+Components.Vim.Syntax.Analyzer = function(){};
+
+/** @type Function */
+Components.Vim.Syntax.Analyzer.bracketAt;
+/** @type Function */
+Components.Vim.Syntax.Analyzer.bracketIn;
+/** @type Function */
+Components.Vim.Syntax.Analyzer.wordAt;
+/** @type Function */
+Components.Vim.Syntax.Analyzer.quoteAt;
+/** @type Function */
+Components.Vim.Syntax.Analyzer.reset;
diff --git a/botanjs/src/externs/Components.Vim.Syntax.TokenMatch.js b/botanjs/src/externs/Components.Vim.Syntax.TokenMatch.js
new file mode 100644
index 00000000..916f3cd3
--- /dev/null
+++ b/botanjs/src/externs/Components.Vim.Syntax.TokenMatch.js
@@ -0,0 +1,14 @@
+/** @constructor */
+Components.Vim.Syntax.TokenMatch = function(){};
+
+/** @type {Components.Vim.Syntax.TokenMatch} */
+Components.Vim.Syntax.TokenMatch.parent;
+
+/** @type Number */
+Components.Vim.Syntax.TokenMatch.open;
+/** @type Number */
+Components.Vim.Syntax.TokenMatch.close;
+/** @type Number */
+Components.Vim.Syntax.TokenMatch.level;
+/** @type Number */
+Components.Vim.Syntax.TokenMatch.selected;
diff --git a/botanjs/src/externs/Components.Vim.Syntax.Word.js b/botanjs/src/externs/Components.Vim.Syntax.Word.js
new file mode 100644
index 00000000..a448be5d
--- /dev/null
+++ b/botanjs/src/externs/Components.Vim.Syntax.Word.js
@@ -0,0 +1,5 @@
+/** @constructor */
+Components.Vim.Syntax.Word = function(){};
+
+/** @type Function */
+Components.Vim.Syntax.Word.test;
diff --git a/botanjs/src/externs/Components.Vim.Syntax.js b/botanjs/src/externs/Components.Vim.Syntax.js
new file mode 100644
index 00000000..97fc80c3
--- /dev/null
+++ b/botanjs/src/externs/Components.Vim.Syntax.js
@@ -0,0 +1,2 @@
+/** @object */
+Components.Vim.Syntax = {};
diff --git a/botanjs/src/externs/Components.Vim.VimArea.js b/botanjs/src/externs/Components.Vim.VimArea.js
index 982acda7..51c9825f 100644
--- a/botanjs/src/externs/Components.Vim.VimArea.js
+++ b/botanjs/src/externs/Components.Vim.VimArea.js
@@ -3,6 +3,8 @@ Components.Vim.VimArea = function(){};
 
 /** @type {Components.Vim.LineFeeder} */
 Components.Vim.VimArea.contentFeeder;
+/** @type {Components.Vim.Syntax.Analyzer} */
+Components.Vim.VimArea.contentAnalyzer;
 /** @type {Components.Vim.LineFeeder} */
 Components.Vim.VimArea.statusFeeder;
 /** @type {Components.Vim.StatusBar} */