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 <>.

Attached is a patch (both in the context and unified formats) to implement 
this.  It seems relatively simple/clean to me, but people looking over and 
testing would be benficial in case I failed to consider something.

-- 
-- 
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 forward for the block or, if ']' was specified,
+ 			it will search the buffer backwards.
  			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 forward for the block or, if ']' was specified,
+ 			it will search the buffer backwards.
  			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 forward for the block or, if ')' was specified,
+ 			it will search the buffer backwards.
  			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 forward for the block or, if ')' was specified,
+ 			it will search the buffer backwards.
  			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 forward for the block or, if '>' was specified,
+ 			it will search the buffer backwards.
  			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 forward for the block or, if '>' was specified,
+ 			it will search the buffer backwards.
  			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 forward for the block or, if '}' was specified,
+ 			it will search the buffer backwards.
  			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 forward for the block or, if '}' was specified,
+ 			it will search the buffer backwards.
  			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 = FORWARD;
+ 	    break;
+ 	case ')':
+ 	case '}':
+ 	case ']':
+ 	case '>':
+ 	    dir = BACKWARD;
+ 	    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..9222ce3 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 forward for the block or, if ']' was specified,
+			it will search the buffer backwards.
 			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 forward for the block or, if ']' was specified,
+			it will search the buffer backwards.
 			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 forward for the block or, if ')' was specified,
+			it will search the buffer backwards.
 			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 forward for the block or, if ')' was specified,
+			it will search the buffer backwards.
 			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 forward for the block or, if '>' was specified,
+			it will search the buffer backwards.
 			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 forward for the block or, if '>' was specified,
+			it will search the buffer backwards.
 			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 forward for the block or, if '}' was specified,
+			it will search the buffer backwards.
 			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 forward for the block or, if '}' was specified,
+			it will search the buffer backwards.
 			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..40cf44a 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 = FORWARD;
+	    break;
+	case ')':
+	case '}':
+	case ']':
+	case '>':
+	    dir = BACKWARD;
+	    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