On Wednesday, January 29, 2014 7:45:23 PM UTC-5, Daniel "paradigm" Thau wrote:
> Apologies for the delay.
>
> Review for those who have forgotten and/or don't care to backread:
>
> This patch adds a new text object, "m", which will take one more character as
> input. That character will be used as bounds to the left and right for the
> object. For example, "cim$" will change between dollar signs. This supports
> multi-line objects, so one could do "cim'" which, unlike "ci'", will search
> across lines; this way users have both.
>
> I've been using it quite happily for the last two months or so, but more eyes
> and testing would not be a bad idea.
>
> Attached is the patch, in both unified and context format, including a test.
Added wrong file/filename for the test results. Fixed in attachment.
--
--
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.
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/runtime/doc/tags b/runtime/doc/tags
index dce548f..eb258d5 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -4760,6 +4760,7 @@ aleph options.txt /*aleph*
alt intro.txt /*alt*
alt-input debugger.txt /*alt-input*
alternate-file editing.txt /*alternate-file*
+am motion.txt /*am*
amiga-window starting.txt /*amiga-window*
and() eval.txt /*and()*
anonymous-function eval.txt /*anonymous-function*
@@ -6532,6 +6533,7 @@ if_ruby.txt if_ruby.txt /*if_ruby.txt*
if_sniff.txt if_sniff.txt /*if_sniff.txt*
if_tcl.txt if_tcl.txt /*if_tcl.txt*
ignore-errors eval.txt /*ignore-errors*
+im motion.txt /*im*
improved-autocmds-5.4 version5.txt /*improved-autocmds-5.4*
improved-quickfix version5.txt /*improved-quickfix*
improved-sessions version5.txt /*improved-sessions*
@@ -8457,6 +8459,7 @@ v_a[ motion.txt /*v_a[*
v_a] motion.txt /*v_a]*
v_a` motion.txt /*v_a`*
v_ab motion.txt /*v_ab*
+v_am motion.txt /*v_am*
v_ap motion.txt /*v_ap*
v_aquote motion.txt /*v_aquote*
v_as motion.txt /*v_as*
@@ -8504,6 +8507,7 @@ v_i[ motion.txt /*v_i[*
v_i] motion.txt /*v_i]*
v_i` motion.txt /*v_i`*
v_ib motion.txt /*v_ib*
+v_im motion.txt /*v_im*
v_ip motion.txt /*v_ip*
v_iquote motion.txt /*v_iquote*
v_is motion.txt /*v_is*
diff --git a/src/normal.c b/src/normal.c
index 66a5b7a..09d9d0e 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -9310,6 +9310,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 0341a5e..58db91e 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 bounding 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/src/testdir/Makefile b/src/testdir/Makefile
index bae4f44..bd29836 100644
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -30,7 +30,8 @@ SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
test84.out test85.out test86.out test87.out test88.out \
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test97.out test98.out \
- test99.out test100.out test101.out test102.out test103.out
+ test99.out test100.out test101.out test102.out test103.out \
+ test104.out
SCRIPTS_GUI = test16.out
diff --git a/src/testdir/test104.in b/src/testdir/test104.in
new file mode 100644
index 0000000..70df33d
--- /dev/null
+++ b/src/testdir/test104.in
@@ -0,0 +1,59 @@
+Test for im/am text object
+
+Tests every combination of the following:
+- every non-whitespace printable ASCII character (bang/33 to tilde/126)
+- im (i) or am (a)
+- in-line (l) or entire-line (L)
+- single line (s) or multiple line (S)
+
+STARTTEST
+:so small.vim
+:enew
+:
+:" Generate lines with im/am objects in them
+:
+:for nr in range(33, 126)
+: let char = nr2char(nr)
+: let diffchar = nr2char((nr - 33 + 1) % (126 - 32) + 33)
+: let diffchars = diffchar . diffchar . diffchar
+: for ia in ["i", "a"]
+: for lL in ["l", "L"]
+: for sS in ["s", "S"]
+: if sS == "s"
+: let lines = diffchars
+: else
+: let lines = diffchars . "\<cr>" . diffchars
+: endif
+: execute "normal o" . char . ia . lL . sS . "X" . char . lines . char . "X\<esc>"
+: endfor
+: endfor
+: endfor
+:endfor
+:
+:" Apply im/am to every created object
+:
+:for nr in range(33, 126)
+: let char = nr2char(nr)
+: let diffchar = nr2char((nr - 33 + 1) % (126 - 32) + 33)
+: let diffchars = diffchar . diffchar . diffchar
+: for ia in ["i", "a"]
+: for lL in ["l", "L"]
+: for sS in ["s", "S"]
+: execute "normal /^\\V" . escape(char,"\\") . ia . lL . sS . "\<cr>4x"
+: if lL == "L"
+: if sS == "s"
+: execute "normal $x0x"
+: else
+: execute "normal j$xk0x"
+: endif
+: endif
+: execute "normal lc" . ia . "m" . char . "OK\<esc>"
+: endfor
+: endfor
+: endfor
+:endfor
+:
+:w! test.out
+:qa!
+ENDTEST
+
diff --git a/src/testdir/test104.ok b/src/testdir/test104.ok
new file mode 100644
index 0000000..3e095db
--- /dev/null
+++ b/src/testdir/test104.ok
@@ -0,0 +1,753 @@
+
+X!OK!X
+X!OK!X
+!OK!
+!OK!
+XOKX
+XOKX
+OK
+OK
+X"OK"X
+X"OK"X
+"OK"
+"OK"
+XOKX
+XOKX
+OK
+OK
+X#OK#X
+X#OK#X
+#OK#
+#OK#
+XOKX
+XOKX
+OK
+OK
+X$OK$X
+X$OK$X
+$OK$
+$OK$
+XOKX
+XOKX
+OK
+OK
+X%OK%X
+X%OK%X
+%OK%
+%OK%
+XOKX
+XOKX
+OK
+OK
+X&OK&X
+X&OK&X
+&OK&
+&OK&
+XOKX
+XOKX
+OK
+OK
+X'OK'X
+X'OK'X
+'OK'
+'OK'
+XOKX
+XOKX
+OK
+OK
+X(OK(X
+X(OK(X
+(OK(
+(OK(
+XOKX
+XOKX
+OK
+OK
+X)OK)X
+X)OK)X
+)OK)
+)OK)
+XOKX
+XOKX
+OK
+OK
+X*OK*X
+X*OK*X
+*OK*
+*OK*
+XOKX
+XOKX
+OK
+OK
+X+OK+X
+X+OK+X
++OK+
++OK+
+XOKX
+XOKX
+OK
+OK
+X,OK,X
+X,OK,X
+,OK,
+,OK,
+XOKX
+XOKX
+OK
+OK
+X-OK-X
+X-OK-X
+-OK-
+-OK-
+XOKX
+XOKX
+OK
+OK
+X.OK.X
+X.OK.X
+.OK.
+.OK.
+XOKX
+XOKX
+OK
+OK
+X/OK/X
+X/OK/X
+/OK/
+/OK/
+XOKX
+XOKX
+OK
+OK
+X0OK0X
+X0OK0X
+0OK0
+0OK0
+XOKX
+XOKX
+OK
+OK
+X1OK1X
+X1OK1X
+1OK1
+1OK1
+XOKX
+XOKX
+OK
+OK
+X2OK2X
+X2OK2X
+2OK2
+2OK2
+XOKX
+XOKX
+OK
+OK
+X3OK3X
+X3OK3X
+3OK3
+3OK3
+XOKX
+XOKX
+OK
+OK
+X4OK4X
+X4OK4X
+4OK4
+4OK4
+XOKX
+XOKX
+OK
+OK
+X5OK5X
+X5OK5X
+5OK5
+5OK5
+XOKX
+XOKX
+OK
+OK
+X6OK6X
+X6OK6X
+6OK6
+6OK6
+XOKX
+XOKX
+OK
+OK
+X7OK7X
+X7OK7X
+7OK7
+7OK7
+XOKX
+XOKX
+OK
+OK
+X8OK8X
+X8OK8X
+8OK8
+8OK8
+XOKX
+XOKX
+OK
+OK
+X9OK9X
+X9OK9X
+9OK9
+9OK9
+XOKX
+XOKX
+OK
+OK
+X:OK:X
+X:OK:X
+:OK:
+:OK:
+XOKX
+XOKX
+OK
+OK
+X;OK;X
+X;OK;X
+;OK;
+;OK;
+XOKX
+XOKX
+OK
+OK
+X<OK<X
+X<OK<X
+<OK<
+<OK<
+XOKX
+XOKX
+OK
+OK
+X=OK=X
+X=OK=X
+=OK=
+=OK=
+XOKX
+XOKX
+OK
+OK
+X>OK>X
+X>OK>X
+>OK>
+>OK>
+XOKX
+XOKX
+OK
+OK
+X?OK?X
+X?OK?X
+?OK?
+?OK?
+XOKX
+XOKX
+OK
+OK
+X@OK@X
+X@OK@X
+@OK@
+@OK@
+XOKX
+XOKX
+OK
+OK
+XAOKAX
+XAOKAX
+AOKA
+AOKA
+XOKX
+XOKX
+OK
+OK
+XBOKBX
+XBOKBX
+BOKB
+BOKB
+XOKX
+XOKX
+OK
+OK
+XCOKCX
+XCOKCX
+COKC
+COKC
+XOKX
+XOKX
+OK
+OK
+XDOKDX
+XDOKDX
+DOKD
+DOKD
+XOKX
+XOKX
+OK
+OK
+XEOKEX
+XEOKEX
+EOKE
+EOKE
+XOKX
+XOKX
+OK
+OK
+XFOKFX
+XFOKFX
+FOKF
+FOKF
+XOKX
+XOKX
+OK
+OK
+XGOKGX
+XGOKGX
+GOKG
+GOKG
+XOKX
+XOKX
+OK
+OK
+XHOKHX
+XHOKHX
+HOKH
+HOKH
+XOKX
+XOKX
+OK
+OK
+XIOKIX
+XIOKIX
+IOKI
+IOKI
+XOKX
+XOKX
+OK
+OK
+XJOKJX
+XJOKJX
+JOKJ
+JOKJ
+XOKX
+XOKX
+OK
+OK
+XKOKKX
+XKOKKX
+KOKK
+KOKK
+XOKX
+XOKX
+OK
+OK
+XLOKLX
+XLOKLX
+LOKL
+LOKL
+XOKX
+XOKX
+OK
+OK
+XMOKMX
+XMOKMX
+MOKM
+MOKM
+XOKX
+XOKX
+OK
+OK
+XNOKNX
+XNOKNX
+NOKN
+NOKN
+XOKX
+XOKX
+OK
+OK
+XOOKOX
+XOOKOX
+OOKO
+OOKO
+XOKX
+XOKX
+OK
+OK
+XPOKPX
+XPOKPX
+POKP
+POKP
+XOKX
+XOKX
+OK
+OK
+XQOKQX
+XQOKQX
+QOKQ
+QOKQ
+XOKX
+XOKX
+OK
+OK
+XROKRX
+XROKRX
+ROKR
+ROKR
+XOKX
+XOKX
+OK
+OK
+XSOKSX
+XSOKSX
+SOKS
+SOKS
+XOKX
+XOKX
+OK
+OK
+XTOKTX
+XTOKTX
+TOKT
+TOKT
+XOKX
+XOKX
+OK
+OK
+XUOKUX
+XUOKUX
+UOKU
+UOKU
+XOKX
+XOKX
+OK
+OK
+XVOKVX
+XVOKVX
+VOKV
+VOKV
+XOKX
+XOKX
+OK
+OK
+XWOKWX
+XWOKWX
+WOKW
+WOKW
+XOKX
+XOKX
+OK
+OK
+XXOKXX
+XXOKXX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+OK
+XYOKYX
+XYOKYX
+YOKY
+YOKY
+XOKX
+XOKX
+OK
+OK
+XZOKZX
+XZOKZX
+ZOKZ
+ZOKZ
+XOKX
+XOKX
+OK
+OK
+X[OK[X
+X[OK[X
+[OK[
+[OK[
+XOKX
+XOKX
+OK
+OK
+X\OK\X
+X\OK\X
+\OK\
+\OK\
+XOKX
+XOKX
+OK
+OK
+X]OK]X
+X]OK]X
+]OK]
+]OK]
+XOKX
+XOKX
+OK
+OK
+X^OK^X
+X^OK^X
+^OK^
+^OK^
+XOKX
+XOKX
+OK
+OK
+X_OK_X
+X_OK_X
+_OK_
+_OK_
+XOKX
+XOKX
+OK
+OK
+X`OK`X
+X`OK`X
+`OK`
+`OK`
+XOKX
+XOKX
+OK
+OK
+XaOKaX
+XaOKaX
+aOKa
+aOKa
+XOKX
+XOKX
+OK
+OK
+XbOKbX
+XbOKbX
+bOKb
+bOKb
+XOKX
+XOKX
+OK
+OK
+XcOKcX
+XcOKcX
+cOKc
+cOKc
+XOKX
+XOKX
+OK
+OK
+XdOKdX
+XdOKdX
+dOKd
+dOKd
+XOKX
+XOKX
+OK
+OK
+XeOKeX
+XeOKeX
+eOKe
+eOKe
+XOKX
+XOKX
+OK
+OK
+XfOKfX
+XfOKfX
+fOKf
+fOKf
+XOKX
+XOKX
+OK
+OK
+XgOKgX
+XgOKgX
+gOKg
+gOKg
+XOKX
+XOKX
+OK
+OK
+XhOKhX
+XhOKhX
+hOKh
+hOKh
+XOKX
+XOKX
+OK
+OK
+XiOKiX
+XiOKiX
+iOKi
+iOKi
+XOKX
+XOKX
+OK
+OK
+XjOKjX
+XjOKjX
+jOKj
+jOKj
+XOKX
+XOKX
+OK
+OK
+XkOKkX
+XkOKkX
+kOKk
+kOKk
+XOKX
+XOKX
+OK
+OK
+XlOKlX
+XlOKlX
+lOKl
+lOKl
+XOKX
+XOKX
+OK
+OK
+XmOKmX
+XmOKmX
+mOKm
+mOKm
+XOKX
+XOKX
+OK
+OK
+XnOKnX
+XnOKnX
+nOKn
+nOKn
+XOKX
+XOKX
+OK
+OK
+XoOKoX
+XoOKoX
+oOKo
+oOKo
+XOKX
+XOKX
+OK
+OK
+XpOKpX
+XpOKpX
+pOKp
+pOKp
+XOKX
+XOKX
+OK
+OK
+XqOKqX
+XqOKqX
+qOKq
+qOKq
+XOKX
+XOKX
+OK
+OK
+XrOKrX
+XrOKrX
+rOKr
+rOKr
+XOKX
+XOKX
+OK
+OK
+XsOKsX
+XsOKsX
+sOKs
+sOKs
+XOKX
+XOKX
+OK
+OK
+XtOKtX
+XtOKtX
+tOKt
+tOKt
+XOKX
+XOKX
+OK
+OK
+XuOKuX
+XuOKuX
+uOKu
+uOKu
+XOKX
+XOKX
+OK
+OK
+XvOKvX
+XvOKvX
+vOKv
+vOKv
+XOKX
+XOKX
+OK
+OK
+XwOKwX
+XwOKwX
+wOKw
+wOKw
+XOKX
+XOKX
+OK
+OK
+XxOKxX
+XxOKxX
+xOKx
+xOKx
+XOKX
+XOKX
+OK
+OK
+XyOKyX
+XyOKyX
+yOKy
+yOKy
+XOKX
+XOKX
+OK
+OK
+XzOKzX
+XzOKzX
+zOKz
+zOKz
+XOKX
+XOKX
+OK
+OK
+X{OK{X
+X{OK{X
+{OK{
+{OK{
+XOKX
+XOKX
+OK
+OK
+X|OK|X
+X|OK|X
+|OK|
+|OK|
+XOKX
+XOKX
+OK
+OK
+X}OK}X
+X}OK}X
+}OK}
+}OK}
+XOKX
+XOKX
+OK
+OK
+X~OK~X
+X~OK~X
+~OK~
+~OK~
+XOKX
+XOKX
+OK
+OK
*** 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/runtime/doc/tags
--- b/runtime/doc/tags
***************
*** 4760,4765 **** aleph options.txt /*aleph*
--- 4760,4766 ----
alt intro.txt /*alt*
alt-input debugger.txt /*alt-input*
alternate-file editing.txt /*alternate-file*
+ am motion.txt /*am*
amiga-window starting.txt /*amiga-window*
and() eval.txt /*and()*
anonymous-function eval.txt /*anonymous-function*
***************
*** 6532,6537 **** if_ruby.txt if_ruby.txt /*if_ruby.txt*
--- 6533,6539 ----
if_sniff.txt if_sniff.txt /*if_sniff.txt*
if_tcl.txt if_tcl.txt /*if_tcl.txt*
ignore-errors eval.txt /*ignore-errors*
+ im motion.txt /*im*
improved-autocmds-5.4 version5.txt /*improved-autocmds-5.4*
improved-quickfix version5.txt /*improved-quickfix*
improved-sessions version5.txt /*improved-sessions*
***************
*** 8457,8462 **** v_a[ motion.txt /*v_a[*
--- 8459,8465 ----
v_a] motion.txt /*v_a]*
v_a` motion.txt /*v_a`*
v_ab motion.txt /*v_ab*
+ v_am motion.txt /*v_am*
v_ap motion.txt /*v_ap*
v_aquote motion.txt /*v_aquote*
v_as motion.txt /*v_as*
***************
*** 8504,8509 **** v_i[ motion.txt /*v_i[*
--- 8507,8513 ----
v_i] motion.txt /*v_i]*
v_i` motion.txt /*v_i`*
v_ib motion.txt /*v_ib*
+ v_im motion.txt /*v_im*
v_ip motion.txt /*v_ip*
v_iquote motion.txt /*v_iquote*
v_is motion.txt /*v_is*
*** a/src/normal.c
--- b/src/normal.c
***************
*** 9310,9315 **** nv_object(cap)
--- 9310,9320 ----
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 bounding 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)
*** a/src/testdir/Makefile
--- b/src/testdir/Makefile
***************
*** 30,36 **** SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
test84.out test85.out test86.out test87.out test88.out \
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test97.out test98.out \
! test99.out test100.out test101.out test102.out test103.out
SCRIPTS_GUI = test16.out
--- 30,37 ----
test84.out test85.out test86.out test87.out test88.out \
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test97.out test98.out \
! test99.out test100.out test101.out test102.out test103.out \
! test104.out
SCRIPTS_GUI = test16.out
*** /dev/null
--- b/src/testdir/test104.in
***************
*** 0 ****
--- 1,59 ----
+ Test for im/am text object
+
+ Tests every combination of the following:
+ - every non-whitespace printable ASCII character (bang/33 to tilde/126)
+ - im (i) or am (a)
+ - in-line (l) or entire-line (L)
+ - single line (s) or multiple line (S)
+
+ STARTTEST
+ :so small.vim
+ :enew
+ :
+ :" Generate lines with im/am objects in them
+ :
+ :for nr in range(33, 126)
+ : let char = nr2char(nr)
+ : let diffchar = nr2char((nr - 33 + 1) % (126 - 32) + 33)
+ : let diffchars = diffchar . diffchar . diffchar
+ : for ia in ["i", "a"]
+ : for lL in ["l", "L"]
+ : for sS in ["s", "S"]
+ : if sS == "s"
+ : let lines = diffchars
+ : else
+ : let lines = diffchars . "\<cr>" . diffchars
+ : endif
+ : execute "normal o" . char . ia . lL . sS . "X" . char . lines . char . "X\<esc>"
+ : endfor
+ : endfor
+ : endfor
+ :endfor
+ :
+ :" Apply im/am to every created object
+ :
+ :for nr in range(33, 126)
+ : let char = nr2char(nr)
+ : let diffchar = nr2char((nr - 33 + 1) % (126 - 32) + 33)
+ : let diffchars = diffchar . diffchar . diffchar
+ : for ia in ["i", "a"]
+ : for lL in ["l", "L"]
+ : for sS in ["s", "S"]
+ : execute "normal /^\\V" . escape(char,"\\") . ia . lL . sS . "\<cr>4x"
+ : if lL == "L"
+ : if sS == "s"
+ : execute "normal $x0x"
+ : else
+ : execute "normal j$xk0x"
+ : endif
+ : endif
+ : execute "normal lc" . ia . "m" . char . "OK\<esc>"
+ : endfor
+ : endfor
+ : endfor
+ :endfor
+ :
+ :w! test.out
+ :qa!
+ ENDTEST
+
*** /dev/null
--- b/src/testdir/test104.ok
***************
*** 0 ****
--- 1,753 ----
+
+ X!OK!X
+ X!OK!X
+ !OK!
+ !OK!
+ XOKX
+ XOKX
+ OK
+ OK
+ X"OK"X
+ X"OK"X
+ "OK"
+ "OK"
+ XOKX
+ XOKX
+ OK
+ OK
+ X#OK#X
+ X#OK#X
+ #OK#
+ #OK#
+ XOKX
+ XOKX
+ OK
+ OK
+ X$OK$X
+ X$OK$X
+ $OK$
+ $OK$
+ XOKX
+ XOKX
+ OK
+ OK
+ X%OK%X
+ X%OK%X
+ %OK%
+ %OK%
+ XOKX
+ XOKX
+ OK
+ OK
+ X&OK&X
+ X&OK&X
+ &OK&
+ &OK&
+ XOKX
+ XOKX
+ OK
+ OK
+ X'OK'X
+ X'OK'X
+ 'OK'
+ 'OK'
+ XOKX
+ XOKX
+ OK
+ OK
+ X(OK(X
+ X(OK(X
+ (OK(
+ (OK(
+ XOKX
+ XOKX
+ OK
+ OK
+ X)OK)X
+ X)OK)X
+ )OK)
+ )OK)
+ XOKX
+ XOKX
+ OK
+ OK
+ X*OK*X
+ X*OK*X
+ *OK*
+ *OK*
+ XOKX
+ XOKX
+ OK
+ OK
+ X+OK+X
+ X+OK+X
+ +OK+
+ +OK+
+ XOKX
+ XOKX
+ OK
+ OK
+ X,OK,X
+ X,OK,X
+ ,OK,
+ ,OK,
+ XOKX
+ XOKX
+ OK
+ OK
+ X-OK-X
+ X-OK-X
+ -OK-
+ -OK-
+ XOKX
+ XOKX
+ OK
+ OK
+ X.OK.X
+ X.OK.X
+ .OK.
+ .OK.
+ XOKX
+ XOKX
+ OK
+ OK
+ X/OK/X
+ X/OK/X
+ /OK/
+ /OK/
+ XOKX
+ XOKX
+ OK
+ OK
+ X0OK0X
+ X0OK0X
+ 0OK0
+ 0OK0
+ XOKX
+ XOKX
+ OK
+ OK
+ X1OK1X
+ X1OK1X
+ 1OK1
+ 1OK1
+ XOKX
+ XOKX
+ OK
+ OK
+ X2OK2X
+ X2OK2X
+ 2OK2
+ 2OK2
+ XOKX
+ XOKX
+ OK
+ OK
+ X3OK3X
+ X3OK3X
+ 3OK3
+ 3OK3
+ XOKX
+ XOKX
+ OK
+ OK
+ X4OK4X
+ X4OK4X
+ 4OK4
+ 4OK4
+ XOKX
+ XOKX
+ OK
+ OK
+ X5OK5X
+ X5OK5X
+ 5OK5
+ 5OK5
+ XOKX
+ XOKX
+ OK
+ OK
+ X6OK6X
+ X6OK6X
+ 6OK6
+ 6OK6
+ XOKX
+ XOKX
+ OK
+ OK
+ X7OK7X
+ X7OK7X
+ 7OK7
+ 7OK7
+ XOKX
+ XOKX
+ OK
+ OK
+ X8OK8X
+ X8OK8X
+ 8OK8
+ 8OK8
+ XOKX
+ XOKX
+ OK
+ OK
+ X9OK9X
+ X9OK9X
+ 9OK9
+ 9OK9
+ XOKX
+ XOKX
+ OK
+ OK
+ X:OK:X
+ X:OK:X
+ :OK:
+ :OK:
+ XOKX
+ XOKX
+ OK
+ OK
+ X;OK;X
+ X;OK;X
+ ;OK;
+ ;OK;
+ XOKX
+ XOKX
+ OK
+ OK
+ X<OK<X
+ X<OK<X
+ <OK<
+ <OK<
+ XOKX
+ XOKX
+ OK
+ OK
+ X=OK=X
+ X=OK=X
+ =OK=
+ =OK=
+ XOKX
+ XOKX
+ OK
+ OK
+ X>OK>X
+ X>OK>X
+ >OK>
+ >OK>
+ XOKX
+ XOKX
+ OK
+ OK
+ X?OK?X
+ X?OK?X
+ ?OK?
+ ?OK?
+ XOKX
+ XOKX
+ OK
+ OK
+ X@OK@X
+ X@OK@X
+ @OK@
+ @OK@
+ XOKX
+ XOKX
+ OK
+ OK
+ XAOKAX
+ XAOKAX
+ AOKA
+ AOKA
+ XOKX
+ XOKX
+ OK
+ OK
+ XBOKBX
+ XBOKBX
+ BOKB
+ BOKB
+ XOKX
+ XOKX
+ OK
+ OK
+ XCOKCX
+ XCOKCX
+ COKC
+ COKC
+ XOKX
+ XOKX
+ OK
+ OK
+ XDOKDX
+ XDOKDX
+ DOKD
+ DOKD
+ XOKX
+ XOKX
+ OK
+ OK
+ XEOKEX
+ XEOKEX
+ EOKE
+ EOKE
+ XOKX
+ XOKX
+ OK
+ OK
+ XFOKFX
+ XFOKFX
+ FOKF
+ FOKF
+ XOKX
+ XOKX
+ OK
+ OK
+ XGOKGX
+ XGOKGX
+ GOKG
+ GOKG
+ XOKX
+ XOKX
+ OK
+ OK
+ XHOKHX
+ XHOKHX
+ HOKH
+ HOKH
+ XOKX
+ XOKX
+ OK
+ OK
+ XIOKIX
+ XIOKIX
+ IOKI
+ IOKI
+ XOKX
+ XOKX
+ OK
+ OK
+ XJOKJX
+ XJOKJX
+ JOKJ
+ JOKJ
+ XOKX
+ XOKX
+ OK
+ OK
+ XKOKKX
+ XKOKKX
+ KOKK
+ KOKK
+ XOKX
+ XOKX
+ OK
+ OK
+ XLOKLX
+ XLOKLX
+ LOKL
+ LOKL
+ XOKX
+ XOKX
+ OK
+ OK
+ XMOKMX
+ XMOKMX
+ MOKM
+ MOKM
+ XOKX
+ XOKX
+ OK
+ OK
+ XNOKNX
+ XNOKNX
+ NOKN
+ NOKN
+ XOKX
+ XOKX
+ OK
+ OK
+ XOOKOX
+ XOOKOX
+ OOKO
+ OOKO
+ XOKX
+ XOKX
+ OK
+ OK
+ XPOKPX
+ XPOKPX
+ POKP
+ POKP
+ XOKX
+ XOKX
+ OK
+ OK
+ XQOKQX
+ XQOKQX
+ QOKQ
+ QOKQ
+ XOKX
+ XOKX
+ OK
+ OK
+ XROKRX
+ XROKRX
+ ROKR
+ ROKR
+ XOKX
+ XOKX
+ OK
+ OK
+ XSOKSX
+ XSOKSX
+ SOKS
+ SOKS
+ XOKX
+ XOKX
+ OK
+ OK
+ XTOKTX
+ XTOKTX
+ TOKT
+ TOKT
+ XOKX
+ XOKX
+ OK
+ OK
+ XUOKUX
+ XUOKUX
+ UOKU
+ UOKU
+ XOKX
+ XOKX
+ OK
+ OK
+ XVOKVX
+ XVOKVX
+ VOKV
+ VOKV
+ XOKX
+ XOKX
+ OK
+ OK
+ XWOKWX
+ XWOKWX
+ WOKW
+ WOKW
+ XOKX
+ XOKX
+ OK
+ OK
+ XXOKXX
+ XXOKXX
+ XOKX
+ XOKX
+ XOKX
+ XOKX
+ OK
+ OK
+ XYOKYX
+ XYOKYX
+ YOKY
+ YOKY
+ XOKX
+ XOKX
+ OK
+ OK
+ XZOKZX
+ XZOKZX
+ ZOKZ
+ ZOKZ
+ XOKX
+ XOKX
+ OK
+ OK
+ X[OK[X
+ X[OK[X
+ [OK[
+ [OK[
+ XOKX
+ XOKX
+ OK
+ OK
+ X\OK\X
+ X\OK\X
+ \OK\
+ \OK\
+ XOKX
+ XOKX
+ OK
+ OK
+ X]OK]X
+ X]OK]X
+ ]OK]
+ ]OK]
+ XOKX
+ XOKX
+ OK
+ OK
+ X^OK^X
+ X^OK^X
+ ^OK^
+ ^OK^
+ XOKX
+ XOKX
+ OK
+ OK
+ X_OK_X
+ X_OK_X
+ _OK_
+ _OK_
+ XOKX
+ XOKX
+ OK
+ OK
+ X`OK`X
+ X`OK`X
+ `OK`
+ `OK`
+ XOKX
+ XOKX
+ OK
+ OK
+ XaOKaX
+ XaOKaX
+ aOKa
+ aOKa
+ XOKX
+ XOKX
+ OK
+ OK
+ XbOKbX
+ XbOKbX
+ bOKb
+ bOKb
+ XOKX
+ XOKX
+ OK
+ OK
+ XcOKcX
+ XcOKcX
+ cOKc
+ cOKc
+ XOKX
+ XOKX
+ OK
+ OK
+ XdOKdX
+ XdOKdX
+ dOKd
+ dOKd
+ XOKX
+ XOKX
+ OK
+ OK
+ XeOKeX
+ XeOKeX
+ eOKe
+ eOKe
+ XOKX
+ XOKX
+ OK
+ OK
+ XfOKfX
+ XfOKfX
+ fOKf
+ fOKf
+ XOKX
+ XOKX
+ OK
+ OK
+ XgOKgX
+ XgOKgX
+ gOKg
+ gOKg
+ XOKX
+ XOKX
+ OK
+ OK
+ XhOKhX
+ XhOKhX
+ hOKh
+ hOKh
+ XOKX
+ XOKX
+ OK
+ OK
+ XiOKiX
+ XiOKiX
+ iOKi
+ iOKi
+ XOKX
+ XOKX
+ OK
+ OK
+ XjOKjX
+ XjOKjX
+ jOKj
+ jOKj
+ XOKX
+ XOKX
+ OK
+ OK
+ XkOKkX
+ XkOKkX
+ kOKk
+ kOKk
+ XOKX
+ XOKX
+ OK
+ OK
+ XlOKlX
+ XlOKlX
+ lOKl
+ lOKl
+ XOKX
+ XOKX
+ OK
+ OK
+ XmOKmX
+ XmOKmX
+ mOKm
+ mOKm
+ XOKX
+ XOKX
+ OK
+ OK
+ XnOKnX
+ XnOKnX
+ nOKn
+ nOKn
+ XOKX
+ XOKX
+ OK
+ OK
+ XoOKoX
+ XoOKoX
+ oOKo
+ oOKo
+ XOKX
+ XOKX
+ OK
+ OK
+ XpOKpX
+ XpOKpX
+ pOKp
+ pOKp
+ XOKX
+ XOKX
+ OK
+ OK
+ XqOKqX
+ XqOKqX
+ qOKq
+ qOKq
+ XOKX
+ XOKX
+ OK
+ OK
+ XrOKrX
+ XrOKrX
+ rOKr
+ rOKr
+ XOKX
+ XOKX
+ OK
+ OK
+ XsOKsX
+ XsOKsX
+ sOKs
+ sOKs
+ XOKX
+ XOKX
+ OK
+ OK
+ XtOKtX
+ XtOKtX
+ tOKt
+ tOKt
+ XOKX
+ XOKX
+ OK
+ OK
+ XuOKuX
+ XuOKuX
+ uOKu
+ uOKu
+ XOKX
+ XOKX
+ OK
+ OK
+ XvOKvX
+ XvOKvX
+ vOKv
+ vOKv
+ XOKX
+ XOKX
+ OK
+ OK
+ XwOKwX
+ XwOKwX
+ wOKw
+ wOKw
+ XOKX
+ XOKX
+ OK
+ OK
+ XxOKxX
+ XxOKxX
+ xOKx
+ xOKx
+ XOKX
+ XOKX
+ OK
+ OK
+ XyOKyX
+ XyOKyX
+ yOKy
+ yOKy
+ XOKX
+ XOKX
+ OK
+ OK
+ XzOKzX
+ XzOKzX
+ zOKz
+ zOKz
+ XOKX
+ XOKX
+ OK
+ OK
+ X{OK{X
+ X{OK{X
+ {OK{
+ {OK{
+ XOKX
+ XOKX
+ OK
+ OK
+ X|OK|X
+ X|OK|X
+ |OK|
+ |OK|
+ XOKX
+ XOKX
+ OK
+ OK
+ X}OK}X
+ X}OK}X
+ }OK}
+ }OK}
+ XOKX
+ XOKX
+ OK
+ OK
+ X~OK~X
+ X~OK~X
+ ~OK~
+ ~OK~
+ XOKX
+ XOKX
+ OK
+ OK