vi: allow line addresses to have an offset
Line addresses in colon commands can be defined using an expression that includes '+' or '-' operators. The implementation follows traditional vi: - The first term in the expression defines an address. It can be an absolute line number, '.', '$', a search or a marker. - The second and subsequent terms must be non-negative integers. - If the first term is missing '.' is assumed. If the operator is missing addition is assumed. If the final term in missing an offset of 1 is assumed. Thus the following are valid addresses: .+1 .+ + .1 .-1 .- - The following are not valid (though they are in vim): .+$ .$ 2+. function old new delta colon 3701 3844 +143 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 143/0) Total: 143 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		
				
					committed by
					
						
						Denys Vlasenko
					
				
			
			
				
	
			
			
			
						parent
						
							47f78913f7
						
					
				
				
					commit
					f227726838
				
			
							
								
								
									
										124
									
								
								editors/vi.c
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								editors/vi.c
									
									
									
									
									
								
							@@ -2342,67 +2342,93 @@ static char *char_search(char *p, const char *pat, int dir_and_range)
 | 
			
		||||
 | 
			
		||||
//----- The Colon commands -------------------------------------
 | 
			
		||||
#if ENABLE_FEATURE_VI_COLON
 | 
			
		||||
static char *get_one_address(char *p, int *addr)	// get colon addr, if present
 | 
			
		||||
