aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2017-01-13 15:40:48 +0100
committerMarc André Tanner <mat@brain-dump.org>2017-01-13 15:40:48 +0100
commit104df30ff09cb14e2806f3089dde4ade62d29604 (patch)
treef239a03f2f0ed993f2b113ee57064ec9ff7a9646
parent4600b76efe80c9ba0461276412e58992d2300cae (diff)
downloadvis-104df30ff09cb14e2806f3089dde4ade62d29604.tar.gz
vis-104df30ff09cb14e2806f3089dde4ade62d29604.tar.xz
sam: allow input text to refer to search registers
& refers to the most recent complete match and \1 - \9 refer to the last sub-expression matches.
-rw-r--r--man/vis.113
-rw-r--r--sam.c58
2 files changed, 65 insertions, 6 deletions
diff --git a/man/vis.1 b/man/vis.1
index 00f1880..f9274e1 100644
--- a/man/vis.1
+++ b/man/vis.1
@@ -359,8 +359,10 @@ and hence
It is an error for a compound address to represent a malformed substring.
.
.Ss Commands
-In the following, text demarcated by slashes represents text delimited by any printable ASCII character except alphanumerics.
-Any number of trailing delimiters may be elided, with multiple elisions then representing null strings, but the first delimiter must always be present.
+In the following, text demarcated by slashes represents text delimited
+by any printable ASCII character except alphanumerics. Any number
+of trailing delimiters may be elided, with multiple elisions then
+representing null strings, but the first delimiter must always be present.
In any delimited text, newline may not appear literally;
.Li \[rs]n
and
@@ -369,6 +371,13 @@ may be typed for newline and tab;
.Li \[rs]/
quotes the delimiter, here
.Li / .
+An ampersand
+.Li &
+and
+.Sy \[rs]n ,
+where
+.Sy n
+is a digit (1-9) are replaced by the corresponding register.
Backslash is otherwise interpreted literally.
.Pp
Most commands may be prefixed with an address to indicate their range
diff --git a/sam.c b/sam.c
index 5909a8e..70dc6c9 100644
--- a/sam.c
+++ b/sam.c
@@ -537,7 +537,7 @@ static char *parse_until(const char **s, const char *until, const char *escchars
c = '\n';
} else if (c == 't') {
c = '\t';
- } else if (type != CMD_REGEX && c == '\\') {
+ } else if (type != CMD_REGEX && type != CMD_TEXT && c == '\\') {
// ignore one of the back slashes
} else {
bool delim = memchr(until, c, len);
@@ -1145,16 +1145,66 @@ enum SamError sam_cmd(Vis *vis, const char *s) {
return err;
}
+/* process text input, substitute register content for backreferences etc. */
+Buffer text(Vis *vis, const char *text) {
+ Buffer buf;
+ buffer_init(&buf);
+ for (size_t len = strcspn(text, "\\&"); *text; len = strcspn(++text, "\\&")) {
+ buffer_append(&buf, text, len);
+ text += len;
+ enum VisRegister regid = VIS_REG_INVALID;
+ switch (text[0]) {
+ case '&':
+ regid = VIS_REG_AMPERSAND;
+ break;
+ case '\\':
+ if ('1' <= text[1] && text[1] <= '9') {
+ regid = VIS_REG_1 + text[1] - '1';
+ text++;
+ } else if (text[1] == '\\' || text[1] == '&') {
+ text++;
+ }
+ break;
+ case '\0':
+ goto out;
+ }
+
+ const char *data;
+ size_t reglen = 0;
+ if (regid != VIS_REG_INVALID) {
+ data = register_get(vis, &vis->registers[regid], &reglen);
+ } else {
+ data = text;
+ reglen = 1;
+ }
+ buffer_append(&buf, data, reglen);
+ }
+out:
+ return buf;
+}
+
static bool cmd_insert(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) {
- return win && sam_insert(win, cur, range->start, strdup(argv[1]), strlen(argv[1]));
+ if (!win)
+ return false;
+ Buffer buf = text(vis, argv[1]);
+ size_t len = buffer_length(&buf);
+ return sam_insert(win, cur, range->start, buffer_move(&buf), len);
}
static bool cmd_append(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) {
- return win && sam_insert(win, cur, range->end, strdup(argv[1]), strlen(argv[1]));
+ if (!win)
+ return false;
+ Buffer buf = text(vis, argv[1]);
+ size_t len = buffer_length(&buf);
+ return sam_insert(win, cur, range->end, buffer_move(&buf), len);
}
static bool cmd_change(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) {
- return win && sam_change(win, cur, range, strdup(argv[1]), strlen(argv[1]));
+ if (!win)
+ return false;
+ Buffer buf = text(vis, argv[1]);
+ size_t len = buffer_length(&buf);
+ return sam_change(win, cur, range, buffer_move(&buf), len);
}
static bool cmd_delete(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) {