On Wednesday, November 20, 2013 7:16:59 PM UTC-5, Daniel "paradigm" Thau wrote:
> On Tuesday, November 19, 2013 2:25:48 PM UTC-5, 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 <>.
> > 
> > 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.
> 
> Attached is a newer version of the same patch with reworked code to be a bit 
> cleaner.  It includes Christian's suggestion for the search direction.

The attachments didn't seem to stick; trying again.

-- 
-- 
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
***************
*** 662,667 **** i`							*v_i`* *i`*
--- 662,675 ----
  			Special case: With a count of 2 the quotes are
  			included, but no extra white space as with a"/a'/a`.
  
+ am{char}						*v_am* *am*
+ 			"a matched {char}".  Selects the text from the
+ 			previous {char} until the next {char}.  A count is
+ 			currently not used.
+ 
+ im{char}						*v_im* *im*
+ 			Like am{char} but exclude the {char}.
+ 
  When used after an operator:
  For non-block objects:
  	For the "a" commands: The operator applies to the object and the white
*** a/src/normal.c
--- b/src/normal.c
***************
*** 9309,9314 **** nv_object(cap)
--- 9309,9319 ----
  		flag = current_quote(cap->oap, cap->count1, include,
  								  cap->nchar);
  		break;
+ 	case 'm': /* "am{char}" = a matched pair of characters */
+ 		cap->extra_char = plain_vgetc();
+ 		flag = current_match(cap->oap, cap->count1, include,
+ 							      cap->extra_char);
+ 		break;
  #if 0	/* TODO */
  	case 'S': /* "aS" = a section */
  	case 'f': /* "af" = a filename */
*** a/src/proto/search.pro
--- b/src/proto/search.pro
***************
*** 32,37 **** int current_block __ARGS((oparg_T *oap, long count, int include, int what, int o
--- 32,38 ----
  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));
+ int current_match __ARGS((oparg_T *oap, long count, int include, int matchchar));
  int current_search __ARGS((long count, int forward));
  int linewhite __ARGS((linenr_T lnum));
  void find_pattern_in_path __ARGS((char_u *ptr, int dir, int len, int whole, int skip_comments, int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum));
*** a/src/search.c
--- b/src/search.c
***************
*** 4489,4494 **** current_quote(oap, count, include, quotechar)
--- 4489,4635 ----
      return OK;
  }
  
