To: vim_dev@googlegroups.com Subject: Patch 7.4.813 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.813 Problem: It is not possible to save and restore character search state. Solution: Add getcharsearch() and setcharsearch(). (James McCoy) Files: runtime/doc/eval.txt, src/eval.c, src/proto/search.pro, src/search.c, src/testdir/test_charsearch.in, src/testdir/test_charsearch.ok, src/testdir/Makefile, src/testdir/Make_amiga.mak, src/testdir/Make_dos.mak, src/testdir/Make_ming.mak, src/testdir/Make_os2.mak, src/testdir/Make_vms.mms *** ../vim-7.4.812/runtime/doc/eval.txt 2015-07-21 15:48:13.581518028 +0200 --- runtime/doc/eval.txt 2015-08-11 13:32:31.643435417 +0200 *************** *** 1820,1828 **** any variable {varname} in buffer {expr} getchar( [expr]) Number get one character from the user getcharmod( ) Number modifiers for the last typed character getcmdline() String return the current command-line getcmdpos() Number return cursor position in command-line ! getcmdtype() String return the current command-line type getcurpos() List position of the cursor getcwd() String the current working directory getfontname( [{name}]) String name of font being used --- 1822,1832 ---- any variable {varname} in buffer {expr} getchar( [expr]) Number get one character from the user getcharmod( ) Number modifiers for the last typed character + getcharsearch() Dict last character search getcmdline() String return the current command-line getcmdpos() Number return cursor position in command-line ! getcmdtype() String return current command-line type ! getcmdwintype() String return current command-line window type getcurpos() List position of the cursor getcwd() String the current working directory getfontname( [{name}]) String name of font being used *************** *** 1968,1973 **** --- 1972,1978 ---- 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}]) *************** *** 3334,3339 **** --- 3363,3388 ---- 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 *************** *** 5356,5361 **** --- 5419,5444 ---- :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. *** ../vim-7.4.812/src/eval.c 2015-07-21 15:48:13.585517990 +0200 --- src/eval.c 2015-08-11 13:34:03.374392656 +0200 *************** *** 555,560 **** --- 555,561 ---- 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,693 **** --- 689,695 ---- 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,8154 **** --- 8151,8157 ---- {"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,8290 **** --- 8288,8294 ---- {"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,11669 **** --- 11668,11691 ---- } /* + * "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,17009 **** --- 17026,17073 ---- } } + 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 */ *** ../vim-7.4.812/src/proto/search.pro 2014-12-13 03:17:07.465046539 +0100 --- src/proto/search.pro 2015-08-11 13:32:31.651435327 +0200 *************** *** 8,13 **** --- 8,19 ---- 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)); *** ../vim-7.4.812/src/search.c 2015-07-28 21:17:31.518069428 +0200 --- src/search.c 2015-08-11 14:05:25.425003350 +0200 *************** *** 89,94 **** --- 89,102 ---- 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,384 **** } /* ! * Return TRUE if patter "pat" has an uppercase character. */ int pat_has_uppercase(pat) --- 386,392 ---- } /* ! * Return TRUE if pattern "pat" has an uppercase character. */ int pat_has_uppercase(pat) *************** *** 419,424 **** --- 427,484 ---- } 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,1605 **** 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; #ifdef FEAT_MBYTE ! bytelen = (*mb_char2bytes)(c, bytes); if (cap->ncharC1 != 0) { ! bytelen += (*mb_char2bytes)(cap->ncharC1, bytes + bytelen); if (cap->ncharC2 != 0) ! bytelen += (*mb_char2bytes)(cap->ncharC2, bytes + bytelen); } #endif } } else /* repeat previous search */ { ! 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. */ /* 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 --- 1619,1660 ---- int c = cap->nchar; /* char to search for */ int dir = cap->arg; /* TRUE for searching forward */ long count = cap->count1; /* repeat count */ int col; char_u *p; int len; int stop = TRUE; if (c != NUL) /* normal search: remember args for repeat */ { if (!KeyStuffed) /* don't remember when redoing */ { ! *lastc = c; ! set_csearch_direction(dir); ! set_csearch_until(t_cmd); #ifdef FEAT_MBYTE ! lastc_bytelen = (*mb_char2bytes)(c, lastc_bytes); if (cap->ncharC1 != 0) { ! lastc_bytelen += (*mb_char2bytes)(cap->ncharC1, ! lastc_bytes + lastc_bytelen); if (cap->ncharC2 != 0) ! lastc_bytelen += (*mb_char2bytes)(cap->ncharC2, ! lastc_bytes + lastc_bytelen); } #endif } } else /* repeat previous search */ { ! 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 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,1649 **** return FAIL; col -= (*mb_head_off)(p, p + col - 1) + 1; } ! if (bytelen == 1) { if (p[col] == c && stop) break; } else { ! if (vim_memcmp(p + col, bytes, bytelen) == 0 && stop) break; } stop = TRUE; --- 1691,1704 ---- return FAIL; col -= (*mb_head_off)(p, p + col - 1) + 1; } ! if (lastc_bytelen == 1) { if (p[col] == c && stop) break; } else { ! if (vim_memcmp(p + col, lastc_bytes, lastc_bytelen) == 0 && stop) break; } stop = TRUE; *************** *** 1671,1678 **** if (has_mbyte) { if (dir < 0) ! /* Landed on the search char which is bytelen long */ ! col += bytelen - 1; else /* To previous char, which may be multi-byte. */ col -= (*mb_head_off)(p, p + col); --- 1726,1733 ---- if (has_mbyte) { if (dir < 0) ! /* 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); *** ../vim-7.4.812/src/testdir/test_charsearch.in 2015-08-11 14:22:29.713361737 +0200 --- src/testdir/test_charsearch.in 2015-08-11 14:12:34.048131520 +0200 *************** *** 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 *** ../vim-7.4.812/src/testdir/test_charsearch.ok 2015-08-11 14:22:29.717361691 +0200 --- src/testdir/test_charsearch.ok 2015-08-11 13:59:20.253153843 +0200 *************** *** 0 **** --- 1,3 ---- + XabcdeXfghijkeXmnopqreXtuvwxyz + YabcdeYfghiYjkeYmnopqreYtuvwxyz + ZabcdeZfghijkZemnokZqretkZvwxyz *** ../vim-7.4.812/src/testdir/Makefile 2015-07-21 15:48:13.593517912 +0200 --- src/testdir/Makefile 2015-08-11 13:46:04.386197622 +0200 *************** *** 39,44 **** --- 39,45 ---- test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ *** ../vim-7.4.812/src/testdir/Make_amiga.mak 2015-07-21 15:48:13.589517950 +0200 --- src/testdir/Make_amiga.mak 2015-08-11 13:45:21.702682710 +0200 *************** *** 42,47 **** --- 42,48 ---- 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,199 **** --- 195,201 ---- 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 *** ../vim-7.4.812/src/testdir/Make_dos.mak 2015-07-21 15:48:13.589517950 +0200 --- src/testdir/Make_dos.mak 2015-08-11 13:45:29.306596293 +0200 *************** *** 41,46 **** --- 41,47 ---- test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ *** ../vim-7.4.812/src/testdir/Make_ming.mak 2015-07-21 15:48:13.589517950 +0200 --- src/testdir/Make_ming.mak 2015-08-11 13:45:35.742523150 +0200 *************** *** 63,68 **** --- 63,69 ---- test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ *** ../vim-7.4.812/src/testdir/Make_os2.mak 2015-07-21 15:48:13.593517912 +0200 --- src/testdir/Make_os2.mak 2015-08-11 14:23:59.096345955 +0200 *************** *** 43,48 **** --- 43,49 ---- test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ *** ../vim-7.4.812/src/testdir/Make_vms.mms 2015-07-21 15:48:13.593517912 +0200 --- src/testdir/Make_vms.mms 2015-08-11 14:24:20.772099626 +0200 *************** *** 4,10 **** # Authors: Zoltan Arpadffy, # Sandor Kopanyi, # ! # Last change: 2015 Jul 17 # # 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. --- 4,10 ---- # Authors: Zoltan Arpadffy, # Sandor Kopanyi, # ! # 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,107 **** --- 102,108 ---- test_autoformat_join.out \ test_breakindent.out \ test_changelist.out \ + test_charsearch.out \ test_close_count.out \ test_command_count.out \ test_erasebackword.out \ *** ../vim-7.4.812/src/version.c 2015-08-08 18:23:41.219566256 +0200 --- src/version.c 2015-08-11 13:22:49.398054460 +0200 *************** *** 743,744 **** --- 743,746 ---- { /* Add new patch number below this line */ + /**/ + 813, /**/ -- `When any government, or any church for that matter, undertakes to say to its subjects, "This you may not read, this you must not see, this you are forbidden to know," the end result is tyranny and oppression no matter how holy the motives' -- Robert A Heinlein, "If this goes on --" /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///