mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(api): make nvim_parse_cmd work correctly with both range and count
				
					
				
			It seems range and count can be used together in commands. This PR fixes the behavior of `nvim_parse_cmd` for those cases by removing the mutual exclusivity of "range" and "count". It also removes range line number validation for `nvim_parse_cmd` as it's not its job to validate the command.
This commit is contained in:
		| @@ -1782,8 +1782,7 @@ nvim_parse_cmd({str}, {opts})                               *nvim_parse_cmd()* | |||||||
|                       item was specified and two elements if both range items |                       item was specified and two elements if both range items | ||||||
|                       were specified. |                       were specified. | ||||||
|                     • count: (number) Any |<count>| that was supplied to the |                     • count: (number) Any |<count>| that was supplied to the | ||||||
|                       command. -1 if command cannot take a count. Mutually |                       command. -1 if command cannot take a count. | ||||||
|                       exclusive with "range". |  | ||||||
|                     • reg: (number) The optional command |<register>|, if |                     • reg: (number) The optional command |<register>|, if | ||||||
|                       specified. Empty string if not specified or if command |                       specified. Empty string if not specified or if command | ||||||
|                       cannot take a register. |                       cannot take a register. | ||||||
|   | |||||||
| @@ -752,7 +752,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E | |||||||
| ///                          no range was specified, one element if only a single range item was | ///                          no range was specified, one element if only a single range item was | ||||||
| ///                          specified and two elements if both range items were specified. | ///                          specified and two elements if both range items were specified. | ||||||
| ///         - count: (number) Any |<count>| that was supplied to the command. -1 if command cannot | ///         - count: (number) Any |<count>| that was supplied to the command. -1 if command cannot | ||||||
| ///                           take a count. Mutually exclusive with "range". | ///                           take a count. | ||||||
| ///         - reg: (number) The optional command |<register>|, if specified. Empty string if not | ///         - reg: (number) The optional command |<register>|, if specified. Empty string if not | ||||||
| ///                         specified or if command cannot take a register. | ///                         specified or if command cannot take a register. | ||||||
| ///         - bang: (boolean) Whether command contains a |<bang>| (!) modifier. | ///         - bang: (boolean) Whether command contains a |<bang>| (!) modifier. | ||||||
| @@ -853,7 +853,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) | |||||||
|     PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx))); |     PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx))); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if ((ea.argt & EX_RANGE) && !(ea.argt & EX_COUNT) && ea.addr_count > 0) { |   if ((ea.argt & EX_RANGE) && ea.addr_count > 0) { | ||||||
|     Array range = ARRAY_DICT_INIT; |     Array range = ARRAY_DICT_INIT; | ||||||
|     if (ea.addr_count > 1) { |     if (ea.addr_count > 1) { | ||||||
|       ADD(range, INTEGER_OBJ(ea.line1)); |       ADD(range, INTEGER_OBJ(ea.line1)); | ||||||
|   | |||||||
| @@ -1320,7 +1320,7 @@ static void parse_register(exarg_T *eap) | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| static int parse_count(exarg_T *eap, char **errormsg) | static int parse_count(exarg_T *eap, char **errormsg, bool validate) | ||||||
| { | { | ||||||
|   // Check for a count.  When accepting a EX_BUFNAME, don't use "123foo" as a |   // Check for a count.  When accepting a EX_BUFNAME, don't use "123foo" as a | ||||||
|   // count, it's a buffer name. |   // count, it's a buffer name. | ||||||
| @@ -1348,7 +1348,7 @@ static int parse_count(exarg_T *eap, char **errormsg) | |||||||
|       eap->line2 += n - 1; |       eap->line2 += n - 1; | ||||||
|       eap->addr_count++; |       eap->addr_count++; | ||||||
|       // Be vi compatible: no error message for out of range. |       // Be vi compatible: no error message for out of range. | ||||||
|       if (eap->line2 > curbuf->b_ml.ml_line_count) { |       if (validate && eap->line2 > curbuf->b_ml.ml_line_count) { | ||||||
|         eap->line2 = curbuf->b_ml.ml_line_count; |         eap->line2 = curbuf->b_ml.ml_line_count; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -1426,7 +1426,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er | |||||||
|   } |   } | ||||||
|   p = find_command(eap, NULL); |   p = find_command(eap, NULL); | ||||||
|  |  | ||||||
|   // Set command attribute type and parse command range |   // Set command address type and parse command range | ||||||
|   set_cmd_addr_type(eap, (char_u *)p); |   set_cmd_addr_type(eap, (char_u *)p); | ||||||
|   eap->cmd = cmd; |   eap->cmd = cmd; | ||||||
|   if (parse_cmd_address(eap, errormsg, false) == FAIL) { |   if (parse_cmd_address(eap, errormsg, false) == FAIL) { | ||||||
| @@ -1499,7 +1499,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er | |||||||
|  |  | ||||||
|   // Parse register and count |   // Parse register and count | ||||||
|   parse_register(eap); |   parse_register(eap); | ||||||
|   if (parse_count(eap, errormsg) == FAIL) { |   if (parse_count(eap, errormsg, false) == FAIL) { | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -1981,7 +1981,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter | |||||||
|  |  | ||||||
|   // Parse register and count |   // Parse register and count | ||||||
|   parse_register(&ea); |   parse_register(&ea); | ||||||
|   if (parse_count(&ea, &errormsg) == FAIL) { |   if (parse_count(&ea, &errormsg, true) == FAIL) { | ||||||
|     goto doend; |     goto doend; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3176,7 +3176,7 @@ describe('API', function() | |||||||
|         cmd = 'buffer', |         cmd = 'buffer', | ||||||
|         args = {}, |         args = {}, | ||||||
|         bang = false, |         bang = false, | ||||||
|         range = {}, |         range = { 1 }, | ||||||
|         count = 1, |         count = 1, | ||||||
|         reg = '', |         reg = '', | ||||||
|         addr = 'buf', |         addr = 'buf', | ||||||
| @@ -3243,6 +3243,42 @@ describe('API', function() | |||||||
|         } |         } | ||||||
|       }, meths.parse_cmd('put +', {})) |       }, meths.parse_cmd('put +', {})) | ||||||
|     end) |     end) | ||||||
|  |     it('works with range, count and register', function() | ||||||
|  |       eq({ | ||||||
|  |         cmd = 'delete', | ||||||
|  |         args = {}, | ||||||
|  |         bang = false, | ||||||
|  |         range = { 3, 7 }, | ||||||
|  |         count = 7, | ||||||
|  |         reg = '*', | ||||||
|  |         addr = 'line', | ||||||
|  |         magic = { | ||||||
|  |             file = false, | ||||||
|  |             bar = true | ||||||
|  |         }, | ||||||
|  |         nargs = '0', | ||||||
|  |         nextcmd = '', | ||||||
|  |         mods = { | ||||||
|  |           browse = false, | ||||||
|  |           confirm = false, | ||||||
|  |           emsg_silent = false, | ||||||
|  |           hide = false, | ||||||
|  |           keepalt = false, | ||||||
|  |           keepjumps = false, | ||||||
|  |           keepmarks = false, | ||||||
|  |           keeppatterns = false, | ||||||
|  |           lockmarks = false, | ||||||
|  |           noautocmd = false, | ||||||
|  |           noswapfile = false, | ||||||
|  |           sandbox = false, | ||||||
|  |           silent = false, | ||||||
|  |           vertical = false, | ||||||
|  |           split = "", | ||||||
|  |           tab = 0, | ||||||
|  |           verbose = -1 | ||||||
|  |         } | ||||||
|  |       }, meths.parse_cmd('1,3delete * 5', {})) | ||||||
|  |     end) | ||||||
|     it('works with bang', function() |     it('works with bang', function() | ||||||
|       eq({ |       eq({ | ||||||
|         cmd = 'write', |         cmd = 'write', | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Famiu Haque
					Famiu Haque