+     /*
+      * Find matching {char} on each side of cursor/visually selected range.
+      * Returns TRUE if found, else FALSE.
+      */
+     int
+ current_match(oap, count, include, matchchar)
+     oparg_T	*oap;		/* used to set operator range, mode, etc */
+     long	count;		/* not currently used */
+     int		include;	/* TRUE == include quote char */
+     int		matchchar;	/* char to match on both sides */
+ {
+     pos_T	old_pos;	/* initial cursor position (to restore) */
+     pos_T	start_pos;	/* left bound */
+     pos_T	end_pos;	/* right bound */
+     int		ret;		/* temp holder for return values */
+ #ifdef FEAT_VISUAL
+     int		vis_bef_curs;	/* store visual mode direction */
+ 
+     /*
+      * Store visual mode direction so we can be sure it is set the same
+      * direction when we're done.
+      */
+     vis_bef_curs = ltoreq(VIsual, curwin->w_cursor);
+ #endif
+ 
+     /*
+      * Remember starting position so we can restore if we cannot find the
+      * requested object.
+      */
+     old_pos = curwin->w_cursor;
+ 
+     /*
+      * If there is a visually selected range, use its bounds as the starting
+      * bounds.  Otherwise, have both bounds start under the cursor.
+      */
+ #ifdef FEAT_VISUAL
+     if (VIsual_active && lt(VIsual, curwin->w_cursor))
+     {
+ 	start_pos = VIsual;
+ 	end_pos = curwin->w_cursor;
+     }
+     else if (VIsual_active && lt(curwin->w_cursor, VIsual))
+     {
+ 	start_pos = curwin->w_cursor;
+ 	end_pos = VIsual;
+     }
+     else
+ #endif
+     {
+ 	start_pos = curwin->w_cursor;
+ 	end_pos = curwin->w_cursor;
+     }
+ 
+     /*
+      * Search for the left bound.  It can be under or behind the starting
+      * position of the cursor position/visually selected range.
+      */
+     curwin->w_cursor = start_pos;
+     while (gchar_cursor() != matchchar && dec_cursor() != -1)
+ 	;
+     if (gchar_cursor() != matchchar)
+     {
+ 	/* Failed to find left bound, abort. */
+ 	curwin->w_cursor = old_pos;
+ 	return FAIL;
+     }
+     start_pos = curwin->w_cursor;
+ 
+     /*
+      * Search for the right bound.  It has to be to the right of the starting
+      * cursor position/visually selected range.
+      */
+     curwin->w_cursor = end_pos;
+     while (inc_cursor() != -1 && gchar_cursor() != matchchar)
+ 	;
+     if (gchar_cursor() != matchchar)
+     {
+ 	/* Failed to find right bound, abort. */
+ 	curwin->w_cursor = old_pos;
+ 	return FAIL;
+     }
+     end_pos = curwin->w_cursor;
+ 
+     /*
+      * If not include (i.e.: o_i was used), try to move the bounds inward, but
+      * be sure they don't overlap or switch sides.
+      */
+     if (!include)
+     {
+ 	/* try moving in right bound */
+ 	curwin->w_cursor = end_pos;
+ 	ret = dec_cursor();
+ 	if (ret == 2)
+ 	    ret = dec_cursor();
+ 	if (ret != -1 && !ltoreq(curwin->w_cursor, start_pos))
+ 	{
+ 	    end_pos = curwin->w_cursor;
+ 	}
+ 
+ 	/* try moving in left bound */
+ 	curwin->w_cursor = start_pos;
+ 	ret = inc_cursor();
+ 	if (ret == 2)
+ 	    ret = inc_cursor();
+ 	if (ret != -1 && !ltoreq(end_pos, curwin->w_cursor))
+ 	{
+ 	    start_pos = curwin->w_cursor;
+ 	}
+     }
+ 
+     /*
+      * We've found the new bounds.  Set it in the appropriate places before
+      * returning.
+      */
+ #ifdef FEAT_VISUAL
+     if (VIsual_active)
+     {
+ 	/* Retain direction we had when starting. */
+ 	if (vis_bef_curs)
+ 	{
+ 	    VIsual = start_pos;
+ 	    curwin->w_cursor = end_pos;
+ 	}
+ 	else
+ 	{
+ 	    curwin->w_cursor = start_pos;
+ 	    VIsual = end_pos;
+ 	}
+ 	redraw_curbuf_later(INVERTED);	/* update the inversion */
+     }
+     else
+ #endif
+     {
+ 	oap->start = start_pos;
+ 	curwin->w_cursor = end_pos;
+ 	oap->motion_type = MCHAR;
+ 	oap->inclusive = TRUE;
+     }
+     return OK;
+ }
+ 
  #endif /* FEAT_TEXTOBJ */
  
  #if defined(FEAT_VISUAL) || defined(PROTO)
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index d40d825..1cb2287 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -662,6 +662,14 @@ i`							*v_i`* *i`*
 			Special case: With a count of 2 the quotes are
 			included, but no extra white space as with a"/a'/a`.
 
+am{char}						*v_am* *am*
+			"a matched {char}".  Selects the text from the
+			previous {char} until the next {char}.  A count is
+			currently not used.
+
+im{char}						*v_im* *im*
+			Like am{char} but exclude the {char}.
+
 When used after an operator:
 For non-block objects:
 	For the "a" commands: The operator applies to the object and the white
diff --git a/src/normal.c b/src/normal.c
index 9349be2..0758ff7 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -9309,6 +9309,11 @@ nv_object(cap)
 		flag = current_quote(cap->oap, cap->count1, include,
 								  cap->nchar);
 		break;
+	case 'm': /* "am{char}" = a matched pair of characters */
+		cap->extra_char = plain_vgetc();
+		flag = current_match(cap->oap, cap->count1, include,
+							      cap->extra_char);
+		break;
 #if 0	/* TODO */
 	case 'S': /* "aS" = a section */
 	case 'f': /* "af" = a filename */
diff --git a/src/proto/search.pro b/src/proto/search.pro
index f94fb69..0cf3be3 100644
--- a/src/proto/search.pro
+++ b/src/proto/search.pro
@@ -32,6 +32,7 @@ int current_block __ARGS((oparg_T *oap, long count, int include, int what, int o
 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));
+int current_match __ARGS((oparg_T *oap, long count, int include, int matchchar));
 int current_search __ARGS((long count, int forward));
 int linewhite __ARGS((linenr_T lnum));
 void find_pattern_in_path __ARGS((char_u *ptr, int dir, int len, int whole, int skip_comments, int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum));
diff --git a/src/search.c b/src/search.c
index 2fb7624..5075739 100644
--- a/src/search.c
+++ b/src/search.c
@@ -4489,6 +4489,147 @@ current_quote(oap, count, include, quotechar)
     return OK;
 }
 
