On Tuesday, November 19, 2013 4:42:45 PM UTC-5, Christian Brabandt wrote:
> Hi Daniel!
> 
> 
> 
> On Di, 19 Nov 2013, Daniel paradigm Thau wrote:
> 
> 
> 
> > I noticed a common pattern when using Vim:
> 
> > - I want to operate on a text object that is not under/around the cursor
> 
> > - The cursor is not over/in a text object of this type.
> 
> > 
> 
> > For example, with the cursor on the "x" and a desire to operate on the 
> > conditional part of the if-statement:
> 
> > 
> 
> >     x = 1;
> 
> >     ...
> 
> >     if (...) {
> 
> >         ...
> 
> >     }
> 
> > 
> 
> > In these situations I have been moving the cursor to the object then 
> > selecting the object with something like "/(<cr>vi(" or "5jf(vi(".
> 
> > 
> 
> > However, in that situation the text-object commands don't do anything.  We 
> > could have Vim do something useful in this context - jump to the desired 
> > text object.  If the given text-object command is valid - if the cursor is 
> > already in a ()-block - then what Vim normally does should happen.  
> > However, if Vim is about to "return FAIL" could simply search the buffer 
> > for the object and, if it finds it, use that object instead.
> 
> > 
> 
> > Moreover, block text-objects (parens, {}, [], <>) have two (or three!) ways 
> > to access them.  This could be used to indicate direction.  "vi(" will 
> > select the ()-block under/around the cursor or, if no such block exists in 
> > that area, searches forward for a ()-block.  "vi)" will do the same except 
> > it will search in reverse.  "vib" will just act as it always has.  Similar 
> > actions will be used on {}, [], and <>.
> 
> > 
> 
> 
> 
> I think it should be ( to move to the previous object and ) to move to 
> 
> the next block. This would match the behaviour of [s ]s and [z and ]z 
> 
> and other similar motions.
> 
> 
> 
> Other then that, this sounds like a useful addition (although some 
> 
> scripts might depend on the current behaviour).
> 
> 
> 
> regards,
> 
> Christian
> 
> -- 
> 
> "Sie brauchen den Mund nicht so weit aufmachen", sagte der Zahnarzt
> 
> "Wollen Sie denn nicht bohren?"
> 
> "Doch, schon, ... aber ich bleibe drau�en."

Hi Christian,

Thanks for the input.  That makes perfect sense to me.  Adjusted patches are 
attached.