static char *get_one_address(char *p, int *result)	// get colon addr, if present
 | 
			
		||||
{
 | 
			
		||||
	int st;
 | 
			
		||||
	int st, num, sign, addr, new_addr;
 | 
			
		||||
# if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH
 | 
			
		||||
	char *q, c;
 | 
			
		||||
# endif
 | 
			
		||||
	IF_FEATURE_VI_SEARCH(int dir;)
 | 
			
		||||
 | 
			
		||||
	*addr = -1;			// assume no addr
 | 
			
		||||
	if (*p == '.') {	// the current line
 | 
			
		||||
		p++;
 | 
			
		||||
		*addr = count_lines(text, dot);
 | 
			
		||||
	}
 | 
			
		||||
# if ENABLE_FEATURE_VI_YANKMARK
 | 
			
		||||
	else if (*p == '\'') {	// is this a mark addr
 | 
			
		||||
		p++;
 | 
			
		||||
		c = tolower(*p);
 | 
			
		||||
		p++;
 | 
			
		||||
		q = NULL;
 | 
			
		||||
		if (c >= 'a' && c <= 'z') {
 | 
			
		||||
			// we have a mark
 | 
			
		||||
			c = c - 'a';
 | 
			
		||||
			q = mark[(unsigned char) c];
 | 
			
		||||
	addr = -1;			// assume no addr
 | 
			
		||||
	sign = 0;
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		new_addr = -1;
 | 
			
		||||
		if (isblank(*p)) {
 | 
			
		||||
			p++;
 | 
			
		||||
		} else if (*p == '.') {	// the current line
 | 
			
		||||
			p++;
 | 
			
		||||
			new_addr = count_lines(text, dot);
 | 
			
		||||
		}
 | 
			
		||||
# if ENABLE_FEATURE_VI_YANKMARK
 | 
			
		||||
		else if (*p == '\'') {	// is this a mark addr
 | 
			
		||||
			p++;
 | 
			
		||||
			c = tolower(*p);
 | 
			
		||||
			p++;
 | 
			
		||||
			q = NULL;
 | 
			
		||||
			if (c >= 'a' && c <= 'z') {
 | 
			
		||||
				// we have a mark
 | 
			
		||||
				c = c - 'a';
 | 
			
		||||
				q = mark[(unsigned char) c];
 | 
			
		||||
			}
 | 
			
		||||
			if (q == NULL)	// is mark valid
 | 
			
		||||
				return NULL;
 | 
			
		||||
			new_addr = count_lines(text, q);
 | 
			
		||||
		}
 | 
			
		||||
		if (q == NULL)	// is mark valid
 | 
			
		||||
			return NULL;
 | 
			
		||||
		*addr = count_lines(text, q);
 | 
			
		||||
	}
 | 
			
		||||
# endif
 | 
			
		||||
# if ENABLE_FEATURE_VI_SEARCH
 | 
			
		||||
	else if (*p == '/' || *p == '?') {	// a search pattern
 | 
			
		||||
		c = *p;
 | 
			
		||||
		q = strchrnul(p + 1, c);
 | 
			
		||||
		if (p + 1 != q) {
 | 
			
		||||
			// save copy of new pattern
 | 
			
		||||
			free(last_search_pattern);
 | 
			
		||||
			last_search_pattern = xstrndup(p, q - p);
 | 
			
		||||
		else if (*p == '/' || *p == '?') {	// a search pattern
 | 
			
		||||
			c = *p;
 | 
			
		||||
			q = strchrnul(p + 1, c);
 | 
			
		||||
			if (p + 1 != q) {
 | 
			
		||||
				// save copy of new pattern
 | 
			
		||||
				free(last_search_pattern);
 | 
			
		||||
				last_search_pattern = xstrndup(p, q - p);
 | 
			
		||||
			}
 | 
			
		||||
			p = q;
 | 
			
		||||
			if (*p == c)
 | 
			
		||||
				p++;
 | 
			
		||||
			if (c == '/') {
 | 
			
		||||
				q = next_line(dot);
 | 
			
		||||
				dir = (FORWARD << 1) | FULL;
 | 
			
		||||
			} else {
 | 
			
		||||
				q = begin_line(dot);
 | 
			
		||||
				dir = ((unsigned)BACK << 1) | FULL;
 | 
			
		||||
			}
 | 
			
		||||
			q = char_search(q, last_search_pattern + 1, dir);
 | 
			
		||||
			if (q == NULL)
 | 
			
		||||
				return NULL;
 | 
			
		||||
			new_addr = count_lines(text, q);
 | 
			
		||||
		}
 | 
			
		||||
		p = q;
 | 
			
		||||
		if (*p == c)
 | 
			
		||||
			p++;
 | 
			
		||||
		if (c == '/') {
 | 
			
		||||
			q = next_line(dot);
 | 
			
		||||
			dir = (FORWARD << 1) | FULL;
 | 
			
		||||
		} else {
 | 
			
		||||
			q = begin_line(dot);
 | 
			
		||||
			dir = ((unsigned)BACK << 1) | FULL;
 | 
			
		||||
		}
 | 
			
		||||
		q = char_search(q, last_search_pattern + 1, dir);
 | 
			
		||||
		if (q == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		*addr = count_lines(text, q);
 | 
			
		||||
	}
 | 
			
		||||
# endif
 | 
			
		||||
	else if (*p == '$') {	// the last line in file
 | 
			
		||||
		p++;
 | 
			
		||||
		*addr = count_lines(text, end - 1);
 | 
			
		||||
	} else if (isdigit(*p)) {	// specific line number
 | 
			
		||||
		sscanf(p, "%d%n", addr, &st);
 | 
			
		||||
		p += st;
 | 
			
		||||
		else if (*p == '$') {	// the last line in file
 | 
			
		||||
			p++;
 | 
			
		||||
			new_addr = count_lines(text, end - 1);
 | 
			
		||||
		} else if (isdigit(*p)) {
 | 
			
		||||
			sscanf(p, "%d%n", &num, &st);
 | 
			
		||||
			p += st;
 | 
			
		||||
			if (addr < 0) {	// specific line number
 | 
			
		||||
				addr = num;
 | 
			
		||||
			} else {	// offset from current addr
 | 
			
		||||
				addr += sign >= 0 ? num : -num;
 | 
			
		||||
			}
 | 
			
		||||
			sign = 0;
 | 
			
		||||
		} else if (*p == '-' || *p == '+') {
 | 
			
		||||
			sign = *p++ == '-' ? -1 : 1;
 | 
			
		||||
			if (addr < 0) {	// default address is dot
 | 
			
		||||
				addr = count_lines(text, dot);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			addr += sign;	// consume unused trailing sign
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		if (new_addr >= 0) {
 | 
			
		||||
			if (addr >= 0)	// only one new address per expression
 | 
			
		||||
				return NULL;
 | 
			
		||||
			addr = new_addr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	*result = addr;
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user