+    /*
+     * Find matching {char} on each side of cursor/visually selected range.
+     * Returns TRUE if found, else FALSE.
+     */
+    int
+current_match(oap, count, include, matchchar)
+    oparg_T	*oap;		/* used to set operator range, mode, etc */
+    long	count;		/* not currently used */
+    int		include;	/* TRUE == include quote char */
+    int		matchchar;	/* char to match on both sides */
+{
+    pos_T	old_pos;	/* initial cursor position (to restore) */
+    pos_T	start_pos;	/* left bound */
+    pos_T	end_pos;	/* right bound */
+    int		ret;		/* temp holder for return values */
+#ifdef FEAT_VISUAL
+    int		vis_bef_curs;	/* store visual mode direction */
+
+    /*
+     * Store visual mode direction so we can be sure it is set the same
+     * direction when we're done.
+     */
+    vis_bef_curs = ltoreq(VIsual, curwin->w_cursor);
+#endif
+
+    /*
+     * Remember starting position so we can restore if we cannot find the
+     * requested object.
+     */
+    old_pos = curwin->w_cursor;
+
+    /*
+     * If there is a visually selected range, use its bounds as the starting
+     * bounds.  Otherwise, have both bounds start under the cursor.
+     */
+#ifdef FEAT_VISUAL
+    if (VIsual_active && lt(VIsual, curwin->w_cursor))
+    {
+	start_pos = VIsual;
+	end_pos = curwin->w_cursor;
+    }
+    else if (VIsual_active && lt(curwin->w_cursor, VIsual))
+    {
+	start_pos = curwin->w_cursor;
+	end_pos = VIsual;
+    }
+    else
+#endif
+    {
+	start_pos = curwin->w_cursor;
+	end_pos = curwin->w_cursor;
+    }
+
+    /*
+     * Search for the left bound.  It can be under or behind the starting
+     * position of the cursor position/visually selected range.
+     */
+    curwin->w_cursor = start_pos;
+    while (gchar_cursor() != matchchar && dec_cursor() != -1)
+	;
+    if (gchar_cursor() != matchchar)
+    {
+	/* Failed to find left bound, abort. */
+	curwin->w_cursor = old_pos;
+	return FAIL;
+    }
+    start_pos = curwin->w_cursor;
+
+    /*
+     * Search for the right bound.  It has to be to the right of the starting
+     * cursor position/visually selected range.
+     */
+    curwin->w_cursor = end_pos;
+    while (inc_cursor() != -1 && gchar_cursor() != matchchar)
+	;
+    if (gchar_cursor() != matchchar)
+    {
+	/* Failed to find right bound, abort. */
+	curwin->w_cursor = old_pos;
+	return FAIL;
+    }
+    end_pos = curwin->w_cursor;
+
+    /*
+     * If not include (i.e.: o_i was used), try to move the bounds inward, but
+     * be sure they don't overlap or switch sides.
+     */
+    if (!include)
+    {
+	/* try moving in right bound */
+	curwin->w_cursor = end_pos;
+	ret = dec_cursor();
+	if (ret == 2)
+	    ret = dec_cursor();
+	if (ret != -1 && !ltoreq(curwin->w_cursor, start_pos))
+	{
+	    end_pos = curwin->w_cursor;
+	}
+
+	/* try moving in left bound */
+	curwin->w_cursor = start_pos;
+	ret = inc_cursor();
+	if (ret == 2)
+	    ret = inc_cursor();
+	if (ret != -1 && !ltoreq(end_pos, curwin->w_cursor))
+	{
+	    start_pos = curwin->w_cursor;
+	}
+    }
+
+    /*
+     * We've found the new bounds.  Set it in the appropriate places before
+     * returning.
+     */
+#ifdef FEAT_VISUAL
+    if (VIsual_active)
+    {
+	/* Retain direction we had when starting. */
+	if (vis_bef_curs)
+	{
+	    VIsual = start_pos;
+	    curwin->w_cursor = end_pos;
+	}
+	else
+	{
+	    curwin->w_cursor = start_pos;
+	    VIsual = end_pos;
+	}
+	redraw_curbuf_later(INVERTED);	/* update the inversion */
+    }
+    else
+#endif
+    {
+	oap->start = start_pos;
+	curwin->w_cursor = end_pos;
+	oap->motion_type = MCHAR;
+	oap->inclusive = TRUE;
+    }
+    return OK;
+}
+
 #endif /* FEAT_TEXTOBJ */
 
 #if defined(FEAT_VISUAL) || defined(PROTO)

Raspunde prin e-mail lui