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;