diff options
Diffstat (limited to 'src/search.c')
-rw-r--r-- | src/search.c | 1951 |
1 files changed, 0 insertions, 1951 deletions
diff --git a/src/search.c b/src/search.c index 8c335ffd3a..0bf49629eb 100644 --- a/src/search.c +++ b/src/search.c @@ -17,8 +17,6 @@ static void set_vv_searchforward(void); static int first_submatch(regmmatch_T *rp); #endif static int check_linecomment(char_u *line); -static int cls(void); -static int skip_chars(int, int); #ifdef FEAT_FIND_ID static void show_pat_in_path(char_u *, int, int, int, FILE *, linenr_T *, long); @@ -2838,1955 +2836,6 @@ showmatch( } /* - * Find the start of the next sentence, searching in the direction specified - * by the "dir" argument. The cursor is positioned on the start of the next - * sentence when found. If the next sentence is found, return OK. Return FAIL - * otherwise. See ":h sentence" for the precise definition of a "sentence" - * text object. - */ - int -findsent(int dir, long count) -{ - pos_T pos, tpos; - int c; - int (*func)(pos_T *); - int startlnum; - int noskip = FALSE; // do not skip blanks - int cpo_J; - int found_dot; - - pos = curwin->w_cursor; - if (dir == FORWARD) - func = incl; - else - func = decl; - - while (count--) - { - /* - * if on an empty line, skip up to a non-empty line - */ - if (gchar_pos(&pos) == NUL) - { - do - if ((*func)(&pos) == -1) - break; - while (gchar_pos(&pos) == NUL); - if (dir == FORWARD) - goto found; - } - /* - * if on the start of a paragraph or a section and searching forward, - * go to the next line - */ - else if (dir == FORWARD && pos.col == 0 && - startPS(pos.lnum, NUL, FALSE)) - { - if (pos.lnum == curbuf->b_ml.ml_line_count) - return FAIL; - ++pos.lnum; - goto found; - } - else if (dir == BACKWARD) - decl(&pos); - - // go back to the previous non-white non-punctuation character - found_dot = FALSE; - while (c = gchar_pos(&pos), VIM_ISWHITE(c) - || vim_strchr((char_u *)".!?)]\"'", c) != NULL) - { - tpos = pos; - if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD)) - break; - - if (found_dot) - break; - if (vim_strchr((char_u *) ".!?", c) != NULL) - found_dot = TRUE; - - if (vim_strchr((char_u *) ")]\"'", c) != NULL - && vim_strchr((char_u *) ".!?)]\"'", gchar_pos(&tpos)) == NULL) - break; - - decl(&pos); - } - - // remember the line where the search started - startlnum = pos.lnum; - cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL; - - for (;;) // find end of sentence - { - c = gchar_pos(&pos); - if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE))) - { - if (dir == BACKWARD && pos.lnum != startlnum) - ++pos.lnum; - break; - } - if (c == '.' || c == '!' || c == '?') - { - tpos = pos; - do - if ((c = inc(&tpos)) == -1) - break; - while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos)) - != NULL); - if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL - || (cpo_J && (c == ' ' && inc(&tpos) >= 0 - && gchar_pos(&tpos) == ' '))) - { - pos = tpos; - if (gchar_pos(&pos) == NUL) // skip NUL at EOL - inc(&pos); - break; - } - } - if ((*func)(&pos) == -1) - { - if (count) - return FAIL; - noskip = TRUE; - break; - } - } -found: - // skip white space - while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t')) - if (incl(&pos) == -1) - break; - } - - setpcmark(); - curwin->w_cursor = pos; - return OK; -} - -/* - * Find the next paragraph or section in direction 'dir'. - * Paragraphs are currently supposed to be separated by empty lines. - * If 'what' is NUL we go to the next paragraph. - * If 'what' is '{' or '}' we go to the next section. - * If 'both' is TRUE also stop at '}'. - * Return TRUE if the next paragraph or section was found. - */ - int -findpar( - int *pincl, // Return: TRUE if last char is to be included - int dir, - long count, - int what, - int both) -{ - linenr_T curr; - int did_skip; // TRUE after separating lines have been skipped - int first; // TRUE on first line - int posix = (vim_strchr(p_cpo, CPO_PARA) != NULL); -#ifdef FEAT_FOLDING - linenr_T fold_first; // first line of a closed fold - linenr_T fold_last; // last line of a closed fold - int fold_skipped; // TRUE if a closed fold was skipped this - // iteration -#endif - - curr = curwin->w_cursor.lnum; - - while (count--) - { - did_skip = FALSE; - for (first = TRUE; ; first = FALSE) - { - if (*ml_get(curr) != NUL) - did_skip = TRUE; - -#ifdef FEAT_FOLDING - // skip folded lines - fold_skipped = FALSE; - if (first && hasFolding(curr, &fold_first, &fold_last)) - { - curr = ((dir > 0) ? fold_last : fold_first) + dir; - fold_skipped = TRUE; - } -#endif - - // POSIX has its own ideas of what a paragraph boundary is and it - // doesn't match historical Vi: It also stops at a "{" in the - // first column and at an empty line. - if (!first && did_skip && (startPS(curr, what, both) - || (posix && what == NUL && *ml_get(curr) == '{'))) - break; - -#ifdef FEAT_FOLDING - if (fold_skipped) - curr -= dir; -#endif - if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count) - { - if (count) - return FALSE; - curr -= dir; - break; - } - } - } - setpcmark(); - if (both && *ml_get(curr) == '}') // include line with '}' - ++curr; - curwin->w_cursor.lnum = curr; - if (curr == curbuf->b_ml.ml_line_count && what != '}') - { - char_u *line = ml_get(curr); - - // Put the cursor on the last character in the last line and make the - // motion inclusive. - if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0) - { - --curwin->w_cursor.col; - curwin->w_cursor.col -= - (*mb_head_off)(line, line + curwin->w_cursor.col); - *pincl = TRUE; - } - } - else - curwin->w_cursor.col = 0; - return TRUE; -} - -/* - * check if the string 's' is a nroff macro that is in option 'opt' - */ - static int -inmacro(char_u *opt, char_u *s) -{ - char_u *macro; - - for (macro = opt; macro[0]; ++macro) - { - // Accept two characters in the option being equal to two characters - // in the line. A space in the option matches with a space in the - // line or the line having ended. - if ( (macro[0] == s[0] - || (macro[0] == ' ' - && (s[0] == NUL || s[0] == ' '))) - && (macro[1] == s[1] - || ((macro[1] == NUL || macro[1] == ' ') - && (s[0] == NUL || s[1] == NUL || s[1] == ' ')))) - break; - ++macro; - if (macro[0] == NUL) - break; - } - return (macro[0] != NUL); -} - -/* - * startPS: return TRUE if line 'lnum' is the start of a section or paragraph. - * If 'para' is '{' or '}' only check for sections. - * If 'both' is TRUE also stop at '}' - */ - int -startPS(linenr_T lnum, int para, int both) -{ - char_u *s; - - s = ml_get(lnum); - if (*s == para || *s == '\f' || (both && *s == '}')) - return TRUE; - if (*s == '.' && (inmacro(p_sections, s + 1) || - (!para && inmacro(p_para, s + 1)))) - return TRUE; - return FALSE; -} - -/* - * The following routines do the word searches performed by the 'w', 'W', - * 'b', 'B', 'e', and 'E' commands. - */ - -/* - * To perform these searches, characters are placed into one of three - * classes, and transitions between classes determine word boundaries. - * - * The classes are: - * - * 0 - white space - * 1 - punctuation - * 2 or higher - keyword characters (letters, digits and underscore) - */ - -static int cls_bigword; // TRUE for "W", "B" or "E" - -/* - * cls() - returns the class of character at curwin->w_cursor - * - * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars - * from class 2 and higher are reported as class 1 since only white space - * boundaries are of interest. - */ - static int -cls(void) -{ - int c; - - c = gchar_cursor(); - if (c == ' ' || c == '\t' || c == NUL) - return 0; - if (enc_dbcs != 0 && c > 0xFF) - { - // If cls_bigword, report multi-byte chars as class 1. - if (enc_dbcs == DBCS_KOR && cls_bigword) - return 1; - - // process code leading/trailing bytes - return dbcs_class(((unsigned)c >> 8), (c & 0xFF)); - } - if (enc_utf8) - { - c = utf_class(c); - if (c != 0 && cls_bigword) - return 1; - return c; - } - - // If cls_bigword is TRUE, report all non-blanks as class 1. - if (cls_bigword) - return 1; - - if (vim_iswordc(c)) - return 2; - return 1; -} - - -/* - * fwd_word(count, type, eol) - move forward one word - * - * Returns FAIL if the cursor was already at the end of the file. - * If eol is TRUE, last word stops at end of line (for operators). - */ - int -fwd_word( - long count, - int bigword, // "W", "E" or "B" - int eol) -{ - int sclass; // starting class - int i; - int last_line; - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) - { -#ifdef FEAT_FOLDING - // When inside a range of folded lines, move to the last char of the - // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) - coladvance((colnr_T)MAXCOL); -#endif - sclass = cls(); - - /* - * We always move at least one character, unless on the last - * character in the buffer. - */ - last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count); - i = inc_cursor(); - if (i == -1 || (i >= 1 && last_line)) // started at last char in file - return FAIL; - if (i >= 1 && eol && count == 0) // started at last char in line - return OK; - - /* - * Go one char past end of current word (if any) - */ - if (sclass != 0) - while (cls() == sclass) - { - i = inc_cursor(); - if (i == -1 || (i >= 1 && eol && count == 0)) - return OK; - } - - /* - * go to next non-white - */ - while (cls() == 0) - { - /* - * We'll stop if we land on a blank line - */ - if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL) - break; - - i = inc_cursor(); - if (i == -1 || (i >= 1 && eol && count == 0)) - return OK; - } - } - return OK; -} - -/* - * bck_word() - move backward 'count' words - * - * If stop is TRUE and we are already on the start of a word, move one less. - * - * Returns FAIL if top of the file was reached. - */ - int -bck_word(long count, int bigword, int stop) -{ - int sclass; // starting class - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) - { -#ifdef FEAT_FOLDING - // When inside a range of folded lines, move to the first char of the - // first line. - if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) - curwin->w_cursor.col = 0; -#endif - sclass = cls(); - if (dec_cursor() == -1) // started at start of file - return FAIL; - - if (!stop || sclass == cls() || sclass == 0) - { - /* - * Skip white space before the word. - * Stop on an empty line. - */ - while (cls() == 0) - { - if (curwin->w_cursor.col == 0 - && LINEEMPTY(curwin->w_cursor.lnum)) - goto finished; - if (dec_cursor() == -1) // hit start of file, stop here - return OK; - } - - /* - * Move backward to start of this word. - */ - if (skip_chars(cls(), BACKWARD)) - return OK; - } - - inc_cursor(); // overshot - forward one -finished: - stop = FALSE; - } - return OK; -} - -/* - * end_word() - move to the end of the word - * - * There is an apparent bug in the 'e' motion of the real vi. At least on the - * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e' - * motion crosses blank lines. When the real vi crosses a blank line in an - * 'e' motion, the cursor is placed on the FIRST character of the next - * non-blank line. The 'E' command, however, works correctly. Since this - * appears to be a bug, I have not duplicated it here. - * - * Returns FAIL if end of the file was reached. - * - * If stop is TRUE and we are already on the end of a word, move one less. - * If empty is TRUE stop on an empty line. - */ - int -end_word( - long count, - int bigword, - int stop, - int empty) -{ - int sclass; // starting class - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) - { -#ifdef FEAT_FOLDING - // When inside a range of folded lines, move to the last char of the - // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) - coladvance((colnr_T)MAXCOL); -#endif - sclass = cls(); - if (inc_cursor() == -1) - return FAIL; - - /* - * If we're in the middle of a word, we just have to move to the end - * of it. - */ - if (cls() == sclass && sclass != 0) - { - /* - * Move forward to end of the current word - */ - if (skip_chars(sclass, FORWARD)) - return FAIL; - } - else if (!stop || sclass == 0) - { - /* - * We were at the end of a word. Go to the end of the next word. - * First skip white space, if 'empty' is TRUE, stop at empty line. - */ - while (cls() == 0) - { - if (empty && curwin->w_cursor.col == 0 - && LINEEMPTY(curwin->w_cursor.lnum)) - goto finished; - if (inc_cursor() == -1) // hit end of file, stop here - return FAIL; - } - - /* - * Move forward to the end of this word. - */ - if (skip_chars(cls(), FORWARD)) - return FAIL; - } - dec_cursor(); // overshot - one char backward -finished: - stop = FALSE; // we move only one word less - } - return OK; -} - -/* - * Move back to the end of the word. - * - * Returns FAIL if start of the file was reached. - */ - int -bckend_word( - long count, - int bigword, // TRUE for "B" - int eol) // TRUE: stop at end of line. -{ - int sclass; // starting class - int i; - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) - { - sclass = cls(); - if ((i = dec_cursor()) == -1) - return FAIL; - if (eol && i == 1) - return OK; - - /* - * Move backward to before the start of this word. - */ - if (sclass != 0) - { - while (cls() == sclass) - if ((i = dec_cursor()) == -1 || (eol && i == 1)) - return OK; - } - - /* - * Move backward to end of the previous word - */ - while (cls() == 0) - { - if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum)) - break; - if ((i = dec_cursor()) == -1 || (eol && i == 1)) - return OK; - } - } - return OK; -} - -/* - * Skip a row of characters of the same class. - * Return TRUE when end-of-file reached, FALSE otherwise. - */ - static int -skip_chars(int cclass, int dir) -{ - while (cls() == cclass) - if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) - return TRUE; - return FALSE; -} - -#ifdef FEAT_TEXTOBJ -/* - * Go back to the start of the word or the start of white space - */ - static void -back_in_line(void) -{ - int sclass; // starting class - - sclass = cls(); - for (;;) - { - if (curwin->w_cursor.col == 0) // stop at start of line - break; - dec_cursor(); - if (cls() != sclass) // stop at start of word - { - inc_cursor(); - break; - } - } -} - - static void -find_first_blank(pos_T *posp) -{ - int c; - - while (decl(posp) != -1) - { - c = gchar_pos(posp); - if (!VIM_ISWHITE(c)) - { - incl(posp); - break; - } - } -} - -/* - * Skip count/2 sentences and count/2 separating white spaces. - */ - static void -findsent_forward( - long count, - int at_start_sent) // cursor is at start of sentence -{ - while (count--) - { - findsent(FORWARD, 1L); - if (at_start_sent) - find_first_blank(&curwin->w_cursor); - if (count == 0 || at_start_sent) - decl(&curwin->w_cursor); - at_start_sent = !at_start_sent; - } -} - -/* - * Find word under cursor, cursor at end. - * Used while an operator is pending, and in Visual mode. - */ - int -current_word( - oparg_T *oap, - long count, - int include, // TRUE: include word and white space - int bigword) // FALSE == word, TRUE == WORD -{ - pos_T start_pos; - pos_T pos; - int inclusive = TRUE; - int include_white = FALSE; - - cls_bigword = bigword; - CLEAR_POS(&start_pos); - - // Correct cursor when 'selection' is exclusive - if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor)) - dec_cursor(); - - /* - * When Visual mode is not active, or when the VIsual area is only one - * character, select the word and/or white space under the cursor. - */ - if (!VIsual_active || EQUAL_POS(curwin->w_cursor, VIsual)) - { - /* - * Go to start of current word or white space. - */ - back_in_line(); - start_pos = curwin->w_cursor; - - /* - * If the start is on white space, and white space should be included - * (" word"), or start is not on white space, and white space should - * not be included ("word"), find end of word. - */ - if ((cls() == 0) == include) - { - if (end_word(1L, bigword, TRUE, TRUE) == FAIL) - return FAIL; - } - else - { - /* - * If the start is not on white space, and white space should be - * included ("word "), or start is on white space and white - * space should not be included (" "), find start of word. - * If we end up in the first column of the next line (single char - * word) back up to end of the line. - */ - fwd_word(1L, bigword, TRUE); - if (curwin->w_cursor.col == 0) - decl(&curwin->w_cursor); - else - oneleft(); - - if (include) - include_white = TRUE; - } - - if (VIsual_active) - { - // should do something when inclusive == FALSE ! - VIsual = start_pos; - redraw_curbuf_later(INVERTED); // update the inversion - } - else - { - oap->start = start_pos; - oap->motion_type = MCHAR; - } - --count; - } - - /* - * When count is still > 0, extend with more objects. - */ - while (count > 0) - { - inclusive = TRUE; - if (VIsual_active && LT_POS(curwin->w_cursor, VIsual)) - { - /* - * In Visual mode, with cursor at start: move cursor back. - */ - if (decl(&curwin->w_cursor) == -1) - return FAIL; - if (include != (cls() != 0)) - { - if (bck_word(1L, bigword, TRUE) == FAIL) - return FAIL; - } - else - { - if (bckend_word(1L, bigword, TRUE) == FAIL) - return FAIL; - (void)incl(&curwin->w_cursor); - } - } - else - { - /* - * Move cursor forward one word and/or white area. - */ - if (incl(&curwin->w_cursor) == -1) - return FAIL; - if (include != (cls() == 0)) - { - if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1) - return FAIL; - /* - * If end is just past a new-line, we don't want to include - * the first character on the line. - * Put cursor on last char of white. - */ - if (oneleft() == FAIL) - inclusive = FALSE; - } - else - { - if (end_word(1L, bigword, TRUE, TRUE) == FAIL) - return FAIL; - } - } - --count; - } - - if (include_white && (cls() != 0 - || (curwin->w_cursor.col == 0 && !inclusive))) - { - /* - * If we don't include white space at the end, move the start - * to include some white space there. This makes "daw" work - * better on the last word in a sentence (and "2daw" on last-but-one - * word). Also when "2daw" deletes "word." at the end of the line - * (cursor is at start of next line). - * But don't delete white space at start of line (indent). - */ - pos = curwin->w_cursor; // save cursor position - curwin->w_cursor = start_pos; - if (oneleft() == OK) - { - back_in_line(); - if (cls() == 0 && curwin->w_cursor.col > 0) - { - if (VIsual_active) - VIsual = curwin->w_cursor; - else - oap->start = curwin->w_cursor; - } - } - curwin->w_cursor = pos; // put cursor back at end - } - - if (VIsual_active) - { - if (*p_sel == 'e' && inclusive && LTOREQ_POS(VIsual, curwin->w_cursor)) - inc_cursor(); - if (VIsual_mode == 'V') - { - VIsual_mode = 'v'; - redraw_cmdline = TRUE; // show mode later - } - } - else - oap->inclusive = inclusive; - - return OK; -} - -/* - * Find sentence(s) under the cursor, cursor at end. - * When Visual active, extend it by one or more sentences. - */ - int -current_sent(oparg_T *oap, long count, int include) -{ - pos_T start_pos; - pos_T pos; - int start_blank; - int c; - int at_start_sent; - long ncount; - - start_pos = curwin->w_cursor; - pos = start_pos; - findsent(FORWARD, 1L); // Find start of next sentence. - - /* - * When the Visual area is bigger than one character: Extend it. - */ - if (VIsual_active && !EQUAL_POS(start_pos, VIsual)) - { -extend: - if (LT_POS(start_pos, VIsual)) - { - /* - * Cursor at start of Visual area. - * Find out where we are: - * - in the white space before a sentence - * - in a sentence or just after it - * - at the start of a sentence - */ - at_start_sent = TRUE; - decl(&pos); - while (LT_POS(pos, curwin->w_cursor)) - { - c = gchar_pos(&pos); - if (!VIM_ISWHITE(c)) - { - at_start_sent = FALSE; - break; - } - incl(&pos); - } - if (!at_start_sent) - { - findsent(BACKWARD, 1L); - if (EQUAL_POS(curwin->w_cursor, start_pos)) - at_start_sent = TRUE; // exactly at start of sentence - else - // inside a sentence, go to its end (start of next) - findsent(FORWARD, 1L); - } - if (include) // "as" gets twice as much as "is" - count *= 2; - while (count--) - { - if (at_start_sent) - find_first_blank(&curwin->w_cursor); - c = gchar_cursor(); - if (!at_start_sent || (!include && !VIM_ISWHITE(c))) - findsent(BACKWARD, 1L); - at_start_sent = !at_start_sent; - } - } - else - { - /* - * Cursor at end of Visual area. - * Find out where we are: - * - just before a sentence - * - just before or in the white space before a sentence - * - in a sentence - */ - incl(&pos); - at_start_sent = TRUE; - // not just before a sentence - if (!EQUAL_POS(pos, curwin->w_cursor)) - { - at_start_sent = FALSE; - while (LT_POS(pos, curwin->w_cursor)) - { - c = gchar_pos(&pos); - if (!VIM_ISWHITE(c)) - { - at_start_sent = TRUE; - break; - } - incl(&pos); - } - if (at_start_sent) // in the sentence - findsent(BACKWARD, 1L); - else // in/before white before a sentence - curwin->w_cursor = start_pos; - } - - if (include) // "as" gets twice as much as "is" - count *= 2; - findsent_forward(count, at_start_sent); - if (*p_sel == 'e') - ++curwin->w_cursor.col; - } - return OK; - } - - /* - * If the cursor started on a blank, check if it is just before the start - * of the next sentence. - */ - while (c = gchar_pos(&pos), VIM_ISWHITE(c)) // VIM_ISWHITE() is a macro - incl(&pos); - if (EQUAL_POS(pos, curwin->w_cursor)) - { - start_blank = TRUE; - find_first_blank(&start_pos); // go back to first blank - } - else - { - start_blank = FALSE; - findsent(BACKWARD, 1L); - start_pos = curwin->w_cursor; - } - if (include) - ncount = count * 2; - else - { - ncount = count; - if (start_blank) - --ncount; - } - if (ncount > 0) - findsent_forward(ncount, TRUE); - else - decl(&curwin->w_cursor); - - if (include) - { - /* - * If the blank in front of the sentence is included, exclude the - * blanks at the end of the sentence, go back to the first blank. - * If there are no trailing blanks, try to include leading blanks. - */ - if (start_blank) - { - find_first_blank(&curwin->w_cursor); - c = gchar_pos(&curwin->w_cursor); // VIM_ISWHITE() is a macro - if (VIM_ISWHITE(c)) - decl(&curwin->w_cursor); - } - else if (c = gchar_cursor(), !VIM_ISWHITE(c)) - find_first_blank(&start_pos); - } - - if (VIsual_active) - { - // Avoid getting stuck with "is" on a single space before a sentence. - if (EQUAL_POS(start_pos, curwin->w_cursor)) - goto extend; - if (*p_sel == 'e') - ++curwin->w_cursor.col; - VIsual = start_pos; - VIsual_mode = 'v'; - redraw_cmdline = TRUE; // show mode later - redraw_curbuf_later(INVERTED); // update the inversion - } - else - { - // include a newline after the sentence, if there is one - if (incl(&curwin->w_cursor) == -1) - oap->inclusive = TRUE; - else - oap->inclusive = FALSE; - oap->start = start_pos; - oap->motion_type = MCHAR; - } - return OK; -} - -/* - * Find block under the cursor, cursor at end. - * "what" and "other" are two matching parenthesis/brace/etc. - */ - int -current_block( - oparg_T *oap, - long count, - int include, // TRUE == include white space - int what, // '(', '{', etc. - int other) // ')', '}', etc. -{ - pos_T old_pos; - pos_T *pos = NULL; - pos_T start_pos; - pos_T *end_pos; - pos_T old_start, old_end; - char_u *save_cpo; - int sol = FALSE; // '{' at start of line - - old_pos = curwin->w_cursor; - old_end = curwin->w_cursor; // remember where we started - old_start = old_end; - - /* - * If we start on '(', '{', ')', '}', etc., use the whole block inclusive. - */ - if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor)) - { - setpcmark(); - if (what == '{') // ignore indent - while (inindent(1)) - if (inc_cursor() != 0) - break; - if (gchar_cursor() == what) - // cursor on '(' or '{', move cursor just after it - ++curwin->w_cursor.col; - } - else if (LT_POS(VIsual, curwin->w_cursor)) - { - old_start = VIsual; - curwin->w_cursor = VIsual; // cursor at low end of Visual - } - else - old_end = VIsual; - - /* - * Search backwards for unclosed '(', '{', etc.. - * Put this position in start_pos. - * Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the - * user wants. - */ - save_cpo = p_cpo; - p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%"); - while (count-- > 0) - { - if ((pos = findmatch(NULL, what)) == NULL) - break; - curwin->w_cursor = *pos; - start_pos = *pos; // the findmatch for end_pos will overwrite *pos - } - p_cpo = save_cpo; - - /* - * Search for matching ')', '}', etc. - * Put this position in curwin->w_cursor. - */ - if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL) - { - curwin->w_cursor = old_pos; - return FAIL; - } - curwin->w_cursor = *end_pos; - - /* - * Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE. - * If the ending '}', ')' or ']' is only preceded by indent, skip that - * indent. But only if the resulting area is not smaller than what we - * started with. - */ - while (!include) - { - incl(&start_pos); - sol = (curwin->w_cursor.col == 0); - decl(&curwin->w_cursor); - while (inindent(1)) - { - sol = TRUE; - if (decl(&curwin->w_cursor) != 0) - break; - } - - /* - * In Visual mode, when the resulting area is not bigger than what we - * started with, extend it to the next block, and then exclude again. - */ - if (!LT_POS(start_pos, old_start) && !LT_POS(old_end, curwin->w_cursor) - && VIsual_active) - { - curwin->w_cursor = old_start; - decl(&curwin->w_cursor); - if ((pos = findmatch(NULL, what)) == NULL) - { - curwin->w_cursor = old_pos; - return FAIL; - } - start_pos = *pos; - curwin->w_cursor = *pos; - if ((end_pos = findmatch(NULL, other)) == NULL) - { - curwin->w_cursor = old_pos; - return FAIL; - } - curwin->w_cursor = *end_pos; - } - else - break; - } - - if (VIsual_active) - { - if (*p_sel == 'e') - inc(&curwin->w_cursor); - if (sol && gchar_cursor() != NUL) - inc(&curwin->w_cursor); // include the line break - VIsual = start_pos; - VIsual_mode = 'v'; - redraw_curbuf_later(INVERTED); // update the inversion - showmode(); - } - else - { - oap->start = start_pos; - oap->motion_type = MCHAR; - oap->inclusive = FALSE; - if (sol) - incl(&curwin->w_cursor); - else if (LTOREQ_POS(start_pos, curwin->w_cursor)) - // Include the character under the cursor. - oap->inclusive = TRUE; - else - // End is before the start (no text in between <>, [], etc.): don't - // operate on any text. - curwin->w_cursor = start_pos; - } - - return OK; -} - -/* - * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". - * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>". - */ - static int -in_html_tag( - int end_tag) -{ - char_u *line = ml_get_curline(); - char_u *p; - int c; - int lc = NUL; - pos_T pos; - - if (enc_dbcs) - { - char_u *lp = NULL; - - // We search forward until the cursor, because searching backwards is - // very slow for DBCS encodings. - for (p = line; p < line + curwin->w_cursor.col; MB_PTR_ADV(p)) - if (*p == '>' || *p == '<') - { - lc = *p; - lp = p; - } - if (*p != '<') // check for '<' under cursor - { - if (lc != '<') - return FALSE; - p = lp; - } - } - else - { - for (p = line + curwin->w_cursor.col; p > line; ) - { - if (*p == '<') // find '<' under/before cursor - break; - MB_PTR_BACK(line, p); - if (*p == '>') // find '>' before cursor - break; - } - if (*p != '<') - return FALSE; - } - - pos.lnum = curwin->w_cursor.lnum; - pos.col = (colnr_T)(p - line); - - MB_PTR_ADV(p); - if (end_tag) - // check that there is a '/' after the '<' - return *p == '/'; - - // check that there is no '/' after the '<' - if (*p == '/') - return FALSE; - - // check that the matching '>' is not preceded by '/' - for (;;) - { - if (inc(&pos) < 0) - return FALSE; - c = *ml_get_pos(&pos); - if (c == '>') - break; - lc = c; - } - return lc != '/'; -} - -/* - * Find tag block under the cursor, cursor at end. - */ - int -current_tagblock( - oparg_T *oap, - long count_arg, - int include) // TRUE == include white space -{ - long count = count_arg; - long n; - pos_T old_pos; - pos_T start_pos; - pos_T end_pos; - pos_T old_start, old_end; - char_u *spat, *epat; - char_u *p; - char_u *cp; - int len; - int r; - int do_include = include; - int save_p_ws = p_ws; - int retval = FAIL; - int is_inclusive = TRUE; - - p_ws = FALSE; - - old_pos = curwin->w_cursor; - old_end = curwin->w_cursor; // remember where we started - old_start = old_end; - if (!VIsual_active || *p_sel == 'e') - decl(&old_end); // old_end is inclusive - - /* - * If we start on "<aaa>" select that block. - */ - if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor)) - { - setpcmark(); - - // ignore indent - while (inindent(1)) - if (inc_cursor() != 0) |