1
0
forked from aniani/vim

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)
This commit is contained in:
Bram Moolenaar
2020-05-01 14:26:37 +02:00
parent 4cfde1d273
commit 11abd09521
19 changed files with 1167 additions and 1176 deletions

590
src/ops.c
View File

@@ -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
*