diff --git a/botanjs/src/Components/Vim/Actions/INSERT.js b/botanjs/src/Components/Vim/Actions/INSERT.js
index 5a4b30a5..c35c1672 100644
--- a/botanjs/src/Components/Vim/Actions/INSERT.js
+++ b/botanjs/src/Components/Vim/Actions/INSERT.js
@@ -204,6 +204,9 @@
 	{
 		var ind = this.__phantomIndent;
 		if( !this.__phantomIndent ) return;
+
+		debug.Info( "Realize Indentation: " + ind );
+
 		l = ind[ IN_END ];
 		for( var i = ind[ IN_START ]; i < l; i ++ )
 		{
@@ -261,6 +264,7 @@
 			a[ IN_DEL ] = inDel;
 
 			this.__phantomIndent = a;
+			debug.Info( "Phantom indent: " + a );
 		}
 	};
 
@@ -269,6 +273,8 @@
 		var ind = this.__phantomIndent;
 		if( !ind ) return "";
 
+		debug.Info( "Erase phantom indent: " + ind );
+
 		var cur = this.__cursor;
 		var feeder = cur.feeder;
 
diff --git a/botanjs/src/Components/Vim/Actions/REDO.js b/botanjs/src/Components/Vim/Actions/REDO.js
index 43ca88b5..94485d23 100644
--- a/botanjs/src/Components/Vim/Actions/REDO.js
+++ b/botanjs/src/Components/Vim/Actions/REDO.js
@@ -24,8 +24,10 @@
 		var stack = this.__cursor.rec.redo();
 		if( stack )
 		{
+			this.__cursor.suppressEvent();
 			stack.play();
-			this.__message = "<<TODO>>; before #" + stack.id + "  " + stack.time;
+			this.__cursor.unsuppressEvent();
+			this.__message = Mesg( "NCHANGES", "<TODO>", stack.id, stack.time );
 		}
 		else
 		{
diff --git a/botanjs/src/Components/Vim/Actions/REPLACE.js b/botanjs/src/Components/Vim/Actions/REPLACE.js
index 1acf895e..0161595c 100644
--- a/botanjs/src/Components/Vim/Actions/REPLACE.js
+++ b/botanjs/src/Components/Vim/Actions/REPLACE.js
@@ -92,7 +92,7 @@
 		this.__cursor.unsuppressEvent();
 	};
 
