| To: vim_dev@googlegroups.com |
| Subject: Patch 7.4.813 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| 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 |
| |
| |
| |
| |
| |
| *** 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 <expr> ; getcharsearch().forward ? ';' : ',' |
| + :nnoremap <expr> , 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. |
| |
| |
| |
| *** 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 |
| */ |
| |
| |
| |
| *** 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)); |
| |
| |
| |
| *** 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); |
| |
| |
| |
| |
| --- 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 |
| |
| |
| |
| |
| --- 1,3 ---- |
| + XabcdeXfghijkeXmnopqreXtuvwxyz |
| + YabcdeYfghiYjkeYmnopqreYtuvwxyz |
| + ZabcdeZfghijkZemnokZqretkZvwxyz |
| |
| |
| |
| *** 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 \ |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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 \ |
| |
| |
| |
| *** 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 \ |
| |
| |
| |
| *** 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 \ |
| |
| |
| |
| *** 4,10 **** |
| # Authors: Zoltan Arpadffy, <arpadffy@polarhome.com> |
| # Sandor Kopanyi, <sandor.kopanyi@mailbox.hu> |
| # |
| ! # 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, <arpadffy@polarhome.com> |
| # Sandor Kopanyi, <sandor.kopanyi@mailbox.hu> |
| # |
| ! # 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 \ |
| |
| |
| |
| *** 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 /// |