From 11abd095210fc84e5dcee87b9baed86061caefe4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 1 May 2020 14:26:37 +0200 Subject: patch 8.2.0674: some source files are too big Problem: Some source files are too big. Solution: Move text formatting functions to a new file. (Yegappan Lakshmanan, closes #6021) --- src/ops.c | 590 -------------------------------------------------------------- 1 file changed, 590 deletions(-) (limited to 'src/ops.c') diff --git a/src/ops.c b/src/ops.c index 5e9de4d7c..9ab355596 100644 --- a/src/ops.c +++ b/src/ops.c @@ -17,8 +17,6 @@ static void shift_block(oparg_T *oap, int amount); static void mb_adjust_opend(oparg_T *oap); static int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1); -static int ends_in_white(linenr_T lnum); -static int fmt_check_par(linenr_T, int *, char_u **, int do_comments); // Flags for third item in "opchars". #define OPF_LINES 1 // operator always works on lines @@ -590,46 +588,6 @@ block_insert( State = oldstate; } -/* - * Stuff a string into the typeahead buffer, such that edit() will insert it - * literally ("literally" TRUE) or interpret is as typed characters. - */ - void -stuffescaped(char_u *arg, int literally) -{ - int c; - char_u *start; - - while (*arg != NUL) - { - // Stuff a sequence of normal ASCII characters, that's fast. Also - // stuff K_SPECIAL to get the effect of a special key when "literally" - // is TRUE. - start = arg; - while ((*arg >= ' ' -#ifndef EBCDIC - && *arg < DEL // EBCDIC: chars above space are normal -#endif - ) - || (*arg == K_SPECIAL && !literally)) - ++arg; - if (arg > start) - stuffReadbuffLen(start, (long)(arg - start)); - - // stuff a single special character - if (*arg != NUL) - { - if (has_mbyte) - c = mb_cptr2char_adv(&arg); - else - c = *arg++; - if (literally && ((c < ' ' && c != TAB) || c == DEL)) - stuffcharReadbuff(Ctrl_V); - stuffcharReadbuff(c); - } - } -} - /* * Handle a delete operation. * @@ -2170,554 +2128,6 @@ theend: return ret; } -/* - * Return TRUE if the two comment leaders given are the same. "lnum" is - * the first line. White-space is ignored. Note that the whole of - * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb - */ - static int -same_leader( - linenr_T lnum, - int leader1_len, - char_u *leader1_flags, - int leader2_len, - char_u *leader2_flags) -{ - int idx1 = 0, idx2 = 0; - char_u *p; - char_u *line1; - char_u *line2; - - if (leader1_len == 0) - return (leader2_len == 0); - - /* - * If first leader has 'f' flag, the lines can be joined only if the - * second line does not have a leader. - * If first leader has 'e' flag, the lines can never be joined. - * If fist leader has 's' flag, the lines can only be joined if there is - * some text after it and the second line has the 'm' flag. - */ - if (leader1_flags != NULL) - { - for (p = leader1_flags; *p && *p != ':'; ++p) - { - if (*p == COM_FIRST) - return (leader2_len == 0); - if (*p == COM_END) - return FALSE; - if (*p == COM_START) - { - if (*(ml_get(lnum) + leader1_len) == NUL) - return FALSE; - if (leader2_flags == NULL || leader2_len == 0) - return FALSE; - for (p = leader2_flags; *p && *p != ':'; ++p) - if (*p == COM_MIDDLE) - return TRUE; - return FALSE; - } - } - } - - /* - * Get current line and next line, compare the leaders. - * The first line has to be saved, only one line can be locked at a time. - */ - line1 = vim_strsave(ml_get(lnum)); - if (line1 != NULL) - { - for (idx1 = 0; VIM_ISWHITE(line1[idx1]); ++idx1) - ; - line2 = ml_get(lnum + 1); - for (idx2 = 0; idx2 < leader2_len; ++idx2) - { - if (!VIM_ISWHITE(line2[idx2])) - { - if (line1[idx1++] != line2[idx2]) - break; - } - else - while (VIM_ISWHITE(line1[idx1])) - ++idx1; - } - vim_free(line1); - } - return (idx2 == leader2_len && idx1 == leader1_len); -} - -/* - * Implementation of the format operator 'gq'. - */ - static void -op_format( - oparg_T *oap, - int keep_cursor) // keep cursor on same text char -{ - long old_line_count = curbuf->b_ml.ml_line_count; - - // Place the cursor where the "gq" or "gw" command was given, so that "u" - // can put it back there. - curwin->w_cursor = oap->cursor_start; - - if (u_save((linenr_T)(oap->start.lnum - 1), - (linenr_T)(oap->end.lnum + 1)) == FAIL) - return; - curwin->w_cursor = oap->start; - - if (oap->is_VIsual) - // When there is no change: need to remove the Visual selection - redraw_curbuf_later(INVERTED); - - if (!cmdmod.lockmarks) - // Set '[ mark at the start of the formatted area - curbuf->b_op_start = oap->start; - - // For "gw" remember the cursor position and put it back below (adjusted - // for joined and split lines). - if (keep_cursor) - saved_cursor = oap->cursor_start; - - format_lines(oap->line_count, keep_cursor); - - /* - * Leave the cursor at the first non-blank of the last formatted line. - * If the cursor was moved one line back (e.g. with "Q}") go to the next - * line, so "." will do the next lines. - */ - if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) - ++curwin->w_cursor.lnum; - beginline(BL_WHITE | BL_FIX); - old_line_count = curbuf->b_ml.ml_line_count - old_line_count; - msgmore(old_line_count); - - if (!cmdmod.lockmarks) - // put '] mark on the end of the formatted area - curbuf->b_op_end = curwin->w_cursor; - - if (keep_cursor) - { - curwin->w_cursor = saved_cursor; - saved_cursor.lnum = 0; - } - - if (oap->is_VIsual) - { - win_T *wp; - - FOR_ALL_WINDOWS(wp) - { - if (wp->w_old_cursor_lnum != 0) - { - // When lines have been inserted or deleted, adjust the end of - // the Visual area to be redrawn. - if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum) - wp->w_old_cursor_lnum += old_line_count; - else - wp->w_old_visual_lnum += old_line_count; - } - } - } -} - -#if defined(FEAT_EVAL) || defined(PROTO) -/* - * Implementation of the format operator 'gq' for when using 'formatexpr'. - */ - static void -op_formatexpr(oparg_T *oap) -{ - if (oap->is_VIsual) - // When there is no change: need to remove the Visual selection - redraw_curbuf_later(INVERTED); - - if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0) - // As documented: when 'formatexpr' returns non-zero fall back to - // internal formatting. - op_format(oap, FALSE); -} - - int -fex_format( - linenr_T lnum, - long count, - int c) // character to be inserted -{ - int use_sandbox = was_set_insecurely((char_u *)"formatexpr", - OPT_LOCAL); - int r; - char_u *fex; - - /* - * Set v:lnum to the first line number and v:count to the number of lines. - * Set v:char to the character to be inserted (can be NUL). - */ - set_vim_var_nr(VV_LNUM, lnum); - set_vim_var_nr(VV_COUNT, count); - set_vim_var_char(c); - - // Make a copy, the option could be changed while calling it. - fex = vim_strsave(curbuf->b_p_fex); - if (fex == NULL) - return 0; - - /* - * Evaluate the function. - */ - if (use_sandbox) - ++sandbox; - r = (int)eval_to_number(fex); - if (use_sandbox) - --sandbox; - - set_vim_var_string(VV_CHAR, NULL, -1); - vim_free(fex); - - return r; -} -#endif - -/* - * Format "line_count" lines, starting at the cursor position. - * When "line_count" is negative, format until the end of the paragraph. - * Lines after the cursor line are saved for undo, caller must have saved the - * first line. - */ - void -format_lines( - linenr_T line_count, - int avoid_fex) // don't use 'formatexpr' -{ - int max_len; - int is_not_par; // current line not part of parag. - int next_is_not_par; // next line not part of paragraph - int is_end_par; // at end of paragraph - int prev_is_end_par = FALSE;// prev. line not part of parag. - int next_is_start_par = FALSE; - int leader_len = 0; // leader len of current line - int next_leader_len; // leader len of next line - char_u *leader_flags = NULL; // flags for leader of current line - char_u *next_leader_flags; // flags for leader of next line - int do_comments; // format comments - int do_comments_list = 0; // format comments with 'n' or '2' - int advance = TRUE; - int second_indent = -1; // indent for second line (comment - // aware) - int do_second_indent; - int do_number_indent; - int do_trail_white; - int first_par_line = TRUE; - int smd_save; - long count; - int need_set_indent = TRUE; // set indent of next paragraph - int force_format = FALSE; - int old_State = State; - - // length of a line to force formatting: 3 * 'tw' - max_len = comp_textwidth(TRUE) * 3; - - // check for 'q', '2' and '1' in 'formatoptions' - do_comments = has_format_option(FO_Q_COMS); - do_second_indent = has_format_option(FO_Q_SECOND); - do_number_indent = has_format_option(FO_Q_NUMBER); - do_trail_white = has_format_option(FO_WHITE_PAR); - - /* - * Get info about the previous and current line. - */ - if (curwin->w_cursor.lnum > 1) - is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1 - , &leader_len, &leader_flags, do_comments); - else - is_not_par = TRUE; - next_is_not_par = fmt_check_par(curwin->w_cursor.lnum - , &next_leader_len, &next_leader_flags, do_comments); - is_end_par = (is_not_par || next_is_not_par); - if (!is_end_par && do_trail_white) - is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1); - - curwin->w_cursor.lnum--; - for (count = line_count; count != 0 && !got_int; --count) - { - /* - * Advance to next paragraph. - */ - if (advance) - { - curwin->w_cursor.lnum++; - prev_is_end_par = is_end_par; - is_not_par = next_is_not_par; - leader_len = next_leader_len; - leader_flags = next_leader_flags; - } - - /* - * The last line to be formatted. - */ - if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) - { - next_is_not_par = TRUE; - next_leader_len = 0; - next_leader_flags = NULL; - } - else - { - next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1 - , &next_leader_len, &next_leader_flags, do_comments); - if (do_number_indent) - next_is_start_par = - (get_number_indent(curwin->w_cursor.lnum + 1) > 0); - } - advance = TRUE; - is_end_par = (is_not_par || next_is_not_par || next_is_start_par); - if (!is_end_par && do_trail_white) - is_end_par = !ends_in_white(curwin->w_cursor.lnum); - - /* - * Skip lines that are not in a paragraph. - */ - if (is_not_par) - { - if (line_count < 0) - break; - } - else - { - /* - * For the first line of a paragraph, check indent of second line. - * Don't do this for comments and empty lines. - */ - if (first_par_line - && (do_second_indent || do_number_indent) - && prev_is_end_par - && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) - { - if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1)) - { - if (leader_len == 0 && next_leader_len == 0) - { - // no comment found - second_indent = - get_indent_lnum(curwin->w_cursor.lnum + 1); - } - else - { - second_indent = next_leader_len; - do_comments_list = 1; - } - } - else if (do_number_indent) - { - if (leader_len == 0 && next_leader_len == 0) - { - // no comment found - second_indent = - get_number_indent(curwin->w_cursor.lnum); - } - else - { - // get_number_indent() is now "comment aware"... - second_indent = - get_number_indent(curwin->w_cursor.lnum); - do_comments_list = 1; - } - } - } - - /* - * When the comment leader changes, it's the end of the paragraph. - */ - if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count - || !same_leader(curwin->w_cursor.lnum, - leader_len, leader_flags, - next_leader_len, next_leader_flags)) - is_end_par = TRUE; - - /* - * If we have got to the end of a paragraph, or the line is - * getting long, format it. - */ - if (is_end_par || force_format) - { - if (need_set_indent) - // replace indent in first line with minimal number of - // tabs and spaces, according to current options - (void)set_indent(get_indent(), SIN_CHANGED); - - // put cursor on last non-space - State = NORMAL; // don't go past end-of-line - coladvance((colnr_T)MAXCOL); - while (curwin->w_cursor.col && vim_isspace(gchar_cursor())) - dec_cursor(); - - // do the formatting, without 'showmode' - State = INSERT; // for open_line() - smd_save = p_smd; - p_smd = FALSE; - insertchar(NUL, INSCHAR_FORMAT - + (do_comments ? INSCHAR_DO_COM : 0) - + (do_comments && do_comments_list - ? INSCHAR_COM_LIST : 0) - + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent); - State = old_State; - p_smd = smd_save; - second_indent = -1; - // at end of par.: need to set indent of next par. - need_set_indent = is_end_par; - if (is_end_par) - { - // When called with a negative line count, break at the - // end of the paragraph. - if (line_count < 0) - break; - first_par_line = TRUE; - } - force_format = FALSE; - } - - /* - * When still in same paragraph, join the lines together. But - * first delete the leader from the second line. - */ - if (!is_end_par) - { - advance = FALSE; - curwin->w_cursor.lnum++; - curwin->w_cursor.col = 0; - if (line_count < 0 && u_save_cursor() == FAIL) - break; - if (next_leader_len > 0) - { - (void)del_bytes((long)next_leader_len, FALSE, FALSE); - mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L, - (long)-next_leader_len, 0); - } - else if (second_indent > 0) // the "leader" for FO_Q_SECOND - { - int indent = getwhitecols_curline(); - - if (indent > 0) - { - (void)del_bytes(indent, FALSE, FALSE); - mark_col_adjust(curwin->w_cursor.lnum, - (colnr_T)0, 0L, (long)-indent, 0); - } - } - curwin->w_cursor.lnum--; - if (do_join(2, TRUE, FALSE, FALSE, FALSE) == FAIL) - { - beep_flush(); - break; - } - first_par_line = FALSE; - // If the line is getting long, format it next time - if (STRLEN(ml_get_curline()) > (size_t)max_len) - force_format = TRUE; - else - force_format = FALSE; - } - } - line_breakcheck(); - } -} - -/* - * Return TRUE if line "lnum" ends in a white character. - */ - static int -ends_in_white(linenr_T lnum) -{ - char_u *s = ml_get(lnum); - size_t l; - - if (*s == NUL) - return FALSE; - // Don't use STRLEN() inside VIM_ISWHITE(), SAS/C complains: "macro - // invocation may call function multiple times". - l = STRLEN(s) - 1; - return VIM_ISWHITE(s[l]); -} - -/* - * Blank lines, and lines containing only the comment leader, are left - * untouched by the formatting. The function returns TRUE in this - * case. It also returns TRUE when a line starts with the end of a comment - * ('e' in comment flags), so that this line is skipped, and not joined to the - * previous line. A new paragraph starts after a blank line, or when the - * comment leader changes -- webb. - */ - static int -fmt_check_par( - linenr_T lnum, - int *leader_len, - char_u **leader_flags, - int do_comments) -{ - char_u *flags = NULL; // init for GCC - char_u *ptr; - - ptr = ml_get(lnum); - if (do_comments) - *leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE); - else - *leader_len = 0; - - if (*leader_len > 0) - { - /* - * Search for 'e' flag in comment leader flags. - */ - flags = *leader_flags; - while (*flags && *flags != ':' && *flags != COM_END) - ++flags; - } - - return (*skipwhite(ptr + *leader_len) == NUL - || (*leader_len > 0 && *flags == COM_END) - || startPS(lnum, NUL, FALSE)); -} - -/* - * Return TRUE when a paragraph starts in line "lnum". Return FALSE when the - * previous line is in the same paragraph. Used for auto-formatting. - */ - int -paragraph_start(linenr_T lnum) -{ - char_u *p; - int leader_len = 0; // leader len of current line - char_u *leader_flags = NULL; // flags for leader of current line - int next_leader_len; // leader len of next line - char_u *next_leader_flags; // flags for leader of next line - int do_comments; // format comments - - if (lnum <= 1) - return TRUE; // start of the file - - p = ml_get(lnum - 1); - if (*p == NUL) - return TRUE; // after empty line - - do_comments = has_format_option(FO_Q_COMS); - if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) - return TRUE; // after non-paragraph line - - if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments)) - return TRUE; // "lnum" is not a paragraph line - - if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1)) - return TRUE; // missing trailing space in previous line. - - if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0)) - return TRUE; // numbered item starts in "lnum". - - if (!same_leader(lnum - 1, leader_len, leader_flags, - next_leader_len, next_leader_flags)) - return TRUE; // change of comment leader. - - return FALSE; -} - /* * prepare a few things for block mode yank/delete/tilde * -- cgit v1.2.1