Blob Blame History Raw
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


*** ../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 <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.
*** ../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, <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 \
*** ../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    ///