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 vim_dev+unsubscr...@googlegroups.com. 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