Recently, I've heard some script authors ponder whether there was a way to access information about the last character search a user performed. The ideas being explored were overriding ; and , to always search forward/backward respectively, or providing visual cues for where a character search would move the cursor.
There exists a mechanism for script authors to interact with normal searches via the / register and the v:searchforward variable. The attached patch implements comparable functionality for character searches. * A new, read-write ; register exposes the character which would be the target for a subsequent ; or , command. If this register is set, then the direction and type of character search are (re)set as if the user had used t to perform the search. * A new, read-write v:csearchforward variable exposes the direction of the character search, similar to v:searchforward. * A new, read-write v:csearchuntil variable exposes whether the search is an "until" (t) search. * Any normal character searches which happen within a function or autocmd will not affect the user's character search state, similar to the handling of normal searches. However, a script author may affect that through using the above listed variables/register. Aside from enabling script authors to better interact with character searches, this also makes it easier to search for composed characters using character search. One currently has to create a keymap file and use “:loadkeymap” to easily enter a composed character as the character search value. With this functionality, one can instead simply “:let @;="a\u0301"” to search for á. Cheers, -- James GPG Key: 4096R/331BA3DB 2011-12-05 James McCoy <[email protected]> -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
diff --git c/runtime/doc/change.txt w/runtime/doc/change.txt
index 79aa179..c631cd7 100644
--- c/runtime/doc/change.txt
+++ w/runtime/doc/change.txt
@@ -1285,6 +1285,15 @@ Note that the value is restored when returning from a function
|function-search-undo|.
{not in Vi}
+11. Last character search register "; *quote_;* *quote;*
+Contains the most recent character search. This is used for the |;| and |,|
+commands. It is writable with `:let`. This register can not be used as a
+destination for a yank or delete. The search direction is available in
+|v:csearchforward|.
+Note that the value is restored when returning from a function
+|function-search-undo|.
+{not in Vi}
+
*@/*
You can write to a register with a `:let` command |:let-@|. Example: >
:let @/ = "the"
diff --git c/runtime/doc/eval.txt w/runtime/doc/eval.txt
index d9f49ae..b068b3a 100644
--- c/runtime/doc/eval.txt
+++ w/runtime/doc/eval.txt
@@ -1351,6 +1351,22 @@ v:count The count given for the last Normal mode command. Can be used
v:count1 Just like "v:count", but defaults to one when no count is
used.
+v:csearchforward *v:csearchforward* *csearchforward-variable*
+ Character search direction: 1 after a forward character
+ search, 0 after a backward search. It is reset to forward
+ when directly setting the last character search, see |quote;|.
+ Note that the value is restored when returning from a
+ function. |function-search-undo|.
+ Read-write.
+
+ *v:csearchuntil* *csearchuntil-variable*
+v:csearchuntil Character search type: 1 after a |t| or |T| character search,
+ 0 after an |f| or |F| character search. It is reset to 1 when
+ directly setting the last character search, see |quote;|.
+ Note that the value is restored when returning from a
+ function. |function-search-undo|.
+ Read-write.
+
*v:ctype* *ctype-variable*
v:ctype The current locale setting for characters of the runtime
environment. This allows Vim scripts to be aware of the
diff --git c/src/eval.c w/src/eval.c
index 0537c4e..24657c5 100644
--- c/src/eval.c
+++ w/src/eval.c
@@ -368,6 +368,8 @@ static struct vimvar
{VV_NAME("option_new", VAR_STRING), VV_RO},
{VV_NAME("option_old", VAR_STRING), VV_RO},
{VV_NAME("option_type", VAR_STRING), VV_RO},
+ {VV_NAME("csearchforward", VAR_NUMBER), 0},
+ {VV_NAME("csearchuntil", VAR_NUMBER), 0},
};
/* shorthand */
@@ -892,6 +894,8 @@ eval_init()
hash_add(&compat_hashtab, p->vv_di.di_key);
}
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
+ set_vim_var_nr(VV_CSEARCHFORWARD, 1L);
+ set_vim_var_nr(VV_CSEARCHUNTIL, 1L);
set_vim_var_nr(VV_HLSEARCH, 1L);
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
set_reg_var(0); /* default for v:register is not 0 but '"' */
@@ -21648,6 +21652,10 @@ set_var(name, tv, copy)
v->di_tv.vval.v_number = get_tv_number(tv);
if (STRCMP(varname, "searchforward") == 0)
set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
+ else if (STRCMP(varname, "csearchforward") == 0)
+ set_csearch_direction(v->di_tv.vval.v_number ? FORWARD : BACKWARD);
+ else if (STRCMP(varname, "csearchuntil") == 0)
+ set_csearch_until(!!v->di_tv.vval.v_number);
#ifdef FEAT_SEARCH_EXTRA
else if (STRCMP(varname, "hlsearch") == 0)
{
diff --git c/src/ops.c w/src/ops.c
index a9eec34..39b753e 100644
--- c/src/ops.c
+++ w/src/ops.c
@@ -856,9 +856,9 @@ valid_yank_reg(regname, writing)
if ( (regname > 0 && ASCII_ISALNUM(regname))
|| (!writing && vim_strchr((char_u *)
#ifdef FEAT_EVAL
- "/.%:="
+ "/;.%:="
#else
- "/.%:"
+ "/;.%:"
#endif
, regname) != NULL)
|| regname == '#'
@@ -1528,6 +1528,10 @@ get_spec_reg(regname, argp, allocated, errmsg)
*argp = last_search_pat();
return TRUE;
+ case ';': /* last character search */
+ *argp = last_csearch();
+ return TRUE;
+
case '.': /* last inserted text */
*argp = get_last_insert_save();
*allocated = TRUE;
@@ -4230,6 +4234,16 @@ ex_display(eap)
dis_msg(last_search_pat(), FALSE);
}
+ /*
+ * display last character search
+ */
+ if (STRCMP(last_csearch(), "") != 0
+ && (arg == NULL || vim_strchr(arg, ';') != NULL) && !got_int)
+ {
+ MSG_PUTS("\n\"; ");
+ dis_msg(last_csearch(), FALSE);
+ }
+
#ifdef FEAT_EVAL
/*
* display last used expression
@@ -6590,6 +6604,7 @@ write_reg_contents_lst(name, strings, maxlen, must_append, yank_type, block_len)
struct yankreg *old_y_previous, *old_y_current;
if (name == '/'
+ || name == ';'
#ifdef FEAT_EVAL
|| name == '='
#endif
@@ -6601,8 +6616,8 @@ write_reg_contents_lst(name, strings, maxlen, must_append, yank_type, block_len)
s = (char_u *)"";
else if (strings[1] != NULL)
{
- EMSG(_("E883: search pattern and expression register may not "
- "contain two or more lines"));
+ EMSG(_("E883: search pattern, character search, and expression "
+ "register may not contain two or more lines"));
return;
}
else
@@ -6647,6 +6662,21 @@ write_reg_contents_ex(name, str, maxlen, must_append, yank_type, block_len)
return;
}
+ if (name == ';')
+ {
+ if (enc_utf8)
+ {
+ int pcc[MAX_MCO];
+ int c = utfc_ptr2char(str, pcc);
+ set_last_csearch(c, str, utfc_ptr2len(str));
+ }
+ else
+ set_last_csearch(mb_ptr2char(str), str, mb_ptr2len(str));
+ set_csearch_direction(FORWARD);
+ set_csearch_until(TRUE);
+ return;
+ }
+
if (name == '#')
{
buf_T *buf;
diff --git c/src/proto/search.pro w/src/proto/search.pro
index 07f6087..14530d5 100644
--- c/src/proto/search.pro
+++ w/src/proto/search.pro
@@ -8,6 +8,10 @@ void restore_search_patterns __ARGS((void));
void free_search_patterns __ARGS((void));
int ignorecase __ARGS((char_u *pat));
int pat_has_uppercase __ARGS((char_u *pat));
+char_u *last_csearch __ARGS((void));
+void set_last_csearch __ARGS((int c, char_u *s, int len));
+void set_csearch_direction __ARGS((int cdir));
+void set_csearch_until __ARGS((int t_cmd));
char_u *last_search_pat __ARGS((void));
void reset_search_dir __ARGS((void));
void set_last_search_pat __ARGS((char_u *s, int idx, int magic, int setlast));
diff --git c/src/search.c w/src/search.c
index 4905a49..f342649 100644
--- c/src/search.c
+++ w/src/search.c
@@ -89,6 +89,14 @@ static struct spat spats[2] =
static int last_idx = 0; /* index in spats[] for RE_LAST */
+static char_u lastc[2] = { NUL, NUL }; /* last character searched for */
+static int lastcdir = FORWARD; /* last direction of character search */
+static int last_t_cmd = TRUE; /* last search t_cmd */
+#ifdef FEAT_MBYTE
+static char_u lastc_bytes[MB_MAXBYTES + 1];
+static int lastc_bytelen = 1; /* >1 for multi-byte char */
+#endif
+
#if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)
/* copy of spats[], for keeping the search patterns while executing autocmds */
static struct spat saved_spats[2];
@@ -96,6 +104,13 @@ static int saved_last_idx = 0;
# ifdef FEAT_SEARCH_EXTRA
static int saved_no_hlsearch = 0;
# endif
+static char_u saved_lastc[2] = { NUL, NUL };
+static int saved_lastcdir = FORWARD;
+static int saved_last_t_cmd = TRUE;
+# ifdef FEAT_MBYTE
+static char_u saved_bytes[MB_MAXBYTES + 1];
+static int saved_bytelen = 1;
+# endif
#endif
static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */
@@ -315,6 +330,13 @@ save_search_patterns()
# ifdef FEAT_SEARCH_EXTRA
saved_no_hlsearch = no_hlsearch;
# endif
+ memcpy(saved_lastc, lastc, sizeof(lastc));
+ saved_lastcdir = lastcdir;
+ saved_last_t_cmd = last_t_cmd;
+# ifdef FEAT_MBYTE
+ memcpy(saved_bytes, lastc_bytes, sizeof(lastc_bytes));
+ saved_bytelen = lastc_bytelen;
+# endif
}
}
@@ -334,6 +356,13 @@ restore_search_patterns()
# ifdef FEAT_SEARCH_EXTRA
SET_NO_HLSEARCH(saved_no_hlsearch);
# endif
+ memcpy(lastc, saved_lastc, sizeof(lastc));
+ lastcdir = saved_lastcdir;
+ last_t_cmd = saved_last_t_cmd;
+# ifdef FEAT_MBYTE
+ memcpy(lastc_bytes, saved_bytes, sizeof(lastc_bytes));
+ lastc_bytelen = saved_bytelen;
+# endif
}
}
#endif
@@ -419,6 +448,69 @@ pat_has_uppercase(pat)
}
char_u *
+last_csearch()
+{
+#ifdef FEAT_MBYTE
+ return lastc_bytes;
+#else
+ return lastc;
+#endif
+}
+
+ void
+set_last_csearch(c, s, len)
+ int c;
+ char_u *s;
+ int len;
+{
+ *lastc = c;
+ set_csearch_direction(FORWARD);
+ set_csearch_until(TRUE);
+
+#ifdef FEAT_MBYTE
+ lastc_bytelen = len;
+ if (len)
+ memcpy(lastc_bytes, s, len);
+ else
+ vim_memset(lastc_bytes, 0, sizeof(lastc_bytes));
+#endif
+
+#if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL)
+ *saved_lastc = c;
+ saved_lastcdir = FORWARD;
+ saved_last_t_cmd = TRUE;
+
+# ifdef FEAT_MBYTE
+ saved_bytelen = len;
+ if (len)
+ memcpy(saved_bytes, s, len);
+ else
+ vim_memset(saved_bytes, 0, sizeof(saved_bytes));
+# endif
+#endif
+}
+
+ void
+set_csearch_direction(cdir)
+ int cdir;
+{
+ lastcdir = cdir;
+#ifdef FEAT_EVAL
+ set_vim_var_nr(VV_CSEARCHFORWARD, cdir == FORWARD);
+#endif
+}
+
+ void
+set_csearch_until(t_cmd)
+ int t_cmd;
+{
+ last_t_cmd = t_cmd;
+#ifdef FEAT_EVAL
+ set_vim_var_nr(VV_CSEARCHUNTIL, t_cmd);
+#endif
+}
+
+ char_u *
last_search_pat()
{
return spats[last_idx].pat;
@@ -1559,47 +1651,42 @@ searchc(cap, t_cmd)
int c = cap->nchar; /* char to search for */
int dir = cap->arg; /* TRUE for searching forward */
long count = cap->count1; /* repeat count */
- static int lastc = NUL; /* last character searched for */
- static int lastcdir; /* last direction of character search */
- static int last_t_cmd; /* last search t_cmd */
int col;
char_u *p;
int len;
int stop = TRUE;
-#ifdef FEAT_MBYTE
- static char_u bytes[MB_MAXBYTES + 1];
- static int bytelen = 1; /* >1 for multi-byte char */
-#endif
if (c != NUL) /* normal search: remember args for repeat */
{
if (!KeyStuffed) /* don't remember when redoing */
{
- lastc = c;
- lastcdir = dir;
- last_t_cmd = t_cmd;
+ *lastc = c;
+ set_csearch_direction(dir);
+ set_csearch_until(t_cmd);
#ifdef FEAT_MBYTE
- bytelen = (*mb_char2bytes)(c, bytes);
+ lastc_bytelen = (*mb_char2bytes)(c, lastc_bytes);
if (cap->ncharC1 != 0)
{
- bytelen += (*mb_char2bytes)(cap->ncharC1, bytes + bytelen);
+ lastc_bytelen += (*mb_char2bytes)(cap->ncharC1,
+ lastc_bytes + lastc_bytelen);
if (cap->ncharC2 != 0)
- bytelen += (*mb_char2bytes)(cap->ncharC2, bytes + bytelen);
+ lastc_bytelen += (*mb_char2bytes)(cap->ncharC2,
+ lastc_bytes + lastc_bytelen);
}
#endif
}
}
else /* repeat previous search */
{
- if (lastc == NUL)
+ if (*lastc == NUL)
return FAIL;
if (dir) /* repeat in opposite direction */
dir = -lastcdir;
else
dir = lastcdir;
t_cmd = last_t_cmd;
- c = lastc;
- /* For multi-byte re-use last bytes[] and bytelen. */
+ c = *lastc;
+ /* For multi-byte re-use last lastc_bytes[] and lastc_bytelen. */
/* Force a move of at least one char, so ";" and "," will move the
* cursor, even if the cursor is right in front of char we are looking
@@ -1636,14 +1723,14 @@ searchc(cap, t_cmd)
return FAIL;
col -= (*mb_head_off)(p, p + col - 1) + 1;
}
- if (bytelen == 1)
+ if (lastc_bytelen == 1)
{
if (p[col] == c && stop)
break;
}
else
{
- if (vim_memcmp(p + col, bytes, bytelen) == 0 && stop)
+ if (vim_memcmp(p + col, lastc_bytes, lastc_bytelen) == 0 && stop)
break;
}
stop = TRUE;
@@ -1671,8 +1758,8 @@ searchc(cap, t_cmd)
if (has_mbyte)
{
if (dir < 0)
- /* Landed on the search char which is bytelen long */
- col += bytelen - 1;
+ /* Landed on the search char which is lastc_bytelen long */
+ col += lastc_bytelen - 1;
else
/* To previous char, which may be multi-byte. */
col -= (*mb_head_off)(p, p + col);
diff --git c/src/testdir/test_eval.ok w/src/testdir/test_eval.ok
index cda425c..52fe426 100644
--- c/src/testdir/test_eval.ok
+++ w/src/testdir/test_eval.ok
@@ -333,9 +333,9 @@ Vim(call):E731: using Dictionary as a String
Executing call setreg(1, 2, [])
Vim(call):E730: using List as a String
Executing call setreg("/", ["1", "2"])
-Vim(call):E883: search pattern and expression register may not contain two or more lines
+Vim(call):E883: search pattern, character search, and expression register may not contain two or more lines
Executing call setreg("=", ["1", "2"])
-Vim(call):E883: search pattern and expression register may not contain two or more lines
+Vim(call):E883: search pattern, character search, and expression register may not contain two or more lines
Executing call setreg(1, ["", "", [], ""])
Vim(call):E730: using List as a String
Vim(function):E128: Function name must start with a capital or "s:": g:test()
diff --git c/src/vim.h w/src/vim.h
index 809f312..7b87c2b 100644
--- c/src/vim.h
+++ w/src/vim.h
@@ -1902,7 +1902,9 @@ typedef int proftime_T; /* dummy for function prototypes */
#define VV_OPTION_NEW 59
#define VV_OPTION_OLD 60
#define VV_OPTION_TYPE 61
-#define VV_LEN 62 /* number of v: vars */
+#define VV_CSEARCHFORWARD 62
+#define VV_CSEARCHUNTIL 63
+#define VV_LEN 64 /* number of v: vars */
#ifdef FEAT_CLIPBOARD
signature.asc
Description: Digital signature
