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:
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 -------------------------------------
|
//----- The Colon commands -------------------------------------
|
||||||
#if ENABLE_FEATURE_VI_COLON
|
#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
|
# if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH
|
||||||
char *q, c;
|
char *q, c;
|
||||||
# endif
|
# endif
|
||||||
IF_FEATURE_VI_SEARCH(int dir;)
|
IF_FEATURE_VI_SEARCH(int dir;)
|
||||||
|
|
||||||
*addr = -1; // assume no addr
|
addr = -1; // assume no addr
|
||||||
if (*p == '.') { // the current line
|
sign = 0;
|
||||||
p++;
|
for (;;) {
|
||||||
*addr = count_lines(text, dot);
|
new_addr = -1;
|
||||||
}
|
if (isblank(*p)) {
|
||||||
# if ENABLE_FEATURE_VI_YANKMARK
|
p++;
|
||||||
else if (*p == '\'') { // is this a mark addr
|
} else if (*p == '.') { // the current line
|
||||||
p++;
|
p++;
|
||||||
c = tolower(*p);
|
new_addr = count_lines(text, dot);
|
||||||
p++;
|
}
|
||||||
q = NULL;
|
# if ENABLE_FEATURE_VI_YANKMARK
|
||||||
if (c >= 'a' && c <= 'z') {
|
else if (*p == '\'') { // is this a mark addr
|
||||||
// we have a mark
|
p++;
|
||||||
c = c - 'a';
|
c = tolower(*p);
|
||||||
q = mark[(unsigned char) c];
|
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
|
# endif
|
||||||
# if ENABLE_FEATURE_VI_SEARCH
|
# if ENABLE_FEATURE_VI_SEARCH
|
||||||
else if (*p == '/' || *p == '?') { // a search pattern
|
else if (*p == '/' || *p == '?') { // a search pattern
|
||||||
c = *p;
|
c = *p;
|
||||||
q = strchrnul(p + 1, c);
|
q = strchrnul(p + 1, c);
|
||||||
if (p + 1 != q) {
|
if (p + 1 != q) {
|
||||||
// save copy of new pattern
|
// save copy of new pattern
|
||||||
free(last_search_pattern);
|
free(last_search_pattern);
|
||||||
last_search_pattern = xstrndup(p, q - p);
|
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
|
# endif
|
||||||
else if (*p == '$') { // the last line in file
|
else if (*p == '$') { // the last line in file
|
||||||
p++;
|
p++;
|
||||||
*addr = count_lines(text, end - 1);
|
new_addr = count_lines(text, end - 1);
|
||||||
} else if (isdigit(*p)) { // specific line number
|
} else if (isdigit(*p)) {
|
||||||
sscanf(p, "%d%n", addr, &st);
|
sscanf(p, "%d%n", &num, &st);
|
||||||
p += 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;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user