-- 
-- 
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/groups/opt_out.
*** a/runtime/doc/motion.txt
--- b/runtime/doc/motion.txt
***************
*** 574,579 **** a[			"a [] block", select [count] '[' ']' blocks.  This
--- 574,583 ----
  			goes backwards to the [count] unclosed '[', and finds
  			the matching ']'.  The enclosed text is selected,
  			including the '[' and ']'.
+ 			If it fails to find the block under or around the
+ 			cursor, and '[' was specified, it will search the
+ 			buffer backwards for the block or, if ']' was
+ 			specified, it will search the buffer forwards.
  			When used in Visual mode it is made characterwise.
  
  i]						*v_i]* *v_i[* *i]* *i[*
***************
*** 581,586 **** i[			"inner [] block", select [count] '[' ']' blocks.  This
--- 585,594 ----
  			goes backwards to the [count] unclosed '[', and finds
  			the matching ']'.  The enclosed text is selected,
  			excluding the '[' and ']'.
+ 			If it fails to find the block under or around the
+ 			cursor, and '[' was specified, it will search the
+ 			buffer backwards for the block or, if ']' was
+ 			specified, it will search the buffer forwards.
  			When used in Visual mode it is made characterwise.
  
  a)							*v_a)* *a)* *a(*
***************
*** 589,594 **** ab			"a block", select [count] blocks, from "[count] [(" to
--- 597,606 ----
  			the matching ')', including the '(' and ')' (see
  			|[(|).  Does not include white space outside of the
  			parenthesis.
+ 			If it fails to find the block under or around the
+ 			cursor, and '(' was specified, it will search the
+ 			buffer backwards for the block or, if ')' was
+ 			specified, it will search the buffer forwards.
  			When used in Visual mode it is made characterwise.
  
  i)							*v_i)* *i)* *i(*
***************
*** 596,613 **** i(							*v_ib* *v_i(* *ib*
--- 608,637 ----
  ib			"inner block", select [count] blocks, from "[count] [("
  			to the matching ')', excluding the '(' and ')' (see
  			|[(|).
+ 			If it fails to find the block under or around the
+ 			cursor, and '(' was specified, it will search the
+ 			buffer backwards for the block or, if ')' was
+ 			specified, it will search the buffer forwards.
  			When used in Visual mode it is made characterwise.
  
  a>						*v_a>* *v_a<* *a>* *a<*
  a<			"a <> block", select [count] <> blocks, from the
  			[count]'th unmatched '<' backwards to the matching
  			'>', including the '<' and '>'.
+ 			If it fails to find the block under or around the
+ 			cursor, and '<' was specified, it will search the
+ 			buffer backwards for the block or, if '>' was
+ 			specified, it will search the buffer forwards.
  			When used in Visual mode it is made characterwise.
  
  i>						*v_i>* *v_i<* *i>* *i<*
  i<			"inner <> block", select [count] <> blocks, from
  			the [count]'th unmatched '<' backwards to the matching
  			'>', excluding the '<' and '>'.
+ 			If it fails to find the block under or around the
+ 			cursor, and '<' was specified, it will search the
+ 			buffer backwards for the block or, if '>' was
+ 			specified, it will search the buffer forwards.
  			When used in Visual mode it is made characterwise.
  
  						*v_at* *at*
***************
*** 629,634 **** a{							*v_aB* *v_a{* *aB*
--- 653,662 ----
  aB			"a Block", select [count] Blocks, from "[count] [{" to
  			the matching '}', including the '{' and '}' (see
  			|[{|).
+ 			If it fails to find the block under or around the
+ 			cursor, and '{' was specified, it will search the
+ 			buffer backwards for the block or, if '}' was specified,
+ 			it will search the buffer forwards.
  			When used in Visual mode it is made characterwise.
  
  i}							*v_i}* *i}* *i{*
***************
*** 636,641 **** i{							*v_iB* *v_i{* *iB*
--- 664,673 ----
  iB			"inner Block", select [count] Blocks, from "[count] [{"
  			to the matching '}', excluding the '{' and '}' (see
  			|[{|).
+ 			If it fails to find the block under or around the
+ 			cursor, and '{' was specified, it will search the
+ 			buffer backwards for the block or, if '}' was specified,
+ 			it will search the buffer forwards.
  			When used in Visual mode it is made characterwise.
  
  a"							*v_aquote* *aquote*
*** a/src/normal.c
--- b/src/normal.c
***************
*** 9268,9273 **** nv_object(cap)
--- 9268,9293 ----
      mps_save = curbuf->b_p_mps;
      curbuf->b_p_mps = (char_u *)"(:),{:},[:],<:>";
  
+     /* Set search direction */
+     int dir;
+     switch(cap->nchar)
+     {
+ 	case '(':
+ 	case '{':
+ 	case '[':
+ 	case '<':
+ 	    dir = BACKWARD;
+ 	    break;
+ 	case ')':
+ 	case '}':
+ 	case ']':
+ 	case '>':
+ 	    dir = FORWARD;
+ 	    break;
+ 	default:
+ 	    dir = 0;
+     }
+ 
      switch (cap->nchar)
      {
  	case 'w': /* "aw" = a word */
***************
*** 9279,9298 **** nv_object(cap)
  	case 'b': /* "ab" = a braces block */
  	case '(':
  	case ')':
! 		flag = current_block(cap->oap, cap->count1, include, '(', ')');
  		break;
  	case 'B': /* "aB" = a Brackets block */
  	case '{':
  	case '}':
! 		flag = current_block(cap->oap, cap->count1, include, '{', '}');
  		break;
  	case '[': /* "a[" = a [] block */
  	case ']':
! 		flag = current_block(cap->oap, cap->count1, include, '[', ']');
  		break;
  	case '<': /* "a<" = a <> block */
  	case '>':
! 		flag = current_block(cap->oap, cap->count1, include, '<', '>');
  		break;
  	case 't': /* "at" = a tag block (xml and html) */
  		flag = current_tagblock(cap->oap, cap->count1, include);
--- 9299,9318 ----
  	case 'b': /* "ab" = a braces block */
  	case '(':
  	case ')':
! 		flag = current_block(cap->oap, cap->count1, include, '(', ')', dir);
  		break;
  	case 'B': /* "aB" = a Brackets block */
  	case '{':
  	case '}':
! 		flag = current_block(cap->oap, cap->count1, include, '{', '}', dir);
  		break;
  	case '[': /* "a[" = a [] block */
  	case ']':
! 		flag = current_block(cap->oap, cap->count1, include, '[', ']', dir);
  		break;
  	case '<': /* "a<" = a <> block */
  	case '>':
! 		flag = current_block(cap->oap, cap->count1, include, '<', '>', dir);
  		break;
  	case 't': /* "at" = a tag block (xml and html) */
  		flag = current_tagblock(cap->oap, cap->count1, include);
*** a/src/proto/search.pro
--- b/src/proto/search.pro
***************
*** 28,34 **** int end_word __ARGS((long count, int bigword, int stop, int empty));
  int bckend_word __ARGS((long count, int bigword, int eol));
  int current_word __ARGS((oparg_T *oap, long count, int include, int bigword));
  int current_sent __ARGS((oparg_T *oap, long count, int include));
! int current_block __ARGS((oparg_T *oap, long count, int include, int what, int other));
  int current_tagblock __ARGS((oparg_T *oap, long count_arg, int include));
  int current_par __ARGS((oparg_T *oap, long count, int include, int type));
  int current_quote __ARGS((oparg_T *oap, long count, int include, int quotechar));
--- 28,34 ----
  int bckend_word __ARGS((long count, int bigword, int eol));
  int current_word __ARGS((oparg_T *oap, long count, int include, int bigword));
  int current_sent __ARGS((oparg_T *oap, long count, int include));
! int current_block __ARGS((oparg_T *oap, long count, int include, int what, int other, int dir));
  int current_tagblock __ARGS((oparg_T *oap, long count_arg, int include));
  int current_par __ARGS((oparg_T *oap, long count, int include, int type));
  int current_quote __ARGS((oparg_T *oap, long count, int include, int quotechar));
*** a/src/search.c
--- b/src/search.c
***************
*** 3552,3563 **** extend:
   * "what" and "other" are two matching parenthesis/brace/etc.
   */
      int
! current_block(oap, count, include, what, other)
      oparg_T	*oap;
      long	count;
      int		include;	/* TRUE == include white space */
      int		what;		/* '(', '{', etc. */
      int		other;		/* ')', '}', etc. */
  {
      pos_T	old_pos;
      pos_T	*pos = NULL;
--- 3552,3564 ----
   * "what" and "other" are two matching parenthesis/brace/etc.
   */
      int
! current_block(oap, count, include, what, other, dir)
      oparg_T	*oap;
      long	count;
      int		include;	/* TRUE == include white space */
      int		what;		/* '(', '{', etc. */
      int		other;		/* ')', '}', etc. */
+     int		dir;		/* direction to search */
  {
      pos_T	old_pos;
      pos_T	*pos = NULL;
***************
*** 3619,3626 **** current_block(oap, count, include, what, other)
       */
      if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL)
      {
! 	curwin->w_cursor = old_pos;
! 	return FAIL;
      }
      curwin->w_cursor = *end_pos;
  
--- 3620,3691 ----
       */
      if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL)
      {
! 	/*
! 	 * Cursor is not in or on the disired object; however, the object may
! 	 * still be in the buffer.  Search for it in the specified direction.
! 	 */
! 
! 	/* Ensure direction is set. */
! 	if (dir != FORWARD && dir != BACKWARD)
! 	{
! 	    curwin->w_cursor = old_pos;
! 	    return FAIL;
! 	}
! 
! 	/*
! 	 * Specify the character for which we are searching as regex for
! 	 * searchit() as well as the matching character for findmatch()
! 	 */
! 	char startpat[] = "\\Vx";
! 	int endchar;
! 	if (dir == FORWARD)
! 	{
! 	    startpat[2] = what;
! 	    endchar = other;
! 	}
! 	else
! 	{
! 	    startpat[2] = other;
! 	    endchar = what;
! 	}
! 
! 	/* We do not want to wrap here, so backup 'ws' and disable it. */
! 	int save_ws = p_ws;
! 	p_ws = 0;
! 
! 	/*
! 	 * Search for startpat in buffer and, if we find it, search its
! 	 * matching endchar.
! 	 * Search ends when either we found both a starting character and its
! 	 * matching pair, or we can't find another instance of the starting
! 	 * character.
! 	 */
! 	int found_start;
! 	while ((found_start = searchit(curwin, curbuf, &curwin->w_cursor, dir,
! 					startpat, 1L, SEARCH_KEEP, 0, 0, NULL))
! 		!= FAIL && (pos = findmatch(NULL, endchar)) == NULL)
! 	    ;
! 
! 	/* Restore 'ws' */
! 	p_ws = save_ws;
! 
! 	/* Check if we found a matching set and, if not, abort. */
! 	if (found_start == FAIL || pos == NULL) {
! 	    curwin->w_cursor = old_pos;
! 	    return FAIL;
! 	}
! 
! 	/* Set start_pos and end_pos */
! 	if (dir == FORWARD)
! 	{
! 	    start_pos = curwin->w_cursor;
! 	    end_pos = pos;
! 	}
! 	else
! 	{
! 	    start_pos = *pos;
! 	    end_pos = &curwin->w_cursor;
! 	}
      }
      curwin->w_cursor = *end_pos;
  
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index d40d825..48e727f 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -574,6 +574,10 @@ a[			"a [] block", select [count] '[' ']' blocks.  This
 			goes backwards to the [count] unclosed '[', and finds
 			the matching ']'.  The enclosed text is selected,
 			including the '[' and ']'.
+			If it fails to find the block under or around the
+			cursor, and '[' was specified, it will search the
+			buffer backwards for the block or, if ']' was
+			specified, it will search the buffer forwards.
 			When used in Visual mode it is made characterwise.
 
 i]						*v_i]* *v_i[* *i]* *i[*
@@ -581,6 +585,10 @@ i[			"inner [] block", select [count] '[' ']' blocks.  This
 			goes backwards to the [count] unclosed '[', and finds
 			the matching ']'.  The enclosed text is selected,
 			excluding the '[' and ']'.
+			If it fails to find the block under or around the
+			cursor, and '[' was specified, it will search the
+			buffer backwards for the block or, if ']' was
+			specified, it will search the buffer forwards.
 			When used in Visual mode it is made characterwise.
 
 a)							*v_a)* *a)* *a(*
@@ -589,6 +597,10 @@ ab			"a block", select [count] blocks, from "[count] [(" to
 			the matching ')', including the '(' and ')' (see
 			|[(|).  Does not include white space outside of the
 			parenthesis.
+			If it fails to find the block under or around the
+			cursor, and '(' was specified, it will search the
+			buffer backwards for the block or, if ')' was
+			specified, it will search the buffer forwards.
 			When used in Visual mode it is made characterwise.
 
 i)							*v_i)* *i)* *i(*
@@ -596,18 +608,30 @@ i(							*v_ib* *v_i(* *ib*
 ib			"inner block", select [count] blocks, from "[count] [("
 			to the matching ')', excluding the '(' and ')' (see
 			|[(|).
+			If it fails to find the block under or around the
+			cursor, and '(' was specified, it will search the
+			buffer backwards for the block or, if ')' was
+			specified, it will search the buffer forwards.
 			When used in Visual mode it is made characterwise.
 
 a>						*v_a>* *v_a<* *a>* *a<*
 a<			"a <> block", select [count] <> blocks, from the
 			[count]'th unmatched '<' backwards to the matching
 			'>', including the '<' and '>'.
+			If it fails to find the block under or around the
+			cursor, and '<' was specified, it will search the
+			buffer backwards for the block or, if '>' was
+			specified, it will search the buffer forwards.
 			When used in Visual mode it is made characterwise.
 
 i>						*v_i>* *v_i<* *i>* *i<*
 i<			"inner <> block", select [count] <> blocks, from
 			the [count]'th unmatched '<' backwards to the matching
 			'>', excluding the '<' and '>'.
+			If it fails to find the block under or around the
+			cursor, and '<' was specified, it will search the
+			buffer backwards for the block or, if '>' was
+			specified, it will search the buffer forwards.
 			When used in Visual mode it is made characterwise.
 
 						*v_at* *at*
@@ -629,6 +653,10 @@ a{							*v_aB* *v_a{* *aB*
 aB			"a Block", select [count] Blocks, from "[count] [{" to
 			the matching '}', including the '{' and '}' (see
 			|[{|).
+			If it fails to find the block under or around the
+			cursor, and '{' was specified, it will search the
+			buffer backwards for the block or, if '}' was specified,
+			it will search the buffer forwards.
 			When used in Visual mode it is made characterwise.
 
 i}							*v_i}* *i}* *i{*
@@ -636,6 +664,10 @@ i{							*v_iB* *v_i{* *iB*
 iB			"inner Block", select [count] Blocks, from "[count] [{"
 			to the matching '}', excluding the '{' and '}' (see
 			|[{|).
+			If it fails to find the block under or around the
+			cursor, and '{' was specified, it will search the
+			buffer backwards for the block or, if '}' was specified,
+			it will search the buffer forwards.
 			When used in Visual mode it is made characterwise.
 
 a"							*v_aquote* *aquote*
diff --git a/src/normal.c b/src/normal.c
index 9349be2..108dc46 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -9268,6 +9268,26 @@ nv_object(cap)
     mps_save = curbuf->b_p_mps;
     curbuf->b_p_mps = (char_u *)"(:),{:},[:],<:>";
 
+    /* Set search direction */
+    int dir;
+    switch(cap->nchar)
+    {
+	case '(':
+	case '{':
+	case '[':
+	case '<':
+	    dir = BACKWARD;
+	    break;
+	case ')':
+	case '}':
+	case ']':
+	case '>':
+	    dir = FORWARD;
+	    break;
+	default:
+	    dir = 0;
+    }
+
     switch (cap->nchar)
     {
 	case 'w': /* "aw" = a word */
@@ -9279,20 +9299,20 @@ nv_object(cap)
 	case 'b': /* "ab" = a braces block */
 	case '(':
 	case ')':
-		flag = current_block(cap->oap, cap->count1, include, '(', ')');
+		flag = current_block(cap->oap, cap->count1, include, '(', ')', dir);
 		break;
 	case 'B': /* "aB" = a Brackets block */
 	case '{':
 	case '}':
-		flag = current_block(cap->oap, cap->count1, include, '{', '}');
+		flag = current_block(cap->oap, cap->count1, include, '{', '}', dir);
 		break;
 	case '[': /* "a[" = a [] block */
 	case ']':
-		flag = current_block(cap->oap, cap->count1, include, '[', ']');
+		flag = current_block(cap->oap, cap->count1, include, '[', ']', dir);
 		break;
 	case '<': /* "a<" = a <> block */
 	case '>':
-		flag = current_block(cap->oap, cap->count1, include, '<', '>');
+		flag = current_block(cap->oap, cap->count1, include, '<', '>', dir);
 		break;
 	case 't': /* "at" = a tag block (xml and html) */
 		flag = current_tagblock(cap->oap, cap->count1, include);
diff --git a/src/proto/search.pro b/src/proto/search.pro
index f94fb69..ef1f44c 100644
--- a/src/proto/search.pro
+++ b/src/proto/search.pro
@@ -28,7 +28,7 @@ int end_word __ARGS((long count, int bigword, int stop, int empty));
 int bckend_word __ARGS((long count, int bigword, int eol));
 int current_word __ARGS((oparg_T *oap, long count, int include, int bigword));
 int current_sent __ARGS((oparg_T *oap, long count, int include));
-int current_block __ARGS((oparg_T *oap, long count, int include, int what, int other));
+int current_block __ARGS((oparg_T *oap, long count, int include, int what, int other, int dir));
 int current_tagblock __ARGS((oparg_T *oap, long count_arg, int include));
 int current_par __ARGS((oparg_T *oap, long count, int include, int type));
 int current_quote __ARGS((oparg_T *oap, long count, int include, int quotechar));
diff --git a/src/search.c b/src/search.c
index 2fb7624..fd8fd64 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3552,12 +3552,13 @@ extend:
  * "what" and "other" are two matching parenthesis/brace/etc.
  */
     int
-current_block(oap, count, include, what, other)
+current_block(oap, count, include, what, other, dir)
     oparg_T	*oap;
     long	count;
     int		include;	/* TRUE == include white space */
     int		what;		/* '(', '{', etc. */
     int		other;		/* ')', '}', etc. */
+    int		dir;		/* direction to search */
 {
     pos_T	old_pos;
     pos_T	*pos = NULL;
@@ -3619,8 +3620,72 @@ current_block(oap, count, include, what, other)
      */
     if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL)
     {
-	curwin->w_cursor = old_pos;
-	return FAIL;
+	/*
+	 * Cursor is not in or on the disired object; however, the object may
+	 * still be in the buffer.  Search for it in the specified direction.
+	 */
+
+	/* Ensure direction is set. */
+	if (dir != FORWARD && dir != BACKWARD)
+	{
+	    curwin->w_cursor = old_pos;
+	    return FAIL;
+	}
+
+	/*
+	 * Specify the character for which we are searching as regex for
+	 * searchit() as well as the matching character for findmatch()
+	 */
+	char startpat[] = "\\Vx";
+	int endchar;
+	if (dir == FORWARD)
+	{
+	    startpat[2] = what;
+	    endchar = other;
+	}
+	else
+	{
+	    startpat[2] = other;
+	    endchar = what;
+	}
+
+	/* We do not want to wrap here, so backup 'ws' and disable it. */
+	int save_ws = p_ws;
+	p_ws = 0;
+
+	/*
+	 * Search for startpat in buffer and, if we find it, search its
+	 * matching endchar.
+	 * Search ends when either we found both a starting character and its
+	 * matching pair, or we can't find another instance of the starting
+	 * character.
+	 */
+	int found_start;
+	while ((found_start = searchit(curwin, curbuf, &curwin->w_cursor, dir,
+					startpat, 1L, SEARCH_KEEP, 0, 0, NULL))
+		!= FAIL && (pos = findmatch(NULL, endchar)) == NULL)
+	    ;
+
+	/* Restore 'ws' */
+	p_ws = save_ws;
+
+	/* Check if we found a matching set and, if not, abort. */
+	if (found_start == FAIL || pos == NULL) {
+	    curwin->w_cursor = old_pos;
+	    return FAIL;
+	}
+
+	/* Set start_pos and end_pos */
+	if (dir == FORWARD)
+	{
+	    start_pos = curwin->w_cursor;
+	    end_pos = pos;
+	}
+	else
+	{
+	    start_pos = *pos;
+	    end_pos = &curwin->w_cursor;
+	}
     }
     curwin->w_cursor = *end_pos;
 

Raspunde prin e-mail lui