# HG changeset patch # User Bram Moolenaar # Date 1439295979 -7200 # Node ID 814f1f569e4a2648097f63160e9b8762fef54c93 # Parent 9c248be4e7d22b349aa146ac888a1a9669ae4da9 patch 7.4.813 Problem: It is not possible to save and restore character search state. Solution: Add getcharsearch() and setcharsearch(). (James McCoy) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1971,6 +1971,7 @@ server2client( {clientid}, {string}) Number send reply string serverlist() String get a list of available servers setbufvar( {expr}, {varname}, {val}) set {varname} in buffer {expr} to {val} +setcharsearch( {dict}) Dict set character search from {dict} setcmdpos( {pos}) Number set cursor position in command-line setline( {lnum}, {line}) Number set line {lnum} to {line} setloclist( {nr}, {list}[, {action}]) @@ -3361,6 +3362,26 @@ getcharmod() *getcharmod()* character itself are obtained. Thus Shift-a results in "A" without a modifier. +getcharsearch() *getcharsearch()* + Return the current character search information as a {dict} + with the following entries: + + char character previously used for a character + search (|t|, |f|, |T|, or |F|); empty string + if no character search has been performed + forward direction of character search; 1 for forward, + 0 for backward + until type of character search; 1 for a |t| or |T| + character search, 0 for an |f| or |F| + character search + + This can be useful to always have |;| and |,| search + forward/backward regardless of the direction of the previous + character search: > + :nnoremap ; getcharsearch().forward ? ';' : ',' + :nnoremap , getcharsearch().forward ? ',' : ';' +< Also see |setcharsearch()|. + getcmdline() *getcmdline()* Return the current command-line. Only works when the command line is being edited, thus requires use of |c_CTRL-\_e| or @@ -5397,6 +5418,26 @@ setbufvar({expr}, {varname}, {val}) *s :call setbufvar("todo", "myvar", "foobar") < This function is not available in the |sandbox|. +setcharsearch() *setcharsearch()* + Set the current character search information to {dict}, + which contains one or more of the following entries: + + char character which will be used for a subsequent + |,| or |;| command; an empty string clears the + character search + forward direction of character search; 1 for forward, + 0 for backward + until type of character search; 1 for a |t| or |T| + character search, 0 for an |f| or |F| + character search + + This can be useful to save/restore a user's character search + from a script: > + :let prevsearch = getcharsearch() + :" Perform a command which clobbers user's search + :call setcharsearch(prevsearch) +< Also see |getcharsearch()|. + setcmdpos({pos}) *setcmdpos()* Set the cursor position in the command line to byte position {pos}. The first position is 1. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -555,6 +555,7 @@ static void f_getbufline __ARGS((typval_ static void f_getbufvar __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getchar __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getcharmod __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_getcharsearch __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getcmdline __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getcmdpos __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getcmdtype __ARGS((typval_T *argvars, typval_T *rettv)); @@ -688,6 +689,7 @@ static void f_searchpos __ARGS((typval_T static void f_server2client __ARGS((typval_T *argvars, typval_T *rettv)); static void f_serverlist __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setbufvar __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_setcharsearch __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setcmdpos __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setline __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setloclist __ARGS((typval_T *argvars, typval_T *rettv)); @@ -8149,6 +8151,7 @@ static struct fst {"getbufvar", 2, 3, f_getbufvar}, {"getchar", 0, 1, f_getchar}, {"getcharmod", 0, 0, f_getcharmod}, + {"getcharsearch", 0, 0, f_getcharsearch}, {"getcmdline", 0, 0, f_getcmdline}, {"getcmdpos", 0, 0, f_getcmdpos}, {"getcmdtype", 0, 0, f_getcmdtype}, @@ -8285,6 +8288,7 @@ static struct fst {"server2client", 2, 2, f_server2client}, {"serverlist", 0, 0, f_serverlist}, {"setbufvar", 3, 3, f_setbufvar}, + {"setcharsearch", 1, 1, f_setcharsearch}, {"setcmdpos", 1, 1, f_setcmdpos}, {"setline", 2, 2, f_setline}, {"setloclist", 2, 3, f_setloclist}, @@ -11664,6 +11668,24 @@ f_getcharmod(argvars, rettv) } /* + * "getcharsearch()" function + */ + static void +f_getcharsearch(argvars, rettv) + typval_T *argvars UNUSED; + typval_T *rettv; +{ + if (rettv_dict_alloc(rettv) != FAIL) + { + dict_T *dict = rettv->vval.v_dict; + + dict_add_nr_str(dict, "char", 0L, last_csearch()); + dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL); + dict_add_nr_str(dict, "until", last_csearch_until(), NULL); + } +} + +/* * "getcmdline()" function */ static void @@ -17004,6 +17026,48 @@ f_setbufvar(argvars, rettv) } } + static void +f_setcharsearch(argvars, rettv) + typval_T *argvars; + typval_T *rettv UNUSED; +{ + dict_T *d; + dictitem_T *di; + char_u *csearch; + + if (argvars[0].v_type != VAR_DICT) + { + EMSG(_(e_dictreq)); + return; + } + + if ((d = argvars[0].vval.v_dict) != NULL) + { + csearch = get_dict_string(d, (char_u *)"char", FALSE); + if (csearch != NULL) + { + if (enc_utf8) + { + int pcc[MAX_MCO]; + int c = utfc_ptr2char(csearch, pcc); + set_last_csearch(c, csearch, utfc_ptr2len(csearch)); + } + else + set_last_csearch(mb_ptr2char(csearch), + csearch, mb_ptr2len(csearch)); + } + + di = dict_find(d, (char_u *)"forward", -1); + if (di != NULL) + set_csearch_direction(get_tv_number(&di->di_tv) + ? FORWARD : BACKWARD); + + di = dict_find(d, (char_u *)"until", -1); + if (di != NULL) + set_csearch_until(!!get_tv_number(&di->di_tv)); + } +} + /* * "setcmdpos()" function */ diff --git a/src/proto/search.pro b/src/proto/search.pro --- a/src/proto/search.pro +++ b/src/proto/search.pro @@ -8,6 +8,12 @@ void restore_search_patterns __ARGS((voi 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)); +int last_csearch_forward __ARGS((void)); +int last_csearch_until __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 a/src/search.c b/src/search.c --- a/src/search.c +++ b/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]; @@ -378,7 +386,7 @@ ignorecase(pat) } /* - * Return TRUE if patter "pat" has an uppercase character. + * Return TRUE if pattern "pat" has an uppercase character. */ int pat_has_uppercase(pat) @@ -419,6 +427,58 @@ pat_has_uppercase(pat) } char_u * +last_csearch() +{ +#ifdef FEAT_MBYTE + return lastc_bytes; +#else + return lastc; +#endif +} + + int +last_csearch_forward() +{ + return lastcdir == FORWARD; +} + + int +last_csearch_until() +{ + return last_t_cmd == TRUE; +} + + void +set_last_csearch(c, s, len) + int c; + char_u *s; + int len; +{ + *lastc = c; +#ifdef FEAT_MBYTE + lastc_bytelen = len; + if (len) + memcpy(lastc_bytes, s, len); + else + vim_memset(lastc_bytes, 0, sizeof(lastc_bytes)); +#endif +} + + void +set_csearch_direction(cdir) + int cdir; +{ + lastcdir = cdir; +} + + void +set_csearch_until(t_cmd) + int t_cmd; +{ + last_t_cmd = t_cmd; +} + + char_u * last_search_pat() { return spats[last_idx].pat; @@ -1559,47 +1619,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 +1691,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 +1726,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 a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak --- a/src/testdir/Make_amiga.mak +++ b/src/testdir/Make_amiga.mak @@ -42,6 +42,7 @@ SCRIPTS = test1.out test3.out test4.out test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ @@ -194,6 +195,7 @@ test_autocmd_option.out: test_autocmd_op test_autoformat_join.out: test_autoformat_join.in test_breakindent.out: test_breakindent.in test_changelist.out: test_changelist.in +test_charsearch.out: test_charsearch.in test_close_count.out: test_close_count.in test_command_count.out: test_command_count.in test_erasebackword.out: test_erasebackword.in diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak --- a/src/testdir/Make_dos.mak +++ b/src/testdir/Make_dos.mak @@ -41,6 +41,7 @@ SCRIPTS = test3.out test4.out test5.out test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak --- a/src/testdir/Make_ming.mak +++ b/src/testdir/Make_ming.mak @@ -63,6 +63,7 @@ SCRIPTS = test3.out test4.out test5.out test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ diff --git a/src/testdir/Make_os2.mak b/src/testdir/Make_os2.mak --- a/src/testdir/Make_os2.mak +++ b/src/testdir/Make_os2.mak @@ -43,6 +43,7 @@ SCRIPTS = test1.out test3.out test4.out test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms --- a/src/testdir/Make_vms.mms +++ b/src/testdir/Make_vms.mms @@ -4,7 +4,7 @@ # Authors: Zoltan Arpadffy, # Sandor Kopanyi, # -# Last change: 2015 Jul 17 +# Last change: 2015 Aug 11 # # This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64. # Edit the lines in the Configuration section below to select. @@ -102,6 +102,7 @@ SCRIPT = test1.out test2.out test3.out test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ diff --git a/src/testdir/Makefile b/src/testdir/Makefile --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -39,6 +39,7 @@ SCRIPTS = test1.out test2.out test3.out test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ diff --git a/src/testdir/test_charsearch.in b/src/testdir/test_charsearch.in new file mode 100644 --- /dev/null +++ b/src/testdir/test_charsearch.in @@ -0,0 +1,25 @@ +Test for character searches + +STARTTEST +:so small.vim +:" check that "fe" and ";" work +/^X +ylfep;;p,,p: +:" check that save/restore works +/^Y +ylfep:let csave = getcharsearch() +fip:call setcharsearch(csave) +;p;p: +:" check that setcharsearch() changes the settins. +/^Z +ylfep:call setcharsearch({'char': 'k'}) +;p:call setcharsearch({'forward': 0}) +$;p:call setcharseearch({'until'}: 1}) +;;p: +:/^X/,$w! test.out +:qa! +ENDTEST + +Xabcdefghijkemnopqretuvwxyz +Yabcdefghijkemnopqretuvwxyz +Zabcdefghijkemnokqretkvwxyz diff --git a/src/testdir/test_charsearch.ok b/src/testdir/test_charsearch.ok new file mode 100644 --- /dev/null +++ b/src/testdir/test_charsearch.ok @@ -0,0 +1,3 @@ +XabcdeXfghijkeXmnopqreXtuvwxyz +YabcdeYfghiYjkeYmnopqreYtuvwxyz +ZabcdeZfghijkZemnokZqretkZvwxyz diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -742,6 +742,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 813, +/**/ 812, /**/ 811,