forked from Botanical/BotanJS
		
	Merge remote-tracking branch 'vim/master' into Astro
This commit is contained in:
		| @@ -48,10 +48,12 @@ | |||||||
|  |  | ||||||
| 		var msg = ":buffers"; | 		var msg = ":buffers"; | ||||||
|  |  | ||||||
| 		for( var i in Insts ) | 		var l = Insts.length; | ||||||
|  | 		for( var i = 0; i < l; i ++ ) | ||||||
| 		{ | 		{ | ||||||
| 			/** @type {Components.Vim.VimArea} */ | 			/** @type {Components.Vim.VimArea} */ | ||||||
| 			var inst = Insts[ i ]; | 			var inst = Insts[ i ]; | ||||||
|  | 			if( !inst ) continue; | ||||||
|  |  | ||||||
| 			var b = inst.index + " "; | 			var b = inst.index + " "; | ||||||
| 			var icur = inst.contentFeeder.cursor; | 			var icur = inst.contentFeeder.cursor; | ||||||
|   | |||||||
| @@ -79,6 +79,9 @@ | |||||||
| 			case "registers": | 			case "registers": | ||||||
| 				out[ CMD_TYPE ] = "REGISTERS"; | 				out[ CMD_TYPE ] = "REGISTERS"; | ||||||
| 				break; | 				break; | ||||||
|  | 			case "marks": | ||||||
|  | 				out[ CMD_TYPE ] = "MARKS"; | ||||||
|  | 				break; | ||||||
| 			case "ver": | 			case "ver": | ||||||
| 			case "version": | 			case "version": | ||||||
| 				out[ CMD_TYPE ] = "VERSION"; | 				out[ CMD_TYPE ] = "VERSION"; | ||||||
| @@ -90,6 +93,13 @@ | |||||||
| 			case "varec": | 			case "varec": | ||||||
| 				out[ CMD_TYPE ] = "VA_REC"; | 				out[ CMD_TYPE ] = "VA_REC"; | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
|  | 			case "": // Range jumping | ||||||
|  | 				pattern.push( true ); | ||||||
|  | 			case "p": | ||||||
|  | 				allowRange = true; | ||||||
|  | 				out[ CMD_TYPE ] = "PRINT"; | ||||||
|  | 				break; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if( range !== "" ) | 		if( range !== "" ) | ||||||
|   | |||||||
| @@ -66,7 +66,10 @@ | |||||||
|  |  | ||||||
| 			var content = feeder.content; | 			var content = feeder.content; | ||||||
|  |  | ||||||
| 			contentUndo = feeder.content.substring( start, end ); | 			var l = content.length; | ||||||
|  | 			while( "\t ".indexOf( content[ end ] ) != -1 && end < l ) end ++; | ||||||
|  |  | ||||||
|  | 			contentUndo = content.substring( start, end ); | ||||||
| 			feeder.content = content.substring( 0, start ) + " " + content.substr( end ); | 			feeder.content = content.substring( 0, start ) + " " + content.substr( end ); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										83
									
								
								botanjs/src/Components/Vim/Actions/MARKS.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								botanjs/src/Components/Vim/Actions/MARKS.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | (function(){ | ||||||
|  | 	var ns = __namespace( "Components.Vim.Actions" ); | ||||||
|  |  | ||||||
|  | 	/** @type {System.Debug} */ | ||||||
|  | 	var debug                                 = __import( "System.Debug" ); | ||||||
|  |  | ||||||
|  | 	var VimError = __import( "Components.Vim.Error" ); | ||||||
|  | 	var Mesg = __import( "Components.Vim.Message" ); | ||||||
|  |  | ||||||
|  | 	/** @type {System.Debug} */ | ||||||
|  | 	var Marks = __import( "Components.Vim.State.Marks" ); | ||||||
|  | 	var Keys = Marks.Keys; | ||||||
|  |  | ||||||
|  | 	/** @type {Components.Vim.IAction} */ | ||||||
|  | 	var MARKS = function( Cursor ) | ||||||
|  | 	{ | ||||||
|  | 		/** @type {Components.Vim.Cursor} */ | ||||||
|  | 		this.__cursor = Cursor; | ||||||
|  | 		this.__msg = ""; | ||||||
|  | 		Cursor.suppressEvent(); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	MARKS.prototype.dispose = function() | ||||||
|  | 	{ | ||||||
|  | 		this.__cursor.unsuppressEvent(); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	MARKS.prototype.handler = function( e, p ) | ||||||
|  | 	{ | ||||||
|  | 		e.preventDefault(); | ||||||
|  |  | ||||||
|  | 		/** @type {Components.Vim.State.Marks} */ | ||||||
|  | 		var marks = e.target.marks; | ||||||
|  |  | ||||||
|  | 		var msg = ":marks"; | ||||||
|  |  | ||||||
|  | 		/** | ||||||
|  | 		 * Regarding to marks 0-9, from Vim docs | ||||||
|  | 		 *   Numbered marks '0 to '9 are quite different.  They can not be set directly. | ||||||
|  | 		 *   They are only present when using a viminfo file viminfo-file.  Basically '0 | ||||||
|  | 		 *   is the location of the cursor when you last exited Vim, '1 the last but one | ||||||
|  | 		 *   time, etc.  Use the "r" flag in 'viminfo' to specify files for which no | ||||||
|  | 		 *   Numbered mark should be stored.  See viminfo-file-marks. | ||||||
|  | 		 * TODO: Need to redefine marks 0-9 | ||||||
|  | 		 **/ | ||||||
|  |  | ||||||
|  | 		// Fuck this, use silly paddings | ||||||
|  | 		msg += "\nmark line  col file/text"; | ||||||
|  |  | ||||||
|  | 		var feeder = this.__cursor.feeder; | ||||||
|  | 		for( var i = 0, j = Keys[ i ]; j != undefined; i ++, j = Keys[ i ] ) | ||||||
|  | 		{ | ||||||
|  | 			var r = marks.get( j ); | ||||||
|  | 			if( !r ) continue; | ||||||
|  |  | ||||||
|  | 			var line = ( r[0] + 1 ) + ""; | ||||||
|  | 			var col = ( r[1] + 1 ) + ""; | ||||||
|  | 			var t = feeder.line( r[0] - 1 ).replace( /^[\t ]+/, "" ); | ||||||
|  |  | ||||||
|  | 			var ll = 4 - line.length; | ||||||
|  | 			for( var il = 0; il < ll; il ++ ) line = " " + line; | ||||||
|  |  | ||||||
|  | 			var ll = 3 - col.length; | ||||||
|  | 			for( var il = 0; il < ll; il ++ ) col = " " + col; | ||||||
|  |  | ||||||
|  | 			msg += "\n " + j + "   " + line + "  " + col + " " + t; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var lastLine = Mesg( "WAIT_FOR_INPUT" ); | ||||||
|  |  | ||||||
|  | 		var l = this.__cursor.feeder.firstBuffer.cols; | ||||||
|  | 		for( var i = msg.length; i < l; i ++ ) msg += " "; | ||||||
|  |  | ||||||
|  | 		this.__msg = msg + "\n" + lastLine; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	MARKS.prototype.getMessage = function() | ||||||
|  | 	{ | ||||||
|  | 		return this.__msg; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	ns[ NS_EXPORT ]( EX_CLASS, "MARKS", MARKS ); | ||||||
|  | })(); | ||||||
							
								
								
									
										48
									
								
								botanjs/src/Components/Vim/Actions/PRINT.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								botanjs/src/Components/Vim/Actions/PRINT.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | (function(){ | ||||||
|  | 	var ns = __namespace( "Components.Vim.Actions" ); | ||||||
|  |  | ||||||
|  | 	/** @type {System.Debug} */ | ||||||
|  | 	var debug                                 = __import( "System.Debug" ); | ||||||
|  |  | ||||||
|  | 	/** @type {Components.Vim.IAction} */ | ||||||
|  | 	var PRINT = function( Cursor ) | ||||||
|  | 	{ | ||||||
|  | 		/** @type {Components.Vim.Cursor} */ | ||||||
|  | 		this.__cursor = Cursor; | ||||||
|  | 		this.__msg = ""; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	PRINT.prototype.dispose = function() { }; | ||||||
|  | 	PRINT.prototype.handler = function( e, args, range ) | ||||||
|  | 	{ | ||||||
|  | 		e.preventDefault(); | ||||||
|  |  | ||||||
|  | 		if( args[0] === true ) | ||||||
|  | 		{ | ||||||
|  | 			switch( range ) | ||||||
|  | 			{ | ||||||
|  | 				case "%": | ||||||
|  | 				case "$": | ||||||
|  | 					this.__cursor.moveY( Number.MAX_VALUE ); | ||||||
|  | 					return; | ||||||
|  | 				case ".": | ||||||
|  | 					this.__cursor.lineStart( true ); | ||||||
|  | 					break; | ||||||
|  | 				case "": | ||||||
|  | 				default: | ||||||
|  | 					var lineNum = parseInt( range ) - 1; | ||||||
|  | 					if( lineNum ) | ||||||
|  | 					{ | ||||||
|  | 						this.__cursor.gotoLine( 0 < lineNum ? lineNum : 0 ); | ||||||
|  | 					} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	PRINT.prototype.getMessage = function() | ||||||
|  | 	{ | ||||||
|  | 		return this.__msg; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	ns[ NS_EXPORT ]( EX_CLASS, "PRINT", PRINT ); | ||||||
|  | })(); | ||||||
| @@ -182,10 +182,13 @@ | |||||||
| 					startLine.aPos = startLine.aEnd; | 					startLine.aPos = startLine.aEnd; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			// Cursor position adjustment |  | ||||||
| 			// this swap the cursor direction from LTR to RTL | 			/** | ||||||
| 			// i.e. treat all delete as "e<----s" flow | 			 * Content Modifier: | ||||||
| 			// to keep the cursor position as the top on UNDO / REDO | 			 *   This swaps 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 | ||||||
|  | 			 **/ | ||||||
| 			var IsContMod = ~[ DELETE, PUT ].indexOf( Action.constructor ); | 			var IsContMod = ~[ DELETE, PUT ].indexOf( Action.constructor ); | ||||||
| 			if( IsContMod && startLine.aPos < cur.aPos ) | 			if( IsContMod && startLine.aPos < cur.aPos ) | ||||||
| 			{ | 			{ | ||||||
| @@ -196,7 +199,12 @@ | |||||||
|  |  | ||||||
| 			Action.handler( e, startLine.aPos, lineMode ); | 			Action.handler( e, startLine.aPos, lineMode ); | ||||||
|  |  | ||||||
| 			if( !IsContMod ) | 			/** | ||||||
|  | 			 * Cursor Modifier: | ||||||
|  | 			 *   Whether the cursor position is already handled | ||||||
|  | 			 **/ | ||||||
|  | 			var IsCurMod = ~[ DELETE, PUT, SHIFT_LINES ].indexOf( Action.constructor ); | ||||||
|  | 			if( !IsCurMod ) | ||||||
| 			{ | 			{ | ||||||
| 				cur.moveTo( startLine.aPos ); | 				cur.moveTo( startLine.aPos ); | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -136,6 +136,7 @@ | |||||||
| 			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 + COMMA; break; | ||||||
| 			case ">": Mod = SHIFT; case ".": kCode = Mod + FULLSTOP; break; | 			case ">": Mod = SHIFT; case ".": kCode = Mod + FULLSTOP; break; | ||||||
|  | 			case "\"": Mod = SHIFT; case "'": kCode = Mod + QUOTE; break; | ||||||
|  |  | ||||||
| 			default: | 			default: | ||||||
| 				throw new Error( "Unsupport keys: " + str ); | 				throw new Error( "Unsupport keys: " + str ); | ||||||
| @@ -477,16 +478,17 @@ | |||||||
| 	{ | 	{ | ||||||
| 		var kCode = e.keyCode; | 		var kCode = e.keyCode; | ||||||
|  |  | ||||||
| 		if( this.__cMovement ) | 		if( this.__captureComp ) | ||||||
| 		{ | 		{ | ||||||
| 			if( !e.ModKeys ) | 			if( !e.ModKeys ) | ||||||
| 			{ | 			{ | ||||||
| 				this.__composite( e ); | 				this.__composite( e ); | ||||||
| 				this.__cMovement = false; | 				this.__captureComp = false; | ||||||
| 				return true; | 				return true; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		var inst = this.__vimArea; | ||||||
| 		var ccur = this.__ccur; | 		var ccur = this.__ccur; | ||||||
| 		var cfeeder = ccur.feeder; | 		var cfeeder = ccur.feeder; | ||||||
|  |  | ||||||
| @@ -609,10 +611,22 @@ | |||||||
|  |  | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
|  | 			case M: | ||||||
|  | 				this.__captureComp = true; | ||||||
|  |  | ||||||
|  | 				var marks = this.__vimArea.marks; | ||||||
|  | 				this.__composite( e, function( e2 ) { | ||||||
|  | 					var line = ccur.getLine().lineNum; | ||||||
|  | 					if( !marks.set( e2.key, line, ccur.aX ) ) | ||||||
|  | 					{ | ||||||
|  | 						beep(); | ||||||
|  | 					} | ||||||
|  | 				}, ANY_KEY ); | ||||||
|  | 				break; | ||||||
|  |  | ||||||
| 			case SHIFT + T: // To | 			case SHIFT + T: // To | ||||||
| 			case T: // To | 			case T: // To | ||||||
| 				this.__cMovement = true; | 				this.__captureComp = true; | ||||||
|  |  | ||||||
| 				this.__composite( e, function( e2 ) { | 				this.__composite( e, function( e2 ) { | ||||||
| 					var oX = ccur.X; | 					var oX = ccur.X; | ||||||
| @@ -631,7 +645,7 @@ | |||||||
| 				break; | 				break; | ||||||
| 			case SHIFT + F: // To | 			case SHIFT + F: // To | ||||||
| 			case F: // To | 			case F: // To | ||||||
| 				this.__cMovement = true; | 				this.__captureComp = true; | ||||||
|  |  | ||||||
| 				this.__composite( e, function( e2 ) { | 				this.__composite( e, function( e2 ) { | ||||||
| 					ccur.openRunAction( "TO", e, e2 ); | 					ccur.openRunAction( "TO", e, e2 ); | ||||||
| @@ -658,7 +672,7 @@ | |||||||
|  |  | ||||||
| 				var analyzer = this.__vimArea.contentAnalyzer; | 				var analyzer = this.__vimArea.contentAnalyzer; | ||||||
|  |  | ||||||
| 				this.__cMovement = true; | 				this.__captureComp = true; | ||||||
|  |  | ||||||
| 				// Word boundary | 				// Word boundary | ||||||
| 				this.__composite( e, function( e2 ) { | 				this.__composite( e, function( e2 ) { | ||||||
| @@ -702,7 +716,7 @@ | |||||||
|  |  | ||||||
| 			case G: | 			case G: | ||||||
|  |  | ||||||
| 				this.__cMovement = true; | 				this.__captureComp = true; | ||||||
|  |  | ||||||
| 				// Go to top | 				// Go to top | ||||||
| 				this.__composite( e, function() { | 				this.__composite( e, function() { | ||||||
| @@ -774,11 +788,35 @@ | |||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| 			case SLASH: // "/" Search movement | 			case SLASH: // "/" Search movement | ||||||
| 				this.__cMovement = true; | 				this.__captureComp = true; | ||||||
|  |  | ||||||
| 				this.__divedCCmd = new ExCommand( ccur, "/" ); | 				this.__divedCCmd = new ExCommand( ccur, "/" ); | ||||||
| 				this.__divedCCmd.handler( e ); | 				this.__divedCCmd.handler( e ); | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
|  | 			case SHIFT + SEMI_COLON: // ":", only happens within action | ||||||
|  | 				if( !ccur.action ) | ||||||
|  | 				{ | ||||||
|  | 					cursorHandled = false; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				this.__captureComp = true; | ||||||
|  |  | ||||||
|  | 				var exCmd = new ExCommand( ccur, ":" ); | ||||||
|  | 				exCmd.handler( e ); | ||||||
|  |  | ||||||
|  | 				// Auto define range '< and '> | ||||||
|  | 				var cSel = ccur.position; | ||||||
|  | 				if( 1 < ( cSel.end - cSel.start ) ) | ||||||
|  | 				{ | ||||||
|  | 					ActionEvent | ||||||
|  | 						.__createEventList( e.sender, "'<,'>" ) | ||||||
|  | 						.forEach( function( e2 ) { exCmd.handler( e2 ); } ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				this.__divedCCmd = exCmd; | ||||||
|  | 				break; | ||||||
| 			default: | 			default: | ||||||
| 				cursorHandled = false; | 				cursorHandled = false; | ||||||
| 		} | 		} | ||||||
| @@ -802,7 +840,7 @@ | |||||||
| 		if( e.Escape ) | 		if( e.Escape ) | ||||||
| 		{ | 		{ | ||||||
| 			var b = false; | 			var b = false; | ||||||
| 			this.__cMovement = false; | 			this.__captureComp = false; | ||||||
|  |  | ||||||
| 			if( this.__compositeReg ) | 			if( this.__compositeReg ) | ||||||
| 			{ | 			{ | ||||||
| @@ -828,7 +866,7 @@ | |||||||
| 			if( this.__divedCCmd.handler( e ) ) | 			if( this.__divedCCmd.handler( e ) ) | ||||||
| 			{ | 			{ | ||||||
| 				this.__divedCCmd.dispose(); | 				this.__divedCCmd.dispose(); | ||||||
| 				this.__cMovement = false; | 				this.__captureComp = false; | ||||||
| 				this.__divedCCmd = null; | 				this.__divedCCmd = null; | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| @@ -839,7 +877,7 @@ | |||||||
| 		var cfeeder = this.__cfeeder; | 		var cfeeder = this.__cfeeder; | ||||||
| 		var ccur = this.__ccur; | 		var ccur = this.__ccur; | ||||||
|  |  | ||||||
| 		if( !this.__cMovement && ( !ccur.action || ccur.action.allowMovement ) ) | 		if( !this.__captureComp && ( !ccur.action || ccur.action.allowMovement ) ) | ||||||
| 		{ | 		{ | ||||||
| 			this.__modCommand( e ); | 			this.__modCommand( e ); | ||||||
| 			if( e.canceled ) return; | 			if( e.canceled ) return; | ||||||
| @@ -861,7 +899,10 @@ | |||||||
| 				{ | 				{ | ||||||
| 					var SubCommand = !this.__compositeReg; | 					var SubCommand = !this.__compositeReg; | ||||||
| 					this.__cursorCommand( e, kCode ); | 					this.__cursorCommand( e, kCode ); | ||||||
| 					if( SubCommand && this.__compositeReg ) |  | ||||||
|  | 					// Check if Sub / Dived composite command has been initiated | ||||||
|  | 					// within the CursorCommand | ||||||
|  | 					if( ( SubCommand && this.__compositeReg ) || this.__divedCCmd ) | ||||||
| 					{ | 					{ | ||||||
| 						e.preventDefault(); | 						e.preventDefault(); | ||||||
| 						return; | 						return; | ||||||
| @@ -927,6 +968,18 @@ | |||||||
| 		this.__range = null; | 		this.__range = null; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	ActionEvent.__createEventList = function( sender, KeyDefs ) | ||||||
|  | 	{ | ||||||
|  | 		var l = KeyDefs.length; | ||||||
|  | 		var List = []; | ||||||
|  | 		for( var i = 0; i < l; i ++ ) | ||||||
|  | 		{ | ||||||
|  | 			List.push( new ActionEvent( sender, KeyDefs[ i ] ) ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return List; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	__readOnly( ActionEvent.prototype, "target", function() { return this.__target; } ); | 	__readOnly( ActionEvent.prototype, "target", function() { return this.__target; } ); | ||||||
| 	__readOnly( ActionEvent.prototype, "key", function() { return this.__key; } ); | 	__readOnly( ActionEvent.prototype, "key", function() { return this.__key; } ); | ||||||
| 	__readOnly( ActionEvent.prototype, "keyCode", function() { return this.__kCode; } ); | 	__readOnly( ActionEvent.prototype, "keyCode", function() { return this.__kCode; } ); | ||||||
|   | |||||||
| @@ -106,6 +106,8 @@ | |||||||
| 	// Move to an absolute position | 	// Move to an absolute position | ||||||
| 	Cursor.prototype.moveTo = function( aPos, phantomSpace, skipTabs ) | 	Cursor.prototype.moveTo = function( aPos, phantomSpace, skipTabs ) | ||||||
| 	{ | 	{ | ||||||
|  | 		this.__suppressUpdate(); | ||||||
|  |  | ||||||
| 		var content = this.feeder.content; | 		var content = this.feeder.content; | ||||||
| 		var pline = this.getLine(); | 		var pline = this.getLine(); | ||||||
| 		var lastLineNum = pline.lineNum; | 		var lastLineNum = pline.lineNum; | ||||||
| @@ -131,17 +133,18 @@ | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		var jumpY = expLineNum - lastLineNum; | 		var jumpY = expLineNum - lastLineNum; | ||||||
| 		if( jumpY ) | 		if( jumpY ) this.moveY( jumpY ); | ||||||
| 		{ |  | ||||||
| 			this.moveY( jumpY ); |  | ||||||
|  |  | ||||||
| 			// Because moveTo is a direct jump function |  | ||||||
| 			// We'll auto reveal the target line here |  | ||||||
| 			if( this.feeder.moreAt == this.Y ) this.moveY( 1 ); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		pline = this.getLine(); | 		pline = this.getLine(); | ||||||
|  |  | ||||||
|  | 		// Because moveTo is a direct jump function | ||||||
|  | 		// We'll have to auto reveal the target line here | ||||||
|  | 		if( pline.lineNum != expLineNum ) | ||||||
|  | 		{ | ||||||
|  | 			this.moveY( expLineNum - pline.lineNum ); | ||||||
|  | 			pline = this.getLine(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart; | 		var jumpX = aPos < lineStart ? lineStart - aPos : aPos - lineStart; | ||||||
| 		var kX = jumpX - pline.content.length; | 		var kX = jumpX - pline.content.length; | ||||||
|  |  | ||||||
| @@ -159,6 +162,50 @@ | |||||||
|  |  | ||||||
| 		this.moveX( - Number.MAX_VALUE, false, false, true ); | 		this.moveX( - Number.MAX_VALUE, false, false, true ); | ||||||
| 		this.moveX( jumpX, false, phantomSpace, skipTabs ); | 		this.moveX( jumpX, false, phantomSpace, skipTabs ); | ||||||
|  |  | ||||||
|  | 		this.__unsuppressUpdate(); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	// A line-only variant of moveTo, de-generalized for the sake of performance | ||||||
|  | 	Cursor.prototype.gotoLine = function( n ) | ||||||
|  | 	{ | ||||||
|  | 		this.__suppressUpdate(); | ||||||
|  |  | ||||||
|  | 		var content = this.feeder.content; | ||||||
|  | 		var pline = this.getLine(); | ||||||
|  | 		var lastLineNum = pline.lineNum; | ||||||
|  |  | ||||||
|  | 		if( pline.placeholder ) | ||||||
|  | 		{ | ||||||
|  | 			lastLineNum = 0; | ||||||
|  | 			this.Y = 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var expLineNum = 0; | ||||||
|  | 		var lineStart = 0; | ||||||
|  | 		for( var i = content.indexOf( "\n" ); 0 <= i ; i = content.indexOf( "\n", i ) ) | ||||||
|  | 		{ | ||||||
|  | 			if( expLineNum == n ) break; | ||||||
|  | 			lineStart = i; | ||||||
|  | 			i ++; | ||||||
|  | 			expLineNum ++; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if( expLineNum < n ) n = expLineNum; | ||||||
|  |  | ||||||
|  | 		var jumpY = expLineNum - lastLineNum; | ||||||
|  | 		if( jumpY ) this.moveY( jumpY ); | ||||||
|  |  | ||||||
|  | 		pline = this.getLine(); | ||||||
|  |  | ||||||
|  | 		if( pline.lineNum != expLineNum ) | ||||||
|  | 		{ | ||||||
|  | 			this.moveY( expLineNum - pline.lineNum ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		this.lineStart( true ); | ||||||
|  |  | ||||||
|  | 		this.__unsuppressUpdate(); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	// 0 will be treated as default ( 1 ) | 	// 0 will be treated as default ( 1 ) | ||||||
| @@ -319,7 +366,7 @@ | |||||||
| 		else if( c == "\n" ) | 		else if( c == "\n" ) | ||||||
| 		{ | 		{ | ||||||
| 			x += d; | 			x += d; | ||||||
| 		} | 	} | ||||||
|  |  | ||||||
| 		// Wordwrap phantomSpace movement compensation on max filled lines | 		// Wordwrap phantomSpace movement compensation on max filled lines | ||||||
| 		if( feeder.wrap && boundary && !hasPhantomSpace && phantomSpace ) | 		if( feeder.wrap && boundary && !hasPhantomSpace && phantomSpace ) | ||||||
| @@ -365,10 +412,12 @@ | |||||||
| 		this.moveX( Number.MAX_VALUE, false, phantomSpace, true ); | 		this.moveX( Number.MAX_VALUE, false, phantomSpace, true ); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	// Because LineOffset is costly, suppress unnecessary calls | ||||||
| 	Cursor.prototype.updatePosition = function() | 	Cursor.prototype.updatePosition = function() | ||||||
| 	{ | 	{ | ||||||
| 		var feeder = this.feeder; | 		if( 0 < this.__suppUpdate ) return; | ||||||
| 		var P = this.X + LineOffset( feeder.lineBuffers, this.Y ) + this.__off; |  | ||||||
|  | 		var P = this.X + LineOffset( this.feeder.lineBuffers, this.Y ) + this.__off; | ||||||
|  |  | ||||||
| 		this.PStart = P; | 		this.PStart = P; | ||||||
| 		this.PEnd = P + 1; | 		this.PEnd = P + 1; | ||||||
| @@ -534,6 +583,13 @@ | |||||||
| 	Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; }; | 	Cursor.prototype.suppressEvent = function() { ++ this.__suppEvt; }; | ||||||
| 	Cursor.prototype.unsuppressEvent = function() { -- this.__suppEvt; }; | 	Cursor.prototype.unsuppressEvent = function() { -- this.__suppEvt; }; | ||||||
|  |  | ||||||
|  | 	Cursor.prototype.__suppressUpdate = function() { ++ this.__suppUpdate; }; | ||||||
|  | 	Cursor.prototype.__unsuppressUpdate = function() | ||||||
|  | 	{ | ||||||
|  | 		-- this.__suppUpdate; | ||||||
|  | 		this.updatePosition(); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	Cursor.prototype.getLine = function( display ) | 	Cursor.prototype.getLine = function( display ) | ||||||
| 	{ | 	{ | ||||||
| 		var feeder = this.feeder; | 		var feeder = this.feeder; | ||||||
| @@ -564,20 +620,7 @@ | |||||||
|  |  | ||||||
| 	__readOnly( Cursor.prototype, "rawLine", function() | 	__readOnly( Cursor.prototype, "rawLine", function() | ||||||
| 	{ | 	{ | ||||||
| 		var str = this.feeder.content; | 		return this.feeder.line( this.getLine().lineNum - 1 ); | ||||||
| 		var lineNum = this.getLine().lineNum - 1; |  | ||||||
| 		var i = str.indexOf( "\n" ), j = 0; |  | ||||||
|  |  | ||||||
| 		for( ; 0 <= i; i = str.indexOf( "\n", i ), j ++ ) |  | ||||||
| 		{ |  | ||||||
| 			if( lineNum == j ) break; |  | ||||||
| 			i ++; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if( j == 0 && i == -1 ) i = 0; |  | ||||||
|  |  | ||||||
| 		var end = str.indexOf( "\n", i + 1 ); |  | ||||||
| 		return str.substring( i + 1, end ); |  | ||||||
| 	} ); | 	} ); | ||||||
|  |  | ||||||
| 	// The position offset relative to current line | 	// The position offset relative to current line | ||||||
| @@ -598,7 +641,8 @@ | |||||||
| 			// because phantomSpace is not a valid character | 			// because phantomSpace is not a valid character | ||||||
| 			// So we calculate along with the phantomSpace here | 			// So we calculate along with the phantomSpace here | ||||||
| 			var phantomSpace = X; | 			var phantomSpace = X; | ||||||
| 			for( var i in lines ) | 			var lc = lines.length; | ||||||
|  | 			for( var i = 0; i < lc; i ++ ) | ||||||
| 			{ | 			{ | ||||||
| 				/** @type {Components.Vim.LineBuffer} */ | 				/** @type {Components.Vim.LineBuffer} */ | ||||||
| 				var vline = lines[ i ]; | 				var vline = lines[ i ]; | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ | |||||||
| 	var Cursor = ns[ NS_INVOKE ]( "Cursor" ); | 	var Cursor = ns[ NS_INVOKE ]( "Cursor" ); | ||||||
|  |  | ||||||
| 	var occurence = __import( "System.utils.Perf.CountSubstr" ); | 	var occurence = __import( "System.utils.Perf.CountSubstr" ); | ||||||
|  | 	var C_LINE = 0; | ||||||
|  |  | ||||||
| 	var Feeder = function( rows, cols ) | 	var Feeder = function( rows, cols ) | ||||||
| 	{ | 	{ | ||||||
| @@ -35,6 +36,7 @@ | |||||||
| 		this.cursor = new Cursor( this ); | 		this.cursor = new Cursor( this ); | ||||||
| 		this.dispatcher = new EventDispatcher(); | 		this.dispatcher = new EventDispatcher(); | ||||||
|  |  | ||||||
|  | 		this.__lineCache = []; | ||||||
| 		this.__clseLine = null; | 		this.__clseLine = null; | ||||||
| 		this.__moreAt = -1; | 		this.__moreAt = -1; | ||||||
| 		this.__rows = rows; | 		this.__rows = rows; | ||||||
| @@ -42,7 +44,7 @@ | |||||||
|  |  | ||||||
| 	Feeder.prototype.init = function( content, wrap ) | 	Feeder.prototype.init = function( content, wrap ) | ||||||
| 	{ | 	{ | ||||||
| 		this.content = content; | 		this.__content = content; | ||||||
| 		this.setWrap( wrap ); | 		this.setWrap( wrap ); | ||||||
|  |  | ||||||
| 		this.firstBuffer.Push( content, this.wrap, 0 );  | 		this.firstBuffer.Push( content, this.wrap, 0 );  | ||||||
| @@ -142,7 +144,7 @@ | |||||||
| 		if( Y < 0 ) Y = 0; | 		if( Y < 0 ) Y = 0; | ||||||
|  |  | ||||||
| 		// Compensate the last "\n" content placeholder | 		// Compensate the last "\n" content placeholder | ||||||
| 		var cont = this.content.slice( 0, -1 ); | 		var cont = this.__content.slice( 0, -1 ); | ||||||
| 		if( 0 < Y ) | 		if( 0 < Y ) | ||||||
| 		{ | 		{ | ||||||
| 			f = cont.indexOf( "\n" ); | 			f = cont.indexOf( "\n" ); | ||||||
| @@ -158,7 +160,7 @@ | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		this.firstBuffer.Push( this.content.substr( f + 1 ), this.wrap, i ); | 		this.firstBuffer.Push( this.__content.substr( f + 1 ), this.wrap, i ); | ||||||
|  |  | ||||||
| 		this.panX = X; | 		this.panX = X; | ||||||
| 		this.panY = Y; | 		this.panY = Y; | ||||||
| @@ -171,8 +173,27 @@ | |||||||
| 		this.__softRender(); | 		this.__softRender(); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	Feeder.prototype.line = function( n ) | ||||||
|  | 	{ | ||||||
|  | 		if( this.__lineCache[ n ] ) | ||||||
|  | 			return this.__lineCache[ n ]; | ||||||
|  | 		var str = this.__content; | ||||||
|  | 		var i = str.indexOf( "\n" ), j = 0; | ||||||
|  |  | ||||||
|  | 		for( ; 0 <= i; i = str.indexOf( "\n", i ), j ++ ) | ||||||
|  | 		{ | ||||||
|  | 			if( n == j ) break; | ||||||
|  | 			i ++; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if( j == 0 && i == -1 ) i = 0; | ||||||
|  |  | ||||||
|  | 		var end = str.indexOf( "\n", i + 1 ); | ||||||
|  | 		return ( this.__lineCache[ n ] = str.substring( i + 1, end ) ); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	__readOnly( Feeder.prototype, "linesTotal", function() { | 	__readOnly( Feeder.prototype, "linesTotal", function() { | ||||||
| 		return occurence( this.content, "\n" ); | 		return occurence( this.__content, "\n" ); | ||||||
| 	} ); | 	} ); | ||||||
|  |  | ||||||
| 	__readOnly( Feeder.prototype, "firstBuffer", function() { | 	__readOnly( Feeder.prototype, "firstBuffer", function() { | ||||||
| @@ -216,7 +237,7 @@ | |||||||
| 		var i = l - X; | 		var i = l - X; | ||||||
| 		do | 		do | ||||||
| 		{ | 		{ | ||||||
| 			if( this.content[ i + 1 ] == "\t" ) tabs ++; | 			if( this.__content[ i + 1 ] == "\t" ) tabs ++; | ||||||
| 			i ++; | 			i ++; | ||||||
| 		} | 		} | ||||||
| 		while( i < l ) | 		while( i < l ) | ||||||
| @@ -254,6 +275,15 @@ | |||||||
| 		return pos; | 		return pos; | ||||||
| 	} ); | 	} ); | ||||||
|  |  | ||||||
|  | 	Object.defineProperty( Feeder.prototype, "content", { | ||||||
|  | 		get: function() { return this.__content; } | ||||||
|  | 		, set: function( v ) | ||||||
|  | 		{ | ||||||
|  | 			this.__lineCache = []; | ||||||
|  | 			this.__content = v; | ||||||
|  | 		} | ||||||
|  | 	} ); | ||||||
|  |  | ||||||
| 	__readOnly( Feeder.prototype, "linesOccupied", function() { | 	__readOnly( Feeder.prototype, "linesOccupied", function() { | ||||||
| 		var line = this.firstBuffer; | 		var line = this.firstBuffer; | ||||||
| 		if( line.placeholder ) return 0; | 		if( line.placeholder ) return 0; | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								botanjs/src/Components/Vim/State/Marks.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								botanjs/src/Components/Vim/State/Marks.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | (function(){ | ||||||
|  | 	var ns = __namespace( "Components.Vim.State" ); | ||||||
|  |  | ||||||
|  | 	/** @type {System.Debug} */ | ||||||
|  | 	var debug = __import( "System.Debug" ); | ||||||
|  |  | ||||||
|  | 	var Keys = "'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy\"[]^.<>"; | ||||||
|  |  | ||||||
|  | 	var Marks = function() | ||||||
|  | 	{ | ||||||
|  | 		this.__marks = {}; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	Marks.prototype.set = function( t, line, col ) | ||||||
|  | 	{ | ||||||
|  | 		if( Keys.indexOf( t ) == -1 ) return false; | ||||||
|  |  | ||||||
|  | 		this.__marks[ t ] = [ line, col ]; | ||||||
|  | 		return true; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	Marks.prototype.get = function( t ) | ||||||
|  | 	{ | ||||||
|  | 		return this.__marks[ t ]; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	__readOnly( Marks, "Keys", function() { return Keys; } ); | ||||||
|  |  | ||||||
|  | 	ns[ NS_EXPORT ]( EX_CLASS, "Marks", Marks ); | ||||||
|  |  | ||||||
|  | })(); | ||||||
| @@ -14,6 +14,8 @@ | |||||||
|  |  | ||||||
| 	/** @type {Components.Vim.State.Registers} */ | 	/** @type {Components.Vim.State.Registers} */ | ||||||
| 	var Registers                                 = __import( "Components.Vim.State.Registers" ); | 	var Registers                                 = __import( "Components.Vim.State.Registers" ); | ||||||
|  | 	/** @type {Components.Vim.State.Marks} */ | ||||||
|  | 	var Marks                                     = __import( "Components.Vim.State.Marks" ); | ||||||
| 	/** @type {Components.Vim.Syntax.Analyzer} */ | 	/** @type {Components.Vim.Syntax.Analyzer} */ | ||||||
| 	var SyntaxAnalyzer                            = __import( "Components.Vim.Syntax.Analyzer" ); | 	var SyntaxAnalyzer                            = __import( "Components.Vim.Syntax.Analyzer" ); | ||||||
|  |  | ||||||
| @@ -58,10 +60,10 @@ | |||||||
| 			throw new Error( "This element is not compatible for VimArea" ); | 			throw new Error( "This element is not compatible for VimArea" ); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		for( var i in Insts ) | 		for( var i = 0; i < InstIndex; i ++ ) | ||||||
| 		{ | 		{ | ||||||
| 			var inst = Insts[ i ]; | 			var inst = Insts[ i ]; | ||||||
| 			if( inst.stage.element == element ) | 			if( inst && inst.stage.element == element ) | ||||||
| 			{ | 			{ | ||||||
| 				debug.Info( "Instance exists" ); | 				debug.Info( "Instance exists" ); | ||||||
| 				return inst; | 				return inst; | ||||||
| @@ -243,6 +245,7 @@ | |||||||
| 		this.statusFeeder = sfeeder; | 		this.statusFeeder = sfeeder; | ||||||
| 		this.statusBar = statusBar; | 		this.statusBar = statusBar; | ||||||
| 		this.registers = new Registers(); | 		this.registers = new Registers(); | ||||||
|  | 		this.marks = new Marks(); | ||||||
|  |  | ||||||
| 		this.__cursor = cfeeder.cursor; | 		this.__cursor = cfeeder.cursor; | ||||||
|  |  | ||||||
| @@ -387,7 +390,12 @@ | |||||||
|  |  | ||||||
| 	__readOnly( VimArea, "Instances", function() { | 	__readOnly( VimArea, "Instances", function() { | ||||||
| 		var clone = []; | 		var clone = []; | ||||||
| 		for( var i in Insts ) clone.push( Insts[ i ] ); |  | ||||||
|  | 		for( var i = 0; i < InstIndex; i ++ ) | ||||||
|  | 		{ | ||||||
|  | 			if( Insts[ i ] ) clone.push( Insts[ i ] ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return clone; | 		return clone; | ||||||
| 	} ); | 	} ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,6 +13,8 @@ Components.Vim.Cursor.rec; | |||||||
| /** @type Function */ | /** @type Function */ | ||||||
| Components.Vim.Cursor.moveTo; | Components.Vim.Cursor.moveTo; | ||||||
| /** @type Function */ | /** @type Function */ | ||||||
|  | Components.Vim.Cursor.gotoLine; | ||||||
|  | /** @type Function */ | ||||||
| Components.Vim.Cursor.moveX; | Components.Vim.Cursor.moveX; | ||||||
| /** @type Function */ | /** @type Function */ | ||||||
| Components.Vim.Cursor.moveY; | Components.Vim.Cursor.moveY; | ||||||
|   | |||||||
| @@ -43,6 +43,8 @@ Components.Vim.LineFeeder.linesOccupied; | |||||||
| /** @type String */ | /** @type String */ | ||||||
| Components.Vim.LineFeeder.docPos; | Components.Vim.LineFeeder.docPos; | ||||||
| /** @type String */ | /** @type String */ | ||||||
|  | Components.Vim.LineFeeder.line; | ||||||
|  | /** @type String */ | ||||||
| Components.Vim.LineFeeder.lineStat; | Components.Vim.LineFeeder.lineStat; | ||||||
| /** @type {String} */ | /** @type {String} */ | ||||||
| Components.Vim.LineFeeder.content; | Components.Vim.LineFeeder.content; | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								botanjs/src/externs/Components.Vim.State.Marks.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								botanjs/src/externs/Components.Vim.State.Marks.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | /** @constructor */ | ||||||
|  | Components.Vim.State.Marks = function(){}; | ||||||
|  |  | ||||||
|  | /** @type Function */ | ||||||
|  | Components.Vim.State.Marks.set; | ||||||
|  | /** @type Function */ | ||||||
|  | Components.Vim.State.Marks.get; | ||||||
|  |  | ||||||
|  | /** @type String */ | ||||||
|  | Components.Vim.State.Marks.Keys; | ||||||
| @@ -12,6 +12,11 @@ Components.Vim.VimArea.statusFeeder; | |||||||
| /** @type {Components.Vim.StatusBar} */ | /** @type {Components.Vim.StatusBar} */ | ||||||
| Components.Vim.VimArea.statusBar; | Components.Vim.VimArea.statusBar; | ||||||
|  |  | ||||||
|  | /** @type {Components.Vim.State.Registers} */ | ||||||
|  | Components.Vim.VimArea.registers; | ||||||
|  | /** @type {Components.Vim.State.Marks} */ | ||||||
|  | Components.Vim.VimArea.marks; | ||||||
|  |  | ||||||
| /** @type Function */ | /** @type Function */ | ||||||
| Components.Vim.VimArea.demo; | Components.Vim.VimArea.demo; | ||||||
| /** @type Function */ | /** @type Function */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user