-	REPLACE.prototype.handler = function( e, p, range )
+	REPLACE.prototype.handler = function( e, p )
 	{
 		e.preventDefault();
 
@@ -143,13 +143,16 @@
 		var content = feeder.content.slice( 0, -1 )
 			.replace( search, this.__replCallback ) + "\n";
 
-		if( !this.__replacedGroups.length )
+		var numSubs = this.__replacedGroups.length;
+		if( !numSubs )
 		{
 			this.__msg = VimError( "E486", spattern.join( "" ) );
 		}
 
 		feeder.content = content;
 
+		this.__msg = Mesg( "REPLACE", numSubs, "<TODO>" );
+
 		// Record this step for UNDO / REDO
 		this.__rec();
 
diff --git a/botanjs/src/Components/Vim/Actions/SHIFT_LINES.js b/botanjs/src/Components/Vim/Actions/SHIFT_LINES.js
new file mode 100644
index 00000000..a539c17e
--- /dev/null
+++ b/botanjs/src/Components/Vim/Actions/SHIFT_LINES.js
@@ -0,0 +1,242 @@
+(function(){
+	var ns = __namespace( "Components.Vim.Actions" );
+
+	/** @type {System.Debug} */
+	var debug                                 = __import( "System.Debug" );
+	var beep = __import( "Components.Vim.Beep" );
+
+	/** @type {Components.Vim.State.Stack} */
+	var Stack                                  = __import( "Components.Vim.State.Stack" );
+
+	var VimError = __import( "Components.Vim.Error" );
+	var Mesg = __import( "Components.Vim.Message" );
+
+	var occurence = __import( "System.utils.Perf.CountSubstr" );
+
+	var REPL_BEFORE = 0;
+	var REPL_OFFSET = 1;
+	var REPL_LENGTH = 2;
+
+	/** @type {Components.Vim.IAction}
+	 *  Cursor @param {Components.Vim.Cursor}
+	 *  e @param {Components.Vim.ActionEvent}
+	 **/
+	var SHIFT_LINES = function( Cursor, e )
+	{
+		/** @type {Components.Vim.Cursor} */
+		this.__cursor = Cursor;
+		this.__startX = Cursor.aPos;
+		this.__msg = "<LINE_SHIFT>";
+
+		this.__slineNum = Cursor.getLine().lineNum;
+
+		this.__lines = e.count;
+		debug.Info( "Open shift: " + this.__lines + " line(s) below the cursor" );
+
+		this.__direction = e.kMap( ">" ) ? 1 : -1;
+		debug.Info( "Direction is: " + ( this.__direction == 1 ? ">" : "<" ) );
+
+		Cursor.suppressEvent();
+	};
+
+	SHIFT_LINES.prototype.allowMovement = true;
+
+	SHIFT_LINES.prototype.dispose = function()
+	{
+		this.__cursor.unsuppressEvent();
+	};
+
+	SHIFT_LINES.prototype.handler = function( e, sp )
+	{
+		e.preventDefault();
+
+		if( e.ModKeys || e.kMap( "i" ) ) return;
+
+		var cur = this.__cursor;
+		var feeder = cur.feeder;
+
+		var Triggered = false;
+		var dir = this.__direction;
+
+		var start = this.__slineNum;
+		var nline = this.__lines;
+
+		if( 1 < e.count )
+		{
+			nline += e.count;
+		}
+
+		var end = start;
+
+		var shiftCount = 1;
+		if( sp == undefined )
+		{
+			Triggered = true;
+
+			sp = this.__startX;
+
+			var currAp = cur.aPos;
+
+			if( this.__startX != currAp )
+			{
+				if( e.kMap( "h" ) || e.kMap( "l" ) ){}
+				else if( e.kMap( "j" ) )
+				{
+					end = start + nline;
+				}
+				else if( e.kMap( "k" ) )
+				{
+					start -= nline;
+				}
+				else // TODO: Dectect movement line count
+				{
+				}
+			}
+			else
+			{
+				if( !( ( 0 < dir && ( e.kMap( ">" ) || e.kMap( "l" ) ) )
+					|| ( dir < 0 && ( e.kMap( "<" ) || e.kMap( "h" ) ) )
+				) )
+				{
+					beep();
+					return true;
+				}
+			}
+		}
+
+		// last "\n" padding
+		var c = feeder.content.slice( 0, -1 );
+
+		var indents = c.match( /^[\t ]+/gm );
+		var indentChar = "\t";
+		var tabwidth = feeder.firstBuffer.tabWidth;
+
+		if( indents )
+		{
+			var l = indents.length - 1;
+
+			if( 1 < l )
+			{
+				debug.Info( "Guessing the tabstop:" );
+				var tabOccr = 0;
+				var spOccr = 0;
+
+				// Guess indent
+				var tabStat = {};
+
+				for( var i = 0; i < l; i ++ )
+				{
+					var ind = indents[ i ];
+					var indNext = indents[ i + 1 ];
+					tabOccr += occurence( ind, "\t" );
+					spOccr += occurence( ind, " " );
+					var d = indNext.length - ind.length;
+					if( d == 0 ) continue;
+
+					d = d < 0 ? -d : d;
+
+					if( !tabStat[ d ] ) tabStat[ d ] = 0;
+
+					tabStat[ d ] ++;
+				}
+
+				var upperDiff = 0;
+				var indentCLen = 0;
+				for( var i in tabStat )
+				{
+					var p = tabStat[ i ];
+					if( upperDiff < p )
+					{
+						upperDiff = p;
+						indentCLen = i;
+					}
+				}
+
+				spOccr /= indentCLen;
+
+				if( tabOccr < spOccr )
+				{
+					indentChar = "";
+					for( var i = 0; i < indentCLen; i ++ ) indentChar += " ";
+				}
+
+				tabwidth = indentCLen;
+
+				debug.Info( "\tTab count: " + tabOccr );
+				debug.Info( "\tSpace count: " + spOccr );
+				debug.Info( "\ti.e. indent using " + JSON.stringify( indentChar ) );
+			}
+			else
+			{
+				debug.Info( "Not enough tabs to determine the tabstop, using default" );
+			}
+		}
+
+		debug.Info( "Start: " + start, "End: " + end );
+		var rBlock = "";
+
+		var started = false;
+		var indentTimes = 1;
+
+		feeder.content = "";
+		nline = 0;
+
+		for( var i = 0, j = 0; 0 <= i; i = c.indexOf( "\n", i ), j ++ )
+		{
+			i ++;
+
+			if( j < start ) continue;
+			else if( !started )
+			{
+				started = true;
+				feeder.content = c.substring( 0, i - 1 );
+			}
+
+			if( end < j ) break;
+
+			var line = c.substring( 1 < i ? i : i - 1, c.indexOf( "\n", i ) );
+
+			if( 1 < i ) feeder.content += "\n";
+
+			if( line !== "" )
+			{
+				if( 0 < dir )
+				{
+					feeder.content += indentChar + line;
+				}
+				else
+				{
+					for( var si = 0, sj = 1; si < indentTimes; si ++ )
+					{
+						var startC = line[ si ];
+						if( startC == " " )
+						{
+							for( ; sj < tabwidth; sj ++ )
+							{
+								if( !~"\t ".indexOf( line[ si + sj ] ) ) break;
+							}
+						}
+						else if( startC != "\t" ) break;
+					}
+
+					feeder.content += line.substring( si + sj - 1 );
+				}
+				nline ++;
+			}
+		}
+ 
+		feeder.content += "\n" + c.substring( i ) + "\n";
+		feeder.pan();
+
+		this.__msg = Mesg( "LINES_SHIFTED", nline, dir < 0 ? "<" : ">", 1 );
+
+		return Triggered;
+	};
+
+	SHIFT_LINES.prototype.getMessage = function()
+	{
+		return this.__msg;
+	};
+
+	ns[ NS_EXPORT ]( EX_CLASS, "SHIFT_LINES", SHIFT_LINES );
+})();
diff --git a/botanjs/src/Components/Vim/Actions/UNDO.js b/botanjs/src/Components/Vim/Actions/UNDO.js
index 6f81f526..86db7cf3 100644
--- a/botanjs/src/Components/Vim/Actions/UNDO.js
+++ b/botanjs/src/Components/Vim/Actions/UNDO.js
@@ -24,8 +24,10 @@
 		var stack = this.__cursor.rec.undo();
 		if( stack )
 		{
+			this.__cursor.suppressEvent();
 			stack.play();
-			this.__message = "<<TODO>>; before #" + stack.id + "  " + stack.time;
+			this.__cursor.unsuppressEvent();
+			this.__message = Mesg( "NCHANGES", "<TODO>", stack.id, stack.time );
 		}
 		else
 		{
diff --git a/botanjs/src/Components/Vim/Actions/YANK.js b/botanjs/src/Components/Vim/Actions/YANK.js
index 44e3c27f..9c9a37aa 100644
--- a/botanjs/src/Components/Vim/Actions/YANK.js
+++ b/botanjs/src/Components/Vim/Actions/YANK.js
@@ -50,22 +50,18 @@
 			var currAp = cur.aPos;
 			if( this.__startX != currAp )
 			{
-				// Remove to start
 				if( e.kMap( "^" ) )
 				{
 					sp --;
 				}
-				// Remove char in cursor
 				else if( e.kMap( "l" ) )
 				{
 					cur.moveX( -1 );
 				}
-				// Remove char before cursor
 				else if( e.kMap( "h" ) )
 				{
 					sp = currAp;
 				}
-				// Remove the current and the following line
 				else if( e.kMap( "j" ) )
 				{
 					newLine = true;
@@ -75,7 +71,6 @@
 					cur.lineStart();
 					this.__startX = cur.aPos;
 				}
-				// Remove the current and the preceding line
 				else if( e.kMap( "k" ) )
 				{
 					newLine = true;
@@ -94,7 +89,6 @@
 					cur.moveTo( this.__startX );
 				}
 			}
-			// Remove the current line
 			else
 			{
 				if( e.kMap( "y" ) )
@@ -111,8 +105,6 @@
 				}
 				else if( e.kMap( "^" ) )
 				{
-					// Do nothing as nothing can be removed
-					// since there is no successful movement
 					return true;
 				}
 				// this is the same as kMap( "h" ) above
diff --git a/botanjs/src/Components/Vim/Controls.js b/botanjs/src/Components/Vim/Controls.js
index fac08751..c34a4d9a 100644
--- a/botanjs/src/Components/Vim/Controls.js
+++ b/botanjs/src/Components/Vim/Controls.js
@@ -205,7 +205,7 @@
 			case A: // Append
 				ccur.moveX( 1, true, true );
 			case I: // Insert
-				ccur.openAction( "INSERT" );
+				ccur.openAction( "INSERT", e );
 				break;
 
 			case S: // Delete Char and start insert
@@ -213,18 +213,18 @@
 				{
 					ccur.openRunAction( "DELETE", e, ccur.aPos );
 				}
-				ccur.openAction( "INSERT" );
+				ccur.openAction( "INSERT", e );
 				break;
 
 			case SHIFT + O: // new line before insert
 				ccur.lineStart();
-				ccur.openAction( "INSERT" );
+				ccur.openAction( "INSERT", e );
 				ccur.action.handler( new ActionEvent( e.sender, "Enter" ) );
 				ccur.moveY( -1 );
 				break;
 			case O: // new line insert
 				ccur.lineEnd( true );
-				ccur.openAction( "INSERT" );
+				ccur.openAction( "INSERT", e );
 				ccur.action.handler( new ActionEvent( e.sender, "Enter" ) );
 				break;
 
@@ -236,10 +236,10 @@
 				break;
 
 			case D: // Del with motion
-				ccur.openAction( "DELETE" );
+				ccur.openAction( "DELETE", e );
 				break;
 			case Y: // Yank with motion
-				ccur.openAction( "YANK" );
+				ccur.openAction( "YANK", e );
 				break;
 
 			case P: // Put
@@ -272,7 +272,7 @@
 
 			case V: // Visual
 			case SHIFT + V: // Visual line
-				ccur.openAction( "VISUAL" );
+				ccur.openAction( "VISUAL", e );
 				ccur.action.handler( e );
 				break;
 
@@ -281,6 +281,11 @@
 				this.__divedCCmd.handler( e );
 				break;
 
+			case SHIFT + COMMA: // <
+			case SHIFT + FULLSTOP: // >
+				ccur.openAction( "SHIFT_LINES", e );
+				break;
+
 			case F1: // F1, help
 				break;
 			default:
@@ -349,15 +354,21 @@
 				var Count = e.key;
 				var recurNum = function( e )
 				{
+					var intercept = e.ModKeys;
 					switch( e.keyCode )
 					{
 						case _0: case _1: case _2:
 						case _3: case _4: case _5:
 						case _6: case _7: case _8: case _9:
 							Count += e.key;
-							_self.__composite( e, recurNum, ANY_KEY );
-							e.cancel();
-							return;
+							intercept = true;
+					}
+
+					if( intercept )
+					{
+						_self.__composite( e, recurNum, ANY_KEY );
+						e.cancel();
+						return;
 					}
 
 					e.__count = Number( Count );
diff --git a/botanjs/src/Components/Vim/Cursor.js b/botanjs/src/Components/Vim/Cursor.js
index e9b6d13e..f8d2dd92 100644
--- a/botanjs/src/Components/Vim/Cursor.js
+++ b/botanjs/src/Components/Vim/Cursor.js
@@ -376,13 +376,13 @@
 
 	// Open an action handler
 	// i.e. YANK, VISUAL, INSERT, UNDO, etc.
-	Cursor.prototype.openAction = function( name )
+	Cursor.prototype.openAction = function( name, e )
 	{
 		if( this.action ) this.action.dispose();
 
 		debug.Info( "openAction: " + name );
 
-		this.action = new (Actions[ name ])( this );
+		this.action = new (Actions[ name ])( this, e );
 		this.__pulseMsg = null;
 
 		this.__visualUpdate();
diff --git a/botanjs/src/Components/Vim/_this.js b/botanjs/src/Components/Vim/_this.js
index ab267064..dedf3f41 100644
--- a/botanjs/src/Components/Vim/_this.js
+++ b/botanjs/src/Components/Vim/_this.js
@@ -19,10 +19,12 @@ VIMRE_VERSION = "1.0.0b";
 
 		, "UNDO_LIMIT": "Already at oldest change"
 		, "REDO_LIMIT": "Already at newest change"
+		, "NCHANGES": "%1 change(s); before #%2  %3"
 
 		, "LINES_FEWER": "%1 fewer line(s)"
 		, "LINES_MORE": "%1 more line(s)"
 		, "LINES_YANKED": "%1 line(s) yanked"
+		, "LINES_SHIFTED": "%1 line(s) %2ed %3 time(s)"
 
 		, "SEARCH_HIT_BOTTOM": "search hit BOTTOM, continuing at TOP"
 		, "SEARCH_HIT_TOP": "search hit TOP, continuing at BOTTOM"