On Thursday, January 30, 2014 9:07:19 PM UTC-5, Daniel "paradigm" Thau wrote: > On Thursday, January 30, 2014 8:07:04 PM UTC-5, Marcin Szamotulski wrote: > > On 16:45 Wed 29 Jan , 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. > > > > > > > > Hi, > > > > > > > > Thanks I'm really happy to see this patch. I compiled it now and there > > > > is one thing that does not work: the "." command. For example di< or ci< > > > > can be repeated with . but dim, or cim, cannot. > > > > > > > > Best regards, > > > > Marcin Szamotulski > > Good catch. I can replicate that on my end. Will fix.
Should be fixed in the attachment. As a bonus, it now supports things such as digraphs. -- -- 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..710c6b4 100644 --- a/src/normal.c +++ b/src/normal.c @@ -981,7 +981,7 @@ getcount: cp = &ca.nchar; } lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG)); - +getchar: /* * Get a second or third character. */ @@ -1132,6 +1132,18 @@ getcount: } #endif } +#ifdef FEAT_TEXTOBJ + /* + * The im/am text object needs one more character to use as left/right + * bounds. + */ + if ((ca.cmdchar == 'a' || ca.cmdchar == 'i') && ca.nchar == 'm' + && ca.extra_char == NUL) + { + cp = &ca.extra_char; + goto getchar; + } +#endif --no_mapping; --allow_keys; } @@ -1526,6 +1538,16 @@ do_pending_operator(cap, old_col, gui_yank) prep_redo(oap->regname, cap->count0, get_op_char(oap->op_type), get_extra_op_char(oap->op_type), oap->motion_force, cap->cmdchar, cap->nchar); +#ifdef FEAT_TEXTOBJ + /* + * If using the am/im text object, there is one additional + * character used as left/right bounds which needs to be added to + * the redo buffer. + */ + if ((cap->cmdchar == 'a' || cap->cmdchar == 'i') + && cap->nchar == 'm' && cap->extra_char != NUL) + AppendCharToRedobuff(cap->extra_char); +#endif if (cap->cmdchar == '/' || cap->cmdchar == '?') /* was a search */ { /* @@ -9310,6 +9332,10 @@ nv_object(cap) flag = current_quote(cap->oap, cap->count1, include, cap->nchar); break; + case 'm': /* "am{char}" = a matched pair of characters */ + 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..9505517 --- /dev/null +++ b/src/testdir/test104.in @@ -0,0 +1,62 @@ +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) +- that . will properly repeat + +STARTTEST +:so small.vim +:enew +: +:" add all of the non-whitespace printable ASCII characters +:let objs = [] +::for nr in range(33,126) +:: let objs += [nr2char(nr)] +::endfor +:" spaces are characters that we aren't using as bounds +:let diffchars = " " + +:" Generate lines with im/am objects in them +:for char in objs +: 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>" +: execute "normal oX" . char . lines . char . "X\<esc>" +: endfor +: endfor +: endfor +:endfor +: +:" Apply im/am to every created object, both directly and with . +: +:for char in objs +: 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>j03l." +: 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..5e8f0ca --- /dev/null +++ b/src/testdir/test104.ok @@ -0,0 +1,1505 @@ + +X!OK!X +X!OK!X +X!OK!X +X!OK!X +!OK! +X!OK!X +!OK! +X!OK!X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X"OK"X +X"OK"X +X"OK"X +X"OK"X +"OK" +X"OK"X +"OK" +X"OK"X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X#OK#X +X#OK#X +X#OK#X +X#OK#X +#OK# +X#OK#X +#OK# +X#OK#X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X$OK$X +X$OK$X +X$OK$X +X$OK$X +$OK$ +X$OK$X +$OK$ +X$OK$X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X%OK%X +X%OK%X +X%OK%X +X%OK%X +%OK% +X%OK%X +%OK% +X%OK%X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X&OK&X +X&OK&X +X&OK&X +X&OK&X +&OK& +X&OK&X +&OK& +X&OK&X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X'OK'X +X'OK'X +X'OK'X +X'OK'X +'OK' +X'OK'X +'OK' +X'OK'X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X(OK(X +X(OK(X +X(OK(X +X(OK(X +(OK( +X(OK(X +(OK( +X(OK(X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X)OK)X +X)OK)X +X)OK)X +X)OK)X +)OK) +X)OK)X +)OK) +X)OK)X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X*OK*X +X*OK*X +X*OK*X +X*OK*X +*OK* +X*OK*X +*OK* +X*OK*X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X+OK+X +X+OK+X +X+OK+X +X+OK+X ++OK+ +X+OK+X ++OK+ +X+OK+X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X,OK,X +X,OK,X +X,OK,X +X,OK,X +,OK, +X,OK,X +,OK, +X,OK,X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X-OK-X +X-OK-X +X-OK-X +X-OK-X +-OK- +X-OK-X +-OK- +X-OK-X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X.OK.X +X.OK.X +X.OK.X +X.OK.X +.OK. +X.OK.X +.OK. +X.OK.X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X/OK/X +X/OK/X +X/OK/X +X/OK/X +/OK/ +X/OK/X +/OK/ +X/OK/X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X0OK0X +X0OK0X +X0OK0X +X0OK0X +0OK0 +X0OK0X +0OK0 +X0OK0X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X1OK1X +X1OK1X +X1OK1X +X1OK1X +1OK1 +X1OK1X +1OK1 +X1OK1X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X2OK2X +X2OK2X +X2OK2X +X2OK2X +2OK2 +X2OK2X +2OK2 +X2OK2X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X3OK3X +X3OK3X +X3OK3X +X3OK3X +3OK3 +X3OK3X +3OK3 +X3OK3X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X4OK4X +X4OK4X +X4OK4X +X4OK4X +4OK4 +X4OK4X +4OK4 +X4OK4X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X5OK5X +X5OK5X +X5OK5X +X5OK5X +5OK5 +X5OK5X +5OK5 +X5OK5X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X6OK6X +X6OK6X +X6OK6X +X6OK6X +6OK6 +X6OK6X +6OK6 +X6OK6X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X7OK7X +X7OK7X +X7OK7X +X7OK7X +7OK7 +X7OK7X +7OK7 +X7OK7X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X8OK8X +X8OK8X +X8OK8X +X8OK8X +8OK8 +X8OK8X +8OK8 +X8OK8X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X9OK9X +X9OK9X +X9OK9X +X9OK9X +9OK9 +X9OK9X +9OK9 +X9OK9X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X:OK:X +X:OK:X +X:OK:X +X:OK:X +:OK: +X:OK:X +:OK: +X:OK:X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X;OK;X +X;OK;X +X;OK;X +X;OK;X +;OK; +X;OK;X +;OK; +X;OK;X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X<OK<X +X<OK<X +X<OK<X +X<OK<X +<OK< +X<OK<X +<OK< +X<OK<X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X=OK=X +X=OK=X +X=OK=X +X=OK=X +=OK= +X=OK=X +=OK= +X=OK=X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X>OK>X +X>OK>X +X>OK>X +X>OK>X +>OK> +X>OK>X +>OK> +X>OK>X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X?OK?X +X?OK?X +X?OK?X +X?OK?X +?OK? +X?OK?X +?OK? +X?OK?X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X@OK@X +X@OK@X +X@OK@X +X@OK@X +@OK@ +X@OK@X +@OK@ +X@OK@X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XAOKAX +XAOKAX +XAOKAX +XAOKAX +AOKA +XAOKAX +AOKA +XAOKAX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XBOKBX +XBOKBX +XBOKBX +XBOKBX +BOKB +XBOKBX +BOKB +XBOKBX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XCOKCX +XCOKCX +XCOKCX +XCOKCX +COKC +XCOKCX +COKC +XCOKCX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XDOKDX +XDOKDX +XDOKDX +XDOKDX +DOKD +XDOKDX +DOKD +XDOKDX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XEOKEX +XEOKEX +XEOKEX +XEOKEX +EOKE +XEOKEX +EOKE +XEOKEX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XFOKFX +XFOKFX +XFOKFX +XFOKFX +FOKF +XFOKFX +FOKF +XFOKFX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XGOKGX +XGOKGX +XGOKGX +XGOKGX +GOKG +XGOKGX +GOKG +XGOKGX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XHOKHX +XHOKHX +XHOKHX +XHOKHX +HOKH +XHOKHX +HOKH +XHOKHX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XIOKIX +XIOKIX +XIOKIX +XIOKIX +IOKI +XIOKIX +IOKI +XIOKIX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XJOKJX +XJOKJX +XJOKJX +XJOKJX +JOKJ +XJOKJX +JOKJ +XJOKJX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XKOKKX +XKOKKX +XKOKKX +XKOKKX +KOKK +XKOKKX +KOKK +XKOKKX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XLOKLX +XLOKLX +XLOKLX +XLOKLX +LOKL +XLOKLX +LOKL +XLOKLX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XMOKMX +XMOKMX +XMOKMX +XMOKMX +MOKM +XMOKMX +MOKM +XMOKMX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XNOKNX +XNOKNX +XNOKNX +XNOKNX +NOKN +XNOKNX +NOKN +XNOKNX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XOOKOX +XOOKOX +XOOKOX +XOOKOX +OOKO +XOOKOX +OOKO +XOOKOX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XPOKPX +XPOKPX +XPOKPX +XPOKPX +POKP +XPOKPX +POKP +XPOKPX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XQOKQX +XQOKQX +XQOKQX +XQOKQX +QOKQ +XQOKQX +QOKQ +XQOKQX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XROKRX +XROKRX +XROKRX +XROKRX +ROKR +XROKRX +ROKR +XROKRX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XSOKSX +XSOKSX +XSOKSX +XSOKSX +SOKS +XSOKSX +SOKS +XSOKSX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XTOKTX +XTOKTX +XTOKTX +XTOKTX +TOKT +XTOKTX +TOKT +XTOKTX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XUOKUX +XUOKUX +XUOKUX +XUOKUX +UOKU +XUOKUX +UOKU +XUOKUX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XVOKVX +XVOKVX +XVOKVX +XVOKVX +VOKV +XVOKVX +VOKV +XVOKVX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XWOKWX +XWOKWX +XWOKWX +XWOKWX +WOKW +XWOKWX +WOKW +XWOKWX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XXOKXX +XXOKXX +XXOKXX +XXOKXX +XOKX +XXOKXX +XOKX +XXOKXX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XYOKYX +XYOKYX +XYOKYX +XYOKYX +YOKY +XYOKYX +YOKY +XYOKYX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XZOKZX +XZOKZX +XZOKZX +XZOKZX +ZOKZ +XZOKZX +ZOKZ +XZOKZX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X[OK[X +X[OK[X +X[OK[X +X[OK[X +[OK[ +X[OK[X +[OK[ +X[OK[X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X\OK\X +X\OK\X +X\OK\X +X\OK\X +\OK\ +X\OK\X +\OK\ +X\OK\X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X]OK]X +X]OK]X +X]OK]X +X]OK]X +]OK] +X]OK]X +]OK] +X]OK]X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X^OK^X +X^OK^X +X^OK^X +X^OK^X +^OK^ +X^OK^X +^OK^ +X^OK^X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X_OK_X +X_OK_X +X_OK_X +X_OK_X +_OK_ +X_OK_X +_OK_ +X_OK_X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X`OK`X +X`OK`X +X`OK`X +X`OK`X +`OK` +X`OK`X +`OK` +X`OK`X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XaOKaX +XaOKaX +XaOKaX +XaOKaX +aOKa +XaOKaX +aOKa +XaOKaX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XbOKbX +XbOKbX +XbOKbX +XbOKbX +bOKb +XbOKbX +bOKb +XbOKbX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XcOKcX +XcOKcX +XcOKcX +XcOKcX +cOKc +XcOKcX +cOKc +XcOKcX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XdOKdX +XdOKdX +XdOKdX +XdOKdX +dOKd +XdOKdX +dOKd +XdOKdX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XeOKeX +XeOKeX +XeOKeX +XeOKeX +eOKe +XeOKeX +eOKe +XeOKeX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XfOKfX +XfOKfX +XfOKfX +XfOKfX +fOKf +XfOKfX +fOKf +XfOKfX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XgOKgX +XgOKgX +XgOKgX +XgOKgX +gOKg +XgOKgX +gOKg +XgOKgX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XhOKhX +XhOKhX +XhOKhX +XhOKhX +hOKh +XhOKhX +hOKh +XhOKhX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XiOKiX +XiOKiX +XiOKiX +XiOKiX +iOKi +XiOKiX +iOKi +XiOKiX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XjOKjX +XjOKjX +XjOKjX +XjOKjX +jOKj +XjOKjX +jOKj +XjOKjX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XkOKkX +XkOKkX +XkOKkX +XkOKkX +kOKk +XkOKkX +kOKk +XkOKkX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XlOKlX +XlOKlX +XlOKlX +XlOKlX +lOKl +XlOKlX +lOKl +XlOKlX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XmOKmX +XmOKmX +XmOKmX +XmOKmX +mOKm +XmOKmX +mOKm +XmOKmX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XnOKnX +XnOKnX +XnOKnX +XnOKnX +nOKn +XnOKnX +nOKn +XnOKnX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XoOKoX +XoOKoX +XoOKoX +XoOKoX +oOKo +XoOKoX +oOKo +XoOKoX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XpOKpX +XpOKpX +XpOKpX +XpOKpX +pOKp +XpOKpX +pOKp +XpOKpX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XqOKqX +XqOKqX +XqOKqX +XqOKqX +qOKq +XqOKqX +qOKq +XqOKqX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XrOKrX +XrOKrX +XrOKrX +XrOKrX +rOKr +XrOKrX +rOKr +XrOKrX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XsOKsX +XsOKsX +XsOKsX +XsOKsX +sOKs +XsOKsX +sOKs +XsOKsX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XtOKtX +XtOKtX +XtOKtX +XtOKtX +tOKt +XtOKtX +tOKt +XtOKtX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XuOKuX +XuOKuX +XuOKuX +XuOKuX +uOKu +XuOKuX +uOKu +XuOKuX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XvOKvX +XvOKvX +XvOKvX +XvOKvX +vOKv +XvOKvX +vOKv +XvOKvX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XwOKwX +XwOKwX +XwOKwX +XwOKwX +wOKw +XwOKwX +wOKw +XwOKwX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XxOKxX +XxOKxX +XxOKxX +XxOKxX +xOKx +XxOKxX +xOKx +XxOKxX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XyOKyX +XyOKyX +XyOKyX +XyOKyX +yOKy +XyOKyX +yOKy +XyOKyX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +XzOKzX +XzOKzX +XzOKzX +XzOKzX +zOKz +XzOKzX +zOKz +XzOKzX +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X{OK{X +X{OK{X +X{OK{X +X{OK{X +{OK{ +X{OK{X +{OK{ +X{OK{X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X|OK|X +X|OK|X +X|OK|X +X|OK|X +|OK| +X|OK|X +|OK| +X|OK|X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X}OK}X +X}OK}X +X}OK}X +X}OK}X +}OK} +X}OK}X +}OK} +X}OK}X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX +X~OK~X +X~OK~X +X~OK~X +X~OK~X +~OK~ +X~OK~X +~OK~ +X~OK~X +XOKX +XOKX +XOKX +XOKX +OK +XOKX +OK +XOKX
*** 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 *************** *** 981,987 **** getcount: cp = &ca.nchar; } lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG)); ! /* * Get a second or third character. */ --- 981,987 ---- cp = &ca.nchar; } lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG)); ! getchar: /* * Get a second or third character. */ *************** *** 1132,1137 **** getcount: --- 1132,1149 ---- } #endif } + #ifdef FEAT_TEXTOBJ + /* + * The im/am text object needs one more character to use as left/right + * bounds. + */ + if ((ca.cmdchar == 'a' || ca.cmdchar == 'i') && ca.nchar == 'm' + && ca.extra_char == NUL) + { + cp = &ca.extra_char; + goto getchar; + } + #endif --no_mapping; --allow_keys; } *************** *** 1526,1531 **** do_pending_operator(cap, old_col, gui_yank) --- 1538,1553 ---- prep_redo(oap->regname, cap->count0, get_op_char(oap->op_type), get_extra_op_char(oap->op_type), oap->motion_force, cap->cmdchar, cap->nchar); + #ifdef FEAT_TEXTOBJ + /* + * If using the am/im text object, there is one additional + * character used as left/right bounds which needs to be added to + * the redo buffer. + */ + if ((cap->cmdchar == 'a' || cap->cmdchar == 'i') + && cap->nchar == 'm' && cap->extra_char != NUL) + AppendCharToRedobuff(cap->extra_char); + #endif if (cap->cmdchar == '/' || cap->cmdchar == '?') /* was a search */ { /* *************** *** 9310,9315 **** nv_object(cap) --- 9332,9341 ---- flag = current_quote(cap->oap, cap->count1, include, cap->nchar); break; + case 'm': /* "am{char}" = a matched pair of characters */ + 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,62 ---- + 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) + - that . will properly repeat + + STARTTEST + :so small.vim + :enew + : + :" add all of the non-whitespace printable ASCII characters + :let objs = [] + ::for nr in range(33,126) + :: let objs += [nr2char(nr)] + ::endfor + :" spaces are characters that we aren't using as bounds + :let diffchars = " " + + :" Generate lines with im/am objects in them + :for char in objs + : 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>" + : execute "normal oX" . char . lines . char . "X\<esc>" + : endfor + : endfor + : endfor + :endfor + : + :" Apply im/am to every created object, both directly and with . + : + :for char in objs + : 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>j03l." + : endfor + : endfor + : endfor + :endfor + : + :w! test.out + :qa! + ENDTEST + *** /dev/null --- b/src/testdir/test104.ok *************** *** 0 **** --- 1,1505 ---- + + X!OK!X + X!OK!X + X!OK!X + X!OK!X + !OK! + X!OK!X + !OK! + X!OK!X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X"OK"X + X"OK"X + X"OK"X + X"OK"X + "OK" + X"OK"X + "OK" + X"OK"X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X#OK#X + X#OK#X + X#OK#X + X#OK#X + #OK# + X#OK#X + #OK# + X#OK#X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X$OK$X + X$OK$X + X$OK$X + X$OK$X + $OK$ + X$OK$X + $OK$ + X$OK$X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X%OK%X + X%OK%X + X%OK%X + X%OK%X + %OK% + X%OK%X + %OK% + X%OK%X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X&OK&X + X&OK&X + X&OK&X + X&OK&X + &OK& + X&OK&X + &OK& + X&OK&X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X'OK'X + X'OK'X + X'OK'X + X'OK'X + 'OK' + X'OK'X + 'OK' + X'OK'X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X(OK(X + X(OK(X + X(OK(X + X(OK(X + (OK( + X(OK(X + (OK( + X(OK(X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X)OK)X + X)OK)X + X)OK)X + X)OK)X + )OK) + X)OK)X + )OK) + X)OK)X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X*OK*X + X*OK*X + X*OK*X + X*OK*X + *OK* + X*OK*X + *OK* + X*OK*X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X+OK+X + X+OK+X + X+OK+X + X+OK+X + +OK+ + X+OK+X + +OK+ + X+OK+X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X,OK,X + X,OK,X + X,OK,X + X,OK,X + ,OK, + X,OK,X + ,OK, + X,OK,X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X-OK-X + X-OK-X + X-OK-X + X-OK-X + -OK- + X-OK-X + -OK- + X-OK-X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X.OK.X + X.OK.X + X.OK.X + X.OK.X + .OK. + X.OK.X + .OK. + X.OK.X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X/OK/X + X/OK/X + X/OK/X + X/OK/X + /OK/ + X/OK/X + /OK/ + X/OK/X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X0OK0X + X0OK0X + X0OK0X + X0OK0X + 0OK0 + X0OK0X + 0OK0 + X0OK0X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X1OK1X + X1OK1X + X1OK1X + X1OK1X + 1OK1 + X1OK1X + 1OK1 + X1OK1X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X2OK2X + X2OK2X + X2OK2X + X2OK2X + 2OK2 + X2OK2X + 2OK2 + X2OK2X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X3OK3X + X3OK3X + X3OK3X + X3OK3X + 3OK3 + X3OK3X + 3OK3 + X3OK3X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X4OK4X + X4OK4X + X4OK4X + X4OK4X + 4OK4 + X4OK4X + 4OK4 + X4OK4X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X5OK5X + X5OK5X + X5OK5X + X5OK5X + 5OK5 + X5OK5X + 5OK5 + X5OK5X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X6OK6X + X6OK6X + X6OK6X + X6OK6X + 6OK6 + X6OK6X + 6OK6 + X6OK6X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X7OK7X + X7OK7X + X7OK7X + X7OK7X + 7OK7 + X7OK7X + 7OK7 + X7OK7X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X8OK8X + X8OK8X + X8OK8X + X8OK8X + 8OK8 + X8OK8X + 8OK8 + X8OK8X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X9OK9X + X9OK9X + X9OK9X + X9OK9X + 9OK9 + X9OK9X + 9OK9 + X9OK9X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X:OK:X + X:OK:X + X:OK:X + X:OK:X + :OK: + X:OK:X + :OK: + X:OK:X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X;OK;X + X;OK;X + X;OK;X + X;OK;X + ;OK; + X;OK;X + ;OK; + X;OK;X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X<OK<X + X<OK<X + X<OK<X + X<OK<X + <OK< + X<OK<X + <OK< + X<OK<X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X=OK=X + X=OK=X + X=OK=X + X=OK=X + =OK= + X=OK=X + =OK= + X=OK=X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X>OK>X + X>OK>X + X>OK>X + X>OK>X + >OK> + X>OK>X + >OK> + X>OK>X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X?OK?X + X?OK?X + X?OK?X + X?OK?X + ?OK? + X?OK?X + ?OK? + X?OK?X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X@OK@X + X@OK@X + X@OK@X + X@OK@X + @OK@ + X@OK@X + @OK@ + X@OK@X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XAOKAX + XAOKAX + XAOKAX + XAOKAX + AOKA + XAOKAX + AOKA + XAOKAX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XBOKBX + XBOKBX + XBOKBX + XBOKBX + BOKB + XBOKBX + BOKB + XBOKBX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XCOKCX + XCOKCX + XCOKCX + XCOKCX + COKC + XCOKCX + COKC + XCOKCX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XDOKDX + XDOKDX + XDOKDX + XDOKDX + DOKD + XDOKDX + DOKD + XDOKDX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XEOKEX + XEOKEX + XEOKEX + XEOKEX + EOKE + XEOKEX + EOKE + XEOKEX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XFOKFX + XFOKFX + XFOKFX + XFOKFX + FOKF + XFOKFX + FOKF + XFOKFX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XGOKGX + XGOKGX + XGOKGX + XGOKGX + GOKG + XGOKGX + GOKG + XGOKGX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XHOKHX + XHOKHX + XHOKHX + XHOKHX + HOKH + XHOKHX + HOKH + XHOKHX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XIOKIX + XIOKIX + XIOKIX + XIOKIX + IOKI + XIOKIX + IOKI + XIOKIX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XJOKJX + XJOKJX + XJOKJX + XJOKJX + JOKJ + XJOKJX + JOKJ + XJOKJX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XKOKKX + XKOKKX + XKOKKX + XKOKKX + KOKK + XKOKKX + KOKK + XKOKKX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XLOKLX + XLOKLX + XLOKLX + XLOKLX + LOKL + XLOKLX + LOKL + XLOKLX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XMOKMX + XMOKMX + XMOKMX + XMOKMX + MOKM + XMOKMX + MOKM + XMOKMX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XNOKNX + XNOKNX + XNOKNX + XNOKNX + NOKN + XNOKNX + NOKN + XNOKNX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XOOKOX + XOOKOX + XOOKOX + XOOKOX + OOKO + XOOKOX + OOKO + XOOKOX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XPOKPX + XPOKPX + XPOKPX + XPOKPX + POKP + XPOKPX + POKP + XPOKPX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XQOKQX + XQOKQX + XQOKQX + XQOKQX + QOKQ + XQOKQX + QOKQ + XQOKQX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XROKRX + XROKRX + XROKRX + XROKRX + ROKR + XROKRX + ROKR + XROKRX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XSOKSX + XSOKSX + XSOKSX + XSOKSX + SOKS + XSOKSX + SOKS + XSOKSX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XTOKTX + XTOKTX + XTOKTX + XTOKTX + TOKT + XTOKTX + TOKT + XTOKTX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XUOKUX + XUOKUX + XUOKUX + XUOKUX + UOKU + XUOKUX + UOKU + XUOKUX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XVOKVX + XVOKVX + XVOKVX + XVOKVX + VOKV + XVOKVX + VOKV + XVOKVX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XWOKWX + XWOKWX + XWOKWX + XWOKWX + WOKW + XWOKWX + WOKW + XWOKWX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XXOKXX + XXOKXX + XXOKXX + XXOKXX + XOKX + XXOKXX + XOKX + XXOKXX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XYOKYX + XYOKYX + XYOKYX + XYOKYX + YOKY + XYOKYX + YOKY + XYOKYX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XZOKZX + XZOKZX + XZOKZX + XZOKZX + ZOKZ + XZOKZX + ZOKZ + XZOKZX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X[OK[X + X[OK[X + X[OK[X + X[OK[X + [OK[ + X[OK[X + [OK[ + X[OK[X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X\OK\X + X\OK\X + X\OK\X + X\OK\X + \OK\ + X\OK\X + \OK\ + X\OK\X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X]OK]X + X]OK]X + X]OK]X + X]OK]X + ]OK] + X]OK]X + ]OK] + X]OK]X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X^OK^X + X^OK^X + X^OK^X + X^OK^X + ^OK^ + X^OK^X + ^OK^ + X^OK^X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X_OK_X + X_OK_X + X_OK_X + X_OK_X + _OK_ + X_OK_X + _OK_ + X_OK_X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X`OK`X + X`OK`X + X`OK`X + X`OK`X + `OK` + X`OK`X + `OK` + X`OK`X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XaOKaX + XaOKaX + XaOKaX + XaOKaX + aOKa + XaOKaX + aOKa + XaOKaX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XbOKbX + XbOKbX + XbOKbX + XbOKbX + bOKb + XbOKbX + bOKb + XbOKbX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XcOKcX + XcOKcX + XcOKcX + XcOKcX + cOKc + XcOKcX + cOKc + XcOKcX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XdOKdX + XdOKdX + XdOKdX + XdOKdX + dOKd + XdOKdX + dOKd + XdOKdX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XeOKeX + XeOKeX + XeOKeX + XeOKeX + eOKe + XeOKeX + eOKe + XeOKeX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XfOKfX + XfOKfX + XfOKfX + XfOKfX + fOKf + XfOKfX + fOKf + XfOKfX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XgOKgX + XgOKgX + XgOKgX + XgOKgX + gOKg + XgOKgX + gOKg + XgOKgX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XhOKhX + XhOKhX + XhOKhX + XhOKhX + hOKh + XhOKhX + hOKh + XhOKhX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XiOKiX + XiOKiX + XiOKiX + XiOKiX + iOKi + XiOKiX + iOKi + XiOKiX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XjOKjX + XjOKjX + XjOKjX + XjOKjX + jOKj + XjOKjX + jOKj + XjOKjX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XkOKkX + XkOKkX + XkOKkX + XkOKkX + kOKk + XkOKkX + kOKk + XkOKkX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XlOKlX + XlOKlX + XlOKlX + XlOKlX + lOKl + XlOKlX + lOKl + XlOKlX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XmOKmX + XmOKmX + XmOKmX + XmOKmX + mOKm + XmOKmX + mOKm + XmOKmX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XnOKnX + XnOKnX + XnOKnX + XnOKnX + nOKn + XnOKnX + nOKn + XnOKnX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XoOKoX + XoOKoX + XoOKoX + XoOKoX + oOKo + XoOKoX + oOKo + XoOKoX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XpOKpX + XpOKpX + XpOKpX + XpOKpX + pOKp + XpOKpX + pOKp + XpOKpX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XqOKqX + XqOKqX + XqOKqX + XqOKqX + qOKq + XqOKqX + qOKq + XqOKqX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XrOKrX + XrOKrX + XrOKrX + XrOKrX + rOKr + XrOKrX + rOKr + XrOKrX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XsOKsX + XsOKsX + XsOKsX + XsOKsX + sOKs + XsOKsX + sOKs + XsOKsX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XtOKtX + XtOKtX + XtOKtX + XtOKtX + tOKt + XtOKtX + tOKt + XtOKtX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XuOKuX + XuOKuX + XuOKuX + XuOKuX + uOKu + XuOKuX + uOKu + XuOKuX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XvOKvX + XvOKvX + XvOKvX + XvOKvX + vOKv + XvOKvX + vOKv + XvOKvX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XwOKwX + XwOKwX + XwOKwX + XwOKwX + wOKw + XwOKwX + wOKw + XwOKwX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XxOKxX + XxOKxX + XxOKxX + XxOKxX + xOKx + XxOKxX + xOKx + XxOKxX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XyOKyX + XyOKyX + XyOKyX + XyOKyX + yOKy + XyOKyX + yOKy + XyOKyX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + XzOKzX + XzOKzX + XzOKzX + XzOKzX + zOKz + XzOKzX + zOKz + XzOKzX + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X{OK{X + X{OK{X + X{OK{X + X{OK{X + {OK{ + X{OK{X + {OK{ + X{OK{X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X|OK|X + X|OK|X + X|OK|X + X|OK|X + |OK| + X|OK|X + |OK| + X|OK|X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X}OK}X + X}OK}X + X}OK}X + X}OK}X + }OK} + X}OK}X + }OK} + X}OK}X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX + X~OK~X + X~OK~X + X~OK~X + X~OK~X + ~OK~ + X~OK~X + ~OK~ + X~OK~X + XOKX + XOKX + XOKX + XOKX + OK + XOKX + OK + XOKX