mirror of
https://github.com/neovim/neovim.git
synced 2025-09-29 06:28:35 +00:00
vim-patch:8.1.2127: the indent.c file is a bit big
Problem: The indent.c file is a bit big.
Solution: Move C-indent code a a new cindent.c file. Move other
indent-related code to indent.c. (Yegappan Lakshmanan,
closes vim/vim#5031)
14c01f8348
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
@@ -957,118 +957,6 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy the indent from ptr to the current line (and fill to size).
|
|
||||||
/// Leaves the cursor on the first non-blank in the line.
|
|
||||||
///
|
|
||||||
/// @return true if the line was changed.
|
|
||||||
bool copy_indent(int size, char *src)
|
|
||||||
{
|
|
||||||
char *p = NULL;
|
|
||||||
char *line = NULL;
|
|
||||||
int ind_len;
|
|
||||||
int line_len = 0;
|
|
||||||
int tab_pad;
|
|
||||||
|
|
||||||
// Round 1: compute the number of characters needed for the indent
|
|
||||||
// Round 2: copy the characters.
|
|
||||||
for (int round = 1; round <= 2; round++) {
|
|
||||||
int todo = size;
|
|
||||||
ind_len = 0;
|
|
||||||
int ind_done = 0;
|
|
||||||
int ind_col = 0;
|
|
||||||
char *s = src;
|
|
||||||
|
|
||||||
// Count/copy the usable portion of the source line.
|
|
||||||
while (todo > 0 && ascii_iswhite(*s)) {
|
|
||||||
if (*s == TAB) {
|
|
||||||
tab_pad = tabstop_padding(ind_done,
|
|
||||||
curbuf->b_p_ts,
|
|
||||||
curbuf->b_p_vts_array);
|
|
||||||
|
|
||||||
// Stop if this tab will overshoot the target.
|
|
||||||
if (todo < tab_pad) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
todo -= tab_pad;
|
|
||||||
ind_done += tab_pad;
|
|
||||||
ind_col += tab_pad;
|
|
||||||
} else {
|
|
||||||
todo--;
|
|
||||||
ind_done++;
|
|
||||||
ind_col++;
|
|
||||||
}
|
|
||||||
ind_len++;
|
|
||||||
|
|
||||||
if (p != NULL) {
|
|
||||||
*p++ = *s;
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill to next tabstop with a tab, if possible.
|
|
||||||
tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts, curbuf->b_p_vts_array);
|
|
||||||
|
|
||||||
if ((todo >= tab_pad) && !curbuf->b_p_et) {
|
|
||||||
todo -= tab_pad;
|
|
||||||
ind_len++;
|
|
||||||
ind_col += tab_pad;
|
|
||||||
|
|
||||||
if (p != NULL) {
|
|
||||||
*p++ = TAB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add tabs required for indent.
|
|
||||||
if (!curbuf->b_p_et) {
|
|
||||||
while (true) {
|
|
||||||
tab_pad = tabstop_padding(ind_col,
|
|
||||||
curbuf->b_p_ts,
|
|
||||||
curbuf->b_p_vts_array);
|
|
||||||
if (todo < tab_pad) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
todo -= tab_pad;
|
|
||||||
ind_len++;
|
|
||||||
ind_col += tab_pad;
|
|
||||||
if (p != NULL) {
|
|
||||||
*p++ = TAB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count/add spaces required for indent.
|
|
||||||
while (todo > 0) {
|
|
||||||
todo--;
|
|
||||||
ind_len++;
|
|
||||||
|
|
||||||
if (p != NULL) {
|
|
||||||
*p++ = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p == NULL) {
|
|
||||||
// Allocate memory for the result: the copied indent, new indent
|
|
||||||
// and the rest of the line.
|
|
||||||
line_len = get_cursor_line_len() + 1;
|
|
||||||
assert(ind_len + line_len >= 0);
|
|
||||||
size_t line_size;
|
|
||||||
STRICT_ADD(ind_len, line_len, &line_size, size_t);
|
|
||||||
line = xmalloc(line_size);
|
|
||||||
p = line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the original line
|
|
||||||
memmove(p, get_cursor_line_ptr(), (size_t)line_len);
|
|
||||||
|
|
||||||
// Replace the line
|
|
||||||
ml_replace(curwin->w_cursor.lnum, line, false);
|
|
||||||
|
|
||||||
// Put the cursor after the indent.
|
|
||||||
curwin->w_cursor.col = ind_len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// open_line: Add a new line below or above the current line.
|
/// open_line: Add a new line below or above the current line.
|
||||||
///
|
///
|
||||||
/// For MODE_VREPLACE state, we only add a new line when we get to the end of
|
/// For MODE_VREPLACE state, we only add a new line when we get to the end of
|
||||||
|
274
src/nvim/edit.c
274
src/nvim/edit.c
@@ -1636,204 +1636,6 @@ void undisplay_dollar(void)
|
|||||||
redrawWinline(curwin, curwin->w_cursor.lnum);
|
redrawWinline(curwin, curwin->w_cursor.lnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
|
|
||||||
/// Keep the cursor on the same character.
|
|
||||||
/// type == INDENT_INC increase indent (for CTRL-T or <Tab>)
|
|
||||||
/// type == INDENT_DEC decrease indent (for CTRL-D)
|
|
||||||
/// type == INDENT_SET set indent to "amount"
|
|
||||||
///
|
|
||||||
/// @param round if true, round the indent to 'shiftwidth' (only with _INC and _Dec).
|
|
||||||
/// @param call_changed_bytes call changed_bytes()
|
|
||||||
void change_indent(int type, int amount, int round, bool call_changed_bytes)
|
|
||||||
{
|
|
||||||
int insstart_less; // reduction for Insstart.col
|
|
||||||
colnr_T orig_col = 0; // init for GCC
|
|
||||||
char *orig_line = NULL; // init for GCC
|
|
||||||
|
|
||||||
// MODE_VREPLACE state needs to know what the line was like before changing
|
|
||||||
if (State & VREPLACE_FLAG) {
|
|
||||||
orig_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
|
|
||||||
orig_col = curwin->w_cursor.col;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for the following tricks we don't want list mode
|
|
||||||
int save_p_list = curwin->w_p_list;
|
|
||||||
curwin->w_p_list = false;
|
|
||||||
colnr_T vc = getvcol_nolist(&curwin->w_cursor);
|
|
||||||
int vcol = vc;
|
|
||||||
|
|
||||||
// For Replace mode we need to fix the replace stack later, which is only
|
|
||||||
// possible when the cursor is in the indent. Remember the number of
|
|
||||||
// characters before the cursor if it's possible.
|
|
||||||
int start_col = curwin->w_cursor.col;
|
|
||||||
|
|
||||||
// determine offset from first non-blank
|
|
||||||
int new_cursor_col = curwin->w_cursor.col;
|
|
||||||
beginline(BL_WHITE);
|
|
||||||
new_cursor_col -= curwin->w_cursor.col;
|
|
||||||
|
|
||||||
insstart_less = curwin->w_cursor.col;
|
|
||||||
|
|
||||||
// If the cursor is in the indent, compute how many screen columns the
|
|
||||||
// cursor is to the left of the first non-blank.
|
|
||||||
if (new_cursor_col < 0) {
|
|
||||||
vcol = get_indent() - vcol;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_cursor_col > 0) { // can't fix replace stack
|
|
||||||
start_col = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the new indent. The cursor will be put on the first non-blank.
|
|
||||||
if (type == INDENT_SET) {
|
|
||||||
set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
|
|
||||||
} else {
|
|
||||||
int save_State = State;
|
|
||||||
|
|
||||||
// Avoid being called recursively.
|
|
||||||
if (State & VREPLACE_FLAG) {
|
|
||||||
State = MODE_INSERT;
|
|
||||||
}
|
|
||||||
shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
|
|
||||||
State = save_State;
|
|
||||||
}
|
|
||||||
insstart_less -= curwin->w_cursor.col;
|
|
||||||
|
|
||||||
// Try to put cursor on same character.
|
|
||||||
// If the cursor is at or after the first non-blank in the line,
|
|
||||||
// compute the cursor column relative to the column of the first
|
|
||||||
// non-blank character.
|
|
||||||
// If we are not in insert mode, leave the cursor on the first non-blank.
|
|
||||||
// If the cursor is before the first non-blank, position it relative
|
|
||||||
// to the first non-blank, counted in screen columns.
|
|
||||||
if (new_cursor_col >= 0) {
|
|
||||||
// When changing the indent while the cursor is touching it, reset
|
|
||||||
// Insstart_col to 0.
|
|
||||||
if (new_cursor_col == 0) {
|
|
||||||
insstart_less = MAXCOL;
|
|
||||||
}
|
|
||||||
new_cursor_col += curwin->w_cursor.col;
|
|
||||||
} else if (!(State & MODE_INSERT)) {
|
|
||||||
new_cursor_col = curwin->w_cursor.col;
|
|
||||||
} else {
|
|
||||||
// Compute the screen column where the cursor should be.
|
|
||||||
vcol = get_indent() - vcol;
|
|
||||||
int const end_vcol = (colnr_T)((vcol < 0) ? 0 : vcol);
|
|
||||||
curwin->w_virtcol = end_vcol;
|
|
||||||
|
|
||||||
// Advance the cursor until we reach the right screen column.
|
|
||||||
new_cursor_col = 0;
|
|
||||||
char *const line = get_cursor_line_ptr();
|
|
||||||
vcol = 0;
|
|
||||||
if (*line != NUL) {
|
|
||||||
CharsizeArg csarg;
|
|
||||||
CSType cstype = init_charsize_arg(&csarg, curwin, 0, line);
|
|
||||||
StrCharInfo ci = utf_ptr2StrCharInfo(line);
|
|
||||||
while (true) {
|
|
||||||
int next_vcol = vcol + win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width;
|
|
||||||
if (next_vcol > end_vcol) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
vcol = next_vcol;
|
|
||||||
ci = utfc_next(ci);
|
|
||||||
if (*ci.ptr == NUL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
new_cursor_col = (int)(ci.ptr - line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// May need to insert spaces to be able to position the cursor on
|
|
||||||
// the right screen column.
|
|
||||||
if (vcol != (int)curwin->w_virtcol) {
|
|
||||||
curwin->w_cursor.col = (colnr_T)new_cursor_col;
|
|
||||||
const size_t ptrlen = (size_t)(curwin->w_virtcol - vcol);
|
|
||||||
char *ptr = xmallocz(ptrlen);
|
|
||||||
memset(ptr, ' ', ptrlen);
|
|
||||||
new_cursor_col += (int)ptrlen;
|
|
||||||
ins_str(ptr, ptrlen);
|
|
||||||
xfree(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// When changing the indent while the cursor is in it, reset
|
|
||||||
// Insstart_col to 0.
|
|
||||||
insstart_less = MAXCOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
curwin->w_p_list = save_p_list;
|
|
||||||
curwin->w_cursor.col = MAX(0, (colnr_T)new_cursor_col);
|
|
||||||
curwin->w_set_curswant = true;
|
|
||||||
changed_cline_bef_curs(curwin);
|
|
||||||
|
|
||||||
// May have to adjust the start of the insert.
|
|
||||||
if (State & MODE_INSERT) {
|
|
||||||
if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) {
|
|
||||||
if ((int)Insstart.col <= insstart_less) {
|
|
||||||
Insstart.col = 0;
|
|
||||||
} else {
|
|
||||||
Insstart.col -= insstart_less;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((int)ai_col <= insstart_less) {
|
|
||||||
ai_col = 0;
|
|
||||||
} else {
|
|
||||||
ai_col -= insstart_less;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For MODE_REPLACE state, may have to fix the replace stack, if it's
|
|
||||||
// possible. If the number of characters before the cursor decreased, need
|
|
||||||
// to pop a few characters from the replace stack.
|
|
||||||
// If the number of characters before the cursor increased, need to push a
|
|
||||||
// few NULs onto the replace stack.
|
|
||||||
if (REPLACE_NORMAL(State) && start_col >= 0) {
|
|
||||||
while (start_col > (int)curwin->w_cursor.col) {
|
|
||||||
replace_join(0); // remove a NUL from the replace stack
|
|
||||||
start_col--;
|
|
||||||
}
|
|
||||||
while (start_col < (int)curwin->w_cursor.col) {
|
|
||||||
replace_push_nul();
|
|
||||||
start_col++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For MODE_VREPLACE state, we also have to fix the replace stack. In this
|
|
||||||
// case it is always possible because we backspace over the whole line and
|
|
||||||
// then put it back again the way we wanted it.
|
|
||||||
if (State & VREPLACE_FLAG) {
|
|
||||||
// Save new line
|
|
||||||
char *new_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
|
|
||||||
|
|
||||||
// We only put back the new line up to the cursor
|
|
||||||
new_line[curwin->w_cursor.col] = NUL;
|
|
||||||
int new_col = curwin->w_cursor.col;
|
|
||||||
|
|
||||||
// Put back original line
|
|
||||||
ml_replace(curwin->w_cursor.lnum, orig_line, false);
|
|
||||||
curwin->w_cursor.col = orig_col;
|
|
||||||
|
|
||||||
curbuf_splice_pending++;
|
|
||||||
|
|
||||||
// Backspace from cursor to start of line
|
|
||||||
backspace_until_column(0);
|
|
||||||
|
|
||||||
// Insert new stuff into line again
|
|
||||||
ins_bytes(new_line);
|
|
||||||
|
|
||||||
xfree(new_line);
|
|
||||||
|
|
||||||
curbuf_splice_pending--;
|
|
||||||
|
|
||||||
// TODO(bfredl): test for crazy edge cases, like we stand on a TAB or
|
|
||||||
// something? does this even do the right text change then?
|
|
||||||
int delta = orig_col - new_col;
|
|
||||||
extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1, new_col,
|
|
||||||
delta < 0 ? -delta : 0,
|
|
||||||
delta > 0 ? delta : 0,
|
|
||||||
kExtmarkUndo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Truncate the space at the end of a line. This is to be used only in an
|
/// Truncate the space at the end of a line. This is to be used only in an
|
||||||
/// insert mode. It handles fixing the replace stack for MODE_REPLACE and
|
/// insert mode. It handles fixing the replace stack for MODE_REPLACE and
|
||||||
/// MODE_VREPLACE modes.
|
/// MODE_VREPLACE modes.
|
||||||
@@ -2885,7 +2687,7 @@ static int replace_pop_if_nul(void)
|
|||||||
/// encountered.
|
/// encountered.
|
||||||
///
|
///
|
||||||
/// @param off offset for which NUL to remove
|
/// @param off offset for which NUL to remove
|
||||||
static void replace_join(int off)
|
void replace_join(int off)
|
||||||
{
|
{
|
||||||
for (ssize_t i = (ssize_t)kv_size(replace_stack); --i >= 0;) {
|
for (ssize_t i = (ssize_t)kv_size(replace_stack); --i >= 0;) {
|
||||||
if (kv_A(replace_stack, i) == NUL && off-- <= 0) {
|
if (kv_A(replace_stack, i) == NUL && off-- <= 0) {
|
||||||
@@ -4403,80 +4205,6 @@ static int ins_ctrl_ey(int tc)
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to do some very smart auto-indenting.
|
|
||||||
// Used when inserting a "normal" character.
|
|
||||||
static void ins_try_si(int c)
|
|
||||||
{
|
|
||||||
pos_T *pos;
|
|
||||||
|
|
||||||
// do some very smart indenting when entering '{' or '}'
|
|
||||||
if (((did_si || can_si_back) && c == '{') || (can_si && c == '}' && inindent(0))) {
|
|
||||||
pos_T old_pos;
|
|
||||||
char *ptr;
|
|
||||||
int i;
|
|
||||||
bool temp;
|
|
||||||
// for '}' set indent equal to indent of line containing matching '{'
|
|
||||||
if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) {
|
|
||||||
old_pos = curwin->w_cursor;
|
|
||||||
// If the matching '{' has a ')' immediately before it (ignoring
|
|
||||||
// white-space), then line up with the start of the line
|
|
||||||
// containing the matching '(' if there is one. This handles the
|
|
||||||
// case where an "if (..\n..) {" statement continues over multiple
|
|
||||||
// lines -- webb
|
|
||||||
ptr = ml_get(pos->lnum);
|
|
||||||
i = pos->col;
|
|
||||||
if (i > 0) { // skip blanks before '{'
|
|
||||||
while (--i > 0 && ascii_iswhite(ptr[i])) {}
|
|
||||||
}
|
|
||||||
curwin->w_cursor.lnum = pos->lnum;
|
|
||||||
curwin->w_cursor.col = i;
|
|
||||||
if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) {
|
|
||||||
curwin->w_cursor = *pos;
|
|
||||||
}
|
|
||||||
i = get_indent();
|
|
||||||
curwin->w_cursor = old_pos;
|
|
||||||
if (State & VREPLACE_FLAG) {
|
|
||||||
change_indent(INDENT_SET, i, false, true);
|
|
||||||
} else {
|
|
||||||
set_indent(i, SIN_CHANGED);
|
|
||||||
}
|
|
||||||
} else if (curwin->w_cursor.col > 0) {
|
|
||||||
// when inserting '{' after "O" reduce indent, but not
|
|
||||||
// more than indent of previous line
|
|
||||||
temp = true;
|
|
||||||
if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) {
|
|
||||||
old_pos = curwin->w_cursor;
|
|
||||||
i = get_indent();
|
|
||||||
while (curwin->w_cursor.lnum > 1) {
|
|
||||||
ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
|
|
||||||
|
|
||||||
// ignore empty lines and lines starting with '#'.
|
|
||||||
if (*ptr != '#' && *ptr != NUL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (get_indent() >= i) {
|
|
||||||
temp = false;
|
|
||||||
}
|
|
||||||
curwin->w_cursor = old_pos;
|
|
||||||
}
|
|
||||||
if (temp) {
|
|
||||||
shift_line(true, false, 1, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set indent of '#' always to 0
|
|
||||||
if (curwin->w_cursor.col > 0 && can_si && c == '#' && inindent(0)) {
|
|
||||||
// remember current indent for next line
|
|
||||||
old_indent = get_indent();
|
|
||||||
set_indent(0, SIN_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust ai_col, the char at this position can be deleted.
|
|
||||||
ai_col = MIN(ai_col, curwin->w_cursor.col);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the value that w_virtcol would have when 'list' is off.
|
// Get the value that w_virtcol would have when 'list' is off.
|
||||||
// Unless 'cpo' contains the 'L' flag.
|
// Unless 'cpo' contains the 'L' flag.
|
||||||
colnr_T get_nolist_virtcol(void)
|
colnr_T get_nolist_virtcol(void)
|
||||||
|
@@ -777,20 +777,6 @@ static void f_charcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
get_col(argvars, rettv, true);
|
get_col(argvars, rettv, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "cindent(lnum)" function
|
|
||||||
static void f_cindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|
||||||
{
|
|
||||||
pos_T pos = curwin->w_cursor;
|
|
||||||
linenr_T lnum = tv_get_lnum(argvars);
|
|
||||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
|
||||||
curwin->w_cursor.lnum = lnum;
|
|
||||||
rettv->vval.v_number = get_c_indent();
|
|
||||||
curwin->w_cursor = pos;
|
|
||||||
} else {
|
|
||||||
rettv->vval.v_number = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
win_T *get_optional_window(typval_T *argvars, int idx)
|
win_T *get_optional_window(typval_T *argvars, int idx)
|
||||||
{
|
{
|
||||||
if (argvars[idx].v_type == VAR_UNKNOWN) {
|
if (argvars[idx].v_type == VAR_UNKNOWN) {
|
||||||
@@ -3246,17 +3232,6 @@ static void f_hostname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
rettv->vval.v_string = xstrdup(hostname);
|
rettv->vval.v_string = xstrdup(hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "indent()" function
|
|
||||||
static void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|
||||||
{
|
|
||||||
const linenr_T lnum = tv_get_lnum(argvars);
|
|
||||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
|
||||||
rettv->vval.v_number = get_indent_lnum(lnum);
|
|
||||||
} else {
|
|
||||||
rettv->vval.v_number = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// "index()" function
|
/// "index()" function
|
||||||
static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
{
|
{
|
||||||
@@ -4415,20 +4390,6 @@ static void f_line2byte(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "lispindent(lnum)" function
|
|
||||||
static void f_lispindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|
||||||
{
|
|
||||||
const pos_T pos = curwin->w_cursor;
|
|
||||||
const linenr_T lnum = tv_get_lnum(argvars);
|
|
||||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
|
||||||
curwin->w_cursor.lnum = lnum;
|
|
||||||
rettv->vval.v_number = get_lisp_indent();
|
|
||||||
curwin->w_cursor = pos;
|
|
||||||
} else {
|
|
||||||
rettv->vval.v_number = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// "localtime()" function
|
/// "localtime()" function
|
||||||
static void f_localtime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
static void f_localtime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
{
|
{
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include "nvim/edit.h"
|
#include "nvim/edit.h"
|
||||||
#include "nvim/errors.h"
|
#include "nvim/errors.h"
|
||||||
#include "nvim/eval.h"
|
#include "nvim/eval.h"
|
||||||
|
#include "nvim/eval/typval.h"
|
||||||
#include "nvim/eval/typval_defs.h"
|
#include "nvim/eval/typval_defs.h"
|
||||||
#include "nvim/ex_cmds_defs.h"
|
#include "nvim/ex_cmds_defs.h"
|
||||||
#include "nvim/ex_docmd.h"
|
#include "nvim/ex_docmd.h"
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
|
#include "nvim/ops.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/option_defs.h"
|
#include "nvim/option_defs.h"
|
||||||
#include "nvim/option_vars.h"
|
#include "nvim/option_vars.h"
|
||||||
@@ -276,7 +278,7 @@ void tabstop_fromto(colnr_T start_col, colnr_T end_col, int ts_arg, const colnr_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// See if two tabstop arrays contain the same values.
|
/// See if two tabstop arrays contain the same values.
|
||||||
bool tabstop_eq(const colnr_T *ts1, const colnr_T *ts2)
|
static bool tabstop_eq(const colnr_T *ts1, const colnr_T *ts2)
|
||||||
{
|
{
|
||||||
if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0)) {
|
if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -977,12 +979,482 @@ bool inindent(int extra)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle reindenting a block of lines.
|
||||||
|
void op_reindent(oparg_T *oap, Indenter how)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
linenr_T first_changed = 0;
|
||||||
|
linenr_T last_changed = 0;
|
||||||
|
linenr_T start_lnum = curwin->w_cursor.lnum;
|
||||||
|
|
||||||
|
// Don't even try when 'modifiable' is off.
|
||||||
|
if (!MODIFIABLE(curbuf)) {
|
||||||
|
emsg(_(e_modifiable));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save for undo. Do this once for all lines, much faster than doing this
|
||||||
|
// for each line separately, especially when undoing.
|
||||||
|
if (u_savecommon(curbuf, start_lnum - 1, start_lnum + oap->line_count,
|
||||||
|
start_lnum + oap->line_count, false) == OK) {
|
||||||
|
int amount;
|
||||||
|
for (i = oap->line_count - 1; i >= 0 && !got_int; i--) {
|
||||||
|
// it's a slow thing to do, so give feedback so there's no worry
|
||||||
|
// that the computer's just hung.
|
||||||
|
|
||||||
|
if (i > 1
|
||||||
|
&& (i % 50 == 0 || i == oap->line_count - 1)
|
||||||
|
&& oap->line_count > p_report) {
|
||||||
|
smsg(0, _("%" PRId64 " lines to indent... "), (int64_t)i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Be vi-compatible: For lisp indenting the first line is not
|
||||||
|
// indented, unless there is only one line.
|
||||||
|
if (i != oap->line_count - 1 || oap->line_count == 1
|
||||||
|
|| how != get_lisp_indent) {
|
||||||
|
char *l = skipwhite(get_cursor_line_ptr());
|
||||||
|
if (*l == NUL) { // empty or blank line
|
||||||
|
amount = 0;
|
||||||
|
} else {
|
||||||
|
amount = how(); // get the indent for this line
|
||||||
|
}
|
||||||
|
if (amount >= 0 && set_indent(amount, 0)) {
|
||||||
|
// did change the indent, call changed_lines() later
|
||||||
|
if (first_changed == 0) {
|
||||||
|
first_changed = curwin->w_cursor.lnum;
|
||||||
|
}
|
||||||
|
last_changed = curwin->w_cursor.lnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curwin->w_cursor.lnum++;
|
||||||
|
curwin->w_cursor.col = 0; // make sure it's valid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// put cursor on first non-blank of indented line
|
||||||
|
curwin->w_cursor.lnum = start_lnum;
|
||||||
|
beginline(BL_SOL | BL_FIX);
|
||||||
|
|
||||||
|
// Mark changed lines so that they will be redrawn. When Visual
|
||||||
|
// highlighting was present, need to continue until the last line. When
|
||||||
|
// there is no change still need to remove the Visual highlighting.
|
||||||
|
if (last_changed != 0) {
|
||||||
|
changed_lines(curbuf, first_changed, 0,
|
||||||
|
oap->is_VIsual ? start_lnum + oap->line_count
|
||||||
|
: last_changed + 1, 0, true);
|
||||||
|
} else if (oap->is_VIsual) {
|
||||||
|
redraw_curbuf_later(UPD_INVERTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oap->line_count > p_report) {
|
||||||
|
i = oap->line_count - (i + 1);
|
||||||
|
smsg(0, NGETTEXT("%" PRId64 " line indented ", "%" PRId64 " lines indented ", i), (int64_t)i);
|
||||||
|
}
|
||||||
|
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
|
||||||
|
// set '[ and '] marks
|
||||||
|
curbuf->b_op_start = oap->start;
|
||||||
|
curbuf->b_op_end = oap->end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @return true if lines starting with '#' should be left aligned.
|
||||||
|
bool preprocs_left(void)
|
||||||
|
{
|
||||||
|
return ((curbuf->b_p_si && !curbuf->b_p_cin)
|
||||||
|
|| (curbuf->b_p_cin && in_cinkeys('#', ' ', true)
|
||||||
|
&& curbuf->b_ind_hash_comment == 0));
|
||||||
|
}
|
||||||
|
|
||||||
/// @return true if the conditions are OK for smart indenting.
|
/// @return true if the conditions are OK for smart indenting.
|
||||||
bool may_do_si(void)
|
bool may_do_si(void)
|
||||||
{
|
{
|
||||||
return curbuf->b_p_si && !curbuf->b_p_cin && *curbuf->b_p_inde == NUL && !p_paste;
|
return curbuf->b_p_si && !curbuf->b_p_cin && *curbuf->b_p_inde == NUL && !p_paste;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to do some very smart auto-indenting.
|
||||||
|
// Used when inserting a "normal" character.
|
||||||
|
void ins_try_si(int c)
|
||||||
|
{
|
||||||
|
pos_T *pos;
|
||||||
|
|
||||||
|
// do some very smart indenting when entering '{' or '}'
|
||||||
|
if (((did_si || can_si_back) && c == '{') || (can_si && c == '}' && inindent(0))) {
|
||||||
|
pos_T old_pos;
|
||||||
|
char *ptr;
|
||||||
|
int i;
|
||||||
|
bool temp;
|
||||||
|
// for '}' set indent equal to indent of line containing matching '{'
|
||||||
|
if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) {
|
||||||
|
old_pos = curwin->w_cursor;
|
||||||
|
// If the matching '{' has a ')' immediately before it (ignoring
|
||||||
|
// white-space), then line up with the start of the line
|
||||||
|
// containing the matching '(' if there is one. This handles the
|
||||||
|
// case where an "if (..\n..) {" statement continues over multiple
|
||||||
|
// lines -- webb
|
||||||
|
ptr = ml_get(pos->lnum);
|
||||||
|
i = pos->col;
|
||||||
|
if (i > 0) { // skip blanks before '{'
|
||||||
|
while (--i > 0 && ascii_iswhite(ptr[i])) {}
|
||||||
|
}
|
||||||
|
curwin->w_cursor.lnum = pos->lnum;
|
||||||
|
curwin->w_cursor.col = i;
|
||||||
|
if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) {
|
||||||
|
curwin->w_cursor = *pos;
|
||||||
|
}
|
||||||
|
i = get_indent();
|
||||||
|
curwin->w_cursor = old_pos;
|
||||||
|
if (State & VREPLACE_FLAG) {
|
||||||
|
change_indent(INDENT_SET, i, false, true);
|
||||||
|
} else {
|
||||||
|
set_indent(i, SIN_CHANGED);
|
||||||
|
}
|
||||||
|
} else if (curwin->w_cursor.col > 0) {
|
||||||
|
// when inserting '{' after "O" reduce indent, but not
|
||||||
|
// more than indent of previous line
|
||||||
|
temp = true;
|
||||||
|
if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) {
|
||||||
|
old_pos = curwin->w_cursor;
|
||||||
|
i = get_indent();
|
||||||
|
while (curwin->w_cursor.lnum > 1) {
|
||||||
|
ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
|
||||||
|
|
||||||
|
// ignore empty lines and lines starting with '#'.
|
||||||
|
if (*ptr != '#' && *ptr != NUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (get_indent() >= i) {
|
||||||
|
temp = false;
|
||||||
|
}
|
||||||
|
curwin->w_cursor = old_pos;
|
||||||
|
}
|
||||||
|
if (temp) {
|
||||||
|
shift_line(true, false, 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set indent of '#' always to 0
|
||||||
|
if (curwin->w_cursor.col > 0 && can_si && c == '#' && inindent(0)) {
|
||||||
|
// remember current indent for next line
|
||||||
|
old_indent = get_indent();
|
||||||
|
set_indent(0, SIN_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust ai_col, the char at this position can be deleted.
|
||||||
|
ai_col = MIN(ai_col, curwin->w_cursor.col);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
|
||||||
|
/// Keep the cursor on the same character.
|
||||||
|
/// type == INDENT_INC increase indent (for CTRL-T or <Tab>)
|
||||||
|
/// type == INDENT_DEC decrease indent (for CTRL-D)
|
||||||
|
/// type == INDENT_SET set indent to "amount"
|
||||||
|
///
|
||||||
|
/// @param round if true, round the indent to 'shiftwidth' (only with _INC and _Dec).
|
||||||
|
/// @param call_changed_bytes call changed_bytes()
|
||||||
|
void change_indent(int type, int amount, int round, bool call_changed_bytes)
|
||||||
|
{
|
||||||
|
int insstart_less; // reduction for Insstart.col
|
||||||
|
colnr_T orig_col = 0; // init for GCC
|
||||||
|
char *orig_line = NULL; // init for GCC
|
||||||
|
|
||||||
|
// MODE_VREPLACE state needs to know what the line was like before changing
|
||||||
|
if (State & VREPLACE_FLAG) {
|
||||||
|
orig_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
|
||||||
|
orig_col = curwin->w_cursor.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for the following tricks we don't want list mode
|
||||||
|
int save_p_list = curwin->w_p_list;
|
||||||
|
curwin->w_p_list = false;
|
||||||
|
colnr_T vc = getvcol_nolist(&curwin->w_cursor);
|
||||||
|
int vcol = vc;
|
||||||
|
|
||||||
|
// For Replace mode we need to fix the replace stack later, which is only
|
||||||
|
// possible when the cursor is in the indent. Remember the number of
|
||||||
|
// characters before the cursor if it's possible.
|
||||||
|
int start_col = curwin->w_cursor.col;
|
||||||
|
|
||||||
|
// determine offset from first non-blank
|
||||||
|
int new_cursor_col = curwin->w_cursor.col;
|
||||||
|
beginline(BL_WHITE);
|
||||||
|
new_cursor_col -= curwin->w_cursor.col;
|
||||||
|
|
||||||
|
insstart_less = curwin->w_cursor.col;
|
||||||
|
|
||||||
|
// If the cursor is in the indent, compute how many screen columns the
|
||||||
|
// cursor is to the left of the first non-blank.
|
||||||
|
if (new_cursor_col < 0) {
|
||||||
|
vcol = get_indent() - vcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_cursor_col > 0) { // can't fix replace stack
|
||||||
|
start_col = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the new indent. The cursor will be put on the first non-blank.
|
||||||
|
if (type == INDENT_SET) {
|
||||||
|
set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
|
||||||
|
} else {
|
||||||
|
int save_State = State;
|
||||||
|
|
||||||
|
// Avoid being called recursively.
|
||||||
|
if (State & VREPLACE_FLAG) {
|
||||||
|
State = MODE_INSERT;
|
||||||
|
}
|
||||||
|
shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
|
||||||
|
State = save_State;
|
||||||
|
}
|
||||||
|
insstart_less -= curwin->w_cursor.col;
|
||||||
|
|
||||||
|
// Try to put cursor on same character.
|
||||||
|
// If the cursor is at or after the first non-blank in the line,
|
||||||
|
// compute the cursor column relative to the column of the first
|
||||||
|
// non-blank character.
|
||||||
|
// If we are not in insert mode, leave the cursor on the first non-blank.
|
||||||
|
// If the cursor is before the first non-blank, position it relative
|
||||||
|
// to the first non-blank, counted in screen columns.
|
||||||
|
if (new_cursor_col >= 0) {
|
||||||
|
// When changing the indent while the cursor is touching it, reset
|
||||||
|
// Insstart_col to 0.
|
||||||
|
if (new_cursor_col == 0) {
|
||||||
|
insstart_less = MAXCOL;
|
||||||
|
}
|
||||||
|
new_cursor_col += curwin->w_cursor.col;
|
||||||
|
} else if (!(State & MODE_INSERT)) {
|
||||||
|
new_cursor_col = curwin->w_cursor.col;
|
||||||
|
} else {
|
||||||
|
// Compute the screen column where the cursor should be.
|
||||||
|
vcol = get_indent() - vcol;
|
||||||
|
int const end_vcol = (colnr_T)((vcol < 0) ? 0 : vcol);
|
||||||
|
curwin->w_virtcol = end_vcol;
|
||||||
|
|
||||||
|
// Advance the cursor until we reach the right screen column.
|
||||||
|
new_cursor_col = 0;
|
||||||
|
char *const line = get_cursor_line_ptr();
|
||||||
|
vcol = 0;
|
||||||
|
if (*line != NUL) {
|
||||||
|
CharsizeArg csarg;
|
||||||
|
CSType cstype = init_charsize_arg(&csarg, curwin, 0, line);
|
||||||
|
StrCharInfo ci = utf_ptr2StrCharInfo(line);
|
||||||
|
while (true) {
|
||||||
|
int next_vcol = vcol + win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width;
|
||||||
|
if (next_vcol > end_vcol) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vcol = next_vcol;
|
||||||
|
ci = utfc_next(ci);
|
||||||
|
if (*ci.ptr == NUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_cursor_col = (int)(ci.ptr - line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// May need to insert spaces to be able to position the cursor on
|
||||||
|
// the right screen column.
|
||||||
|
if (vcol != (int)curwin->w_virtcol) {
|
||||||
|
curwin->w_cursor.col = (colnr_T)new_cursor_col;
|
||||||
|
const size_t ptrlen = (size_t)(curwin->w_virtcol - vcol);
|
||||||
|
char *ptr = xmallocz(ptrlen);
|
||||||
|
memset(ptr, ' ', ptrlen);
|
||||||
|
new_cursor_col += (int)ptrlen;
|
||||||
|
ins_str(ptr, ptrlen);
|
||||||
|
xfree(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When changing the indent while the cursor is in it, reset
|
||||||
|
// Insstart_col to 0.
|
||||||
|
insstart_less = MAXCOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
curwin->w_p_list = save_p_list;
|
||||||
|
curwin->w_cursor.col = MAX(0, (colnr_T)new_cursor_col);
|
||||||
|
curwin->w_set_curswant = true;
|
||||||
|
changed_cline_bef_curs(curwin);
|
||||||
|
|
||||||
|
// May have to adjust the start of the insert.
|
||||||
|
if (State & MODE_INSERT) {
|
||||||
|
if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) {
|
||||||
|
if ((int)Insstart.col <= insstart_less) {
|
||||||
|
Insstart.col = 0;
|
||||||
|
} else {
|
||||||
|
Insstart.col -= insstart_less;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((int)ai_col <= insstart_less) {
|
||||||
|
ai_col = 0;
|
||||||
|
} else {
|
||||||
|
ai_col -= insstart_less;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For MODE_REPLACE state, may have to fix the replace stack, if it's
|
||||||
|
// possible. If the number of characters before the cursor decreased, need
|
||||||
|
// to pop a few characters from the replace stack.
|
||||||
|
// If the number of characters before the cursor increased, need to push a
|
||||||
|
// few NULs onto the replace stack.
|
||||||
|
if (REPLACE_NORMAL(State) && start_col >= 0) {
|
||||||
|
while (start_col > (int)curwin->w_cursor.col) {
|
||||||
|
replace_join(0); // remove a NUL from the replace stack
|
||||||
|
start_col--;
|
||||||
|
}
|
||||||
|
while (start_col < (int)curwin->w_cursor.col) {
|
||||||
|
replace_push_nul();
|
||||||
|
start_col++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For MODE_VREPLACE state, we also have to fix the replace stack. In this
|
||||||
|
// case it is always possible because we backspace over the whole line and
|
||||||
|
// then put it back again the way we wanted it.
|
||||||
|
if (State & VREPLACE_FLAG) {
|
||||||
|
// Save new line
|
||||||
|
char *new_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
|
||||||
|
|
||||||
|
// We only put back the new line up to the cursor
|
||||||
|
new_line[curwin->w_cursor.col] = NUL;
|
||||||
|
int new_col = curwin->w_cursor.col;
|
||||||
|
|
||||||
|
// Put back original line
|
||||||
|
ml_replace(curwin->w_cursor.lnum, orig_line, false);
|
||||||
|
curwin->w_cursor.col = orig_col;
|
||||||
|
|
||||||
|
curbuf_splice_pending++;
|
||||||
|
|
||||||
|
// Backspace from cursor to start of line
|
||||||
|
backspace_until_column(0);
|
||||||
|
|
||||||
|
// Insert new stuff into line again
|
||||||
|
ins_bytes(new_line);
|
||||||
|
|
||||||
|
xfree(new_line);
|
||||||
|
|
||||||
|
curbuf_splice_pending--;
|
||||||
|
|
||||||
|
// TODO(bfredl): test for crazy edge cases, like we stand on a TAB or
|
||||||
|
// something? does this even do the right text change then?
|
||||||
|
int delta = orig_col - new_col;
|
||||||
|
extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1, new_col,
|
||||||
|
delta < 0 ? -delta : 0,
|
||||||
|
delta > 0 ? delta : 0,
|
||||||
|
kExtmarkUndo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy the indent from ptr to the current line (and fill to size).
|
||||||
|
/// Leaves the cursor on the first non-blank in the line.
|
||||||
|
///
|
||||||
|
/// @return true if the line was changed.
|
||||||
|
bool copy_indent(int size, char *src)
|
||||||
|
{
|
||||||
|
char *p = NULL;
|
||||||
|
char *line = NULL;
|
||||||
|
int ind_len;
|
||||||
|
int line_len = 0;
|
||||||
|
int tab_pad;
|
||||||
|
|
||||||
|
// Round 1: compute the number of characters needed for the indent
|
||||||
|
// Round 2: copy the characters.
|
||||||
|
for (int round = 1; round <= 2; round++) {
|
||||||
|
int todo = size;
|
||||||
|
ind_len = 0;
|
||||||
|
int ind_done = 0;
|
||||||
|
int ind_col = 0;
|
||||||
|
char *s = src;
|
||||||
|
|
||||||
|
// Count/copy the usable portion of the source line.
|
||||||
|
while (todo > 0 && ascii_iswhite(*s)) {
|
||||||
|
if (*s == TAB) {
|
||||||
|
tab_pad = tabstop_padding(ind_done,
|
||||||
|
curbuf->b_p_ts,
|
||||||
|
curbuf->b_p_vts_array);
|
||||||
|
|
||||||
|
// Stop if this tab will overshoot the target.
|
||||||
|
if (todo < tab_pad) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
todo -= tab_pad;
|
||||||
|
ind_done += tab_pad;
|
||||||
|
ind_col += tab_pad;
|
||||||
|
} else {
|
||||||
|
todo--;
|
||||||
|
ind_done++;
|
||||||
|
ind_col++;
|
||||||
|
}
|
||||||
|
ind_len++;
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
*p++ = *s;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill to next tabstop with a tab, if possible.
|
||||||
|
tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts, curbuf->b_p_vts_array);
|
||||||
|
|
||||||
|
if ((todo >= tab_pad) && !curbuf->b_p_et) {
|
||||||
|
todo -= tab_pad;
|
||||||
|
ind_len++;
|
||||||
|
ind_col += tab_pad;
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
*p++ = TAB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add tabs required for indent.
|
||||||
|
if (!curbuf->b_p_et) {
|
||||||
|
while (true) {
|
||||||
|
tab_pad = tabstop_padding(ind_col,
|
||||||
|
curbuf->b_p_ts,
|
||||||
|
curbuf->b_p_vts_array);
|
||||||
|
if (todo < tab_pad) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
todo -= tab_pad;
|
||||||
|
ind_len++;
|
||||||
|
ind_col += tab_pad;
|
||||||
|
if (p != NULL) {
|
||||||
|
*p++ = TAB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count/add spaces required for indent.
|
||||||
|
while (todo > 0) {
|
||||||
|
todo--;
|
||||||
|
ind_len++;
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
*p++ = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == NULL) {
|
||||||
|
// Allocate memory for the result: the copied indent, new indent
|
||||||
|
// and the rest of the line.
|
||||||
|
line_len = get_cursor_line_len() + 1;
|
||||||
|
assert(ind_len + line_len >= 0);
|
||||||
|
size_t line_size;
|
||||||
|
STRICT_ADD(ind_len, line_len, &line_size, size_t);
|
||||||
|
line = xmalloc(line_size);
|
||||||
|
p = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the original line
|
||||||
|
memmove(p, get_cursor_line_ptr(), (size_t)line_len);
|
||||||
|
|
||||||
|
// Replace the line
|
||||||
|
ml_replace(curwin->w_cursor.lnum, line, false);
|
||||||
|
|
||||||
|
// Put the cursor after the indent.
|
||||||
|
curwin->w_cursor.col = ind_len;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Give a "resulting text too long" error and maybe set got_int.
|
/// Give a "resulting text too long" error and maybe set got_int.
|
||||||
static void emsg_text_too_long(void)
|
static void emsg_text_too_long(void)
|
||||||
{
|
{
|
||||||
@@ -1474,3 +1946,28 @@ void fix_indent(void)
|
|||||||
do_c_expr_indent();
|
do_c_expr_indent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// "indent()" function
|
||||||
|
void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
|
{
|
||||||
|
const linenr_T lnum = tv_get_lnum(argvars);
|
||||||
|
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||||
|
rettv->vval.v_number = get_indent_lnum(lnum);
|
||||||
|
} else {
|
||||||
|
rettv->vval.v_number = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "lispindent(lnum)" function
|
||||||
|
void f_lispindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
|
{
|
||||||
|
const pos_T pos = curwin->w_cursor;
|
||||||
|
const linenr_T lnum = tv_get_lnum(argvars);
|
||||||
|
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||||
|
curwin->w_cursor.lnum = lnum;
|
||||||
|
rettv->vval.v_number = get_lisp_indent();
|
||||||
|
curwin->w_cursor = pos;
|
||||||
|
} else {
|
||||||
|
rettv->vval.v_number = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
|
#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
|
||||||
|
#include "nvim/normal_defs.h"
|
||||||
#include "nvim/pos_defs.h" // IWYU pragma: keep
|
#include "nvim/pos_defs.h" // IWYU pragma: keep
|
||||||
#include "nvim/types_defs.h" // IWYU pragma: keep
|
#include "nvim/types_defs.h" // IWYU pragma: keep
|
||||||
|
|
||||||
@@ -14,6 +15,8 @@ enum {
|
|||||||
SIN_NOMARK = 8, ///< don't adjust extmarks
|
SIN_NOMARK = 8, ///< don't adjust extmarks
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef int (*Indenter)(void);
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "indent.h.generated.h"
|
# include "indent.h.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
#include "nvim/edit.h"
|
#include "nvim/edit.h"
|
||||||
|
#include "nvim/eval/typval.h"
|
||||||
#include "nvim/globals.h"
|
#include "nvim/globals.h"
|
||||||
#include "nvim/indent.h"
|
#include "nvim/indent.h"
|
||||||
#include "nvim/indent_c.h"
|
#include "nvim/indent_c.h"
|
||||||
@@ -3932,3 +3933,17 @@ void do_c_expr_indent(void)
|
|||||||
fixthisline(get_c_indent);
|
fixthisline(get_c_indent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// "cindent(lnum)" function
|
||||||
|
void f_cindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
|
{
|
||||||
|
pos_T pos = curwin->w_cursor;
|
||||||
|
linenr_T lnum = tv_get_lnum(argvars);
|
||||||
|
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||||
|
curwin->w_cursor.lnum = lnum;
|
||||||
|
rettv->vval.v_number = get_c_indent();
|
||||||
|
curwin->w_cursor = pos;
|
||||||
|
} else {
|
||||||
|
rettv->vval.v_number = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvim/eval/typval_defs.h"
|
||||||
#include "nvim/pos_defs.h" // IWYU pragma: keep
|
#include "nvim/pos_defs.h" // IWYU pragma: keep
|
||||||
#include "nvim/types_defs.h" // IWYU pragma: keep
|
#include "nvim/types_defs.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
@@ -723,84 +723,6 @@ static void block_insert(oparg_T *oap, const char *s, size_t slen, bool b_insert
|
|||||||
changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0, true);
|
changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle reindenting a block of lines.
|
|
||||||
void op_reindent(oparg_T *oap, Indenter how)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
linenr_T first_changed = 0;
|
|
||||||
linenr_T last_changed = 0;
|
|
||||||
linenr_T start_lnum = curwin->w_cursor.lnum;
|
|
||||||
|
|
||||||
// Don't even try when 'modifiable' is off.
|
|
||||||
if (!MODIFIABLE(curbuf)) {
|
|
||||||
emsg(_(e_modifiable));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save for undo. Do this once for all lines, much faster than doing this
|
|
||||||
// for each line separately, especially when undoing.
|
|
||||||
if (u_savecommon(curbuf, start_lnum - 1, start_lnum + oap->line_count,
|
|
||||||
start_lnum + oap->line_count, false) == OK) {
|
|
||||||
int amount;
|
|
||||||
for (i = oap->line_count - 1; i >= 0 && !got_int; i--) {
|
|
||||||
// it's a slow thing to do, so give feedback so there's no worry
|
|
||||||
// that the computer's just hung.
|
|
||||||
|
|
||||||
if (i > 1
|
|
||||||
&& (i % 50 == 0 || i == oap->line_count - 1)
|
|
||||||
&& oap->line_count > p_report) {
|
|
||||||
smsg(0, _("%" PRId64 " lines to indent... "), (int64_t)i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Be vi-compatible: For lisp indenting the first line is not
|
|
||||||
// indented, unless there is only one line.
|
|
||||||
if (i != oap->line_count - 1 || oap->line_count == 1
|
|
||||||
|| how != get_lisp_indent) {
|
|
||||||
char *l = skipwhite(get_cursor_line_ptr());
|
|
||||||
if (*l == NUL) { // empty or blank line
|
|
||||||
amount = 0;
|
|
||||||
} else {
|
|
||||||
amount = how(); // get the indent for this line
|
|
||||||
}
|
|
||||||
if (amount >= 0 && set_indent(amount, 0)) {
|
|
||||||
// did change the indent, call changed_lines() later
|
|
||||||
if (first_changed == 0) {
|
|
||||||
first_changed = curwin->w_cursor.lnum;
|
|
||||||
}
|
|
||||||
last_changed = curwin->w_cursor.lnum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
curwin->w_cursor.lnum++;
|
|
||||||
curwin->w_cursor.col = 0; // make sure it's valid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// put cursor on first non-blank of indented line
|
|
||||||
curwin->w_cursor.lnum = start_lnum;
|
|
||||||
beginline(BL_SOL | BL_FIX);
|
|
||||||
|
|
||||||
// Mark changed lines so that they will be redrawn. When Visual
|
|
||||||
// highlighting was present, need to continue until the last line. When
|
|
||||||
// there is no change still need to remove the Visual highlighting.
|
|
||||||
if (last_changed != 0) {
|
|
||||||
changed_lines(curbuf, first_changed, 0,
|
|
||||||
oap->is_VIsual ? start_lnum + oap->line_count
|
|
||||||
: last_changed + 1, 0, true);
|
|
||||||
} else if (oap->is_VIsual) {
|
|
||||||
redraw_curbuf_later(UPD_INVERTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oap->line_count > p_report) {
|
|
||||||
i = oap->line_count - (i + 1);
|
|
||||||
smsg(0, NGETTEXT("%" PRId64 " line indented ", "%" PRId64 " lines indented ", i), (int64_t)i);
|
|
||||||
}
|
|
||||||
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
|
|
||||||
// set '[ and '] marks
|
|
||||||
curbuf->b_op_start = oap->start;
|
|
||||||
curbuf->b_op_end = oap->end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the last expression line here, for repeating.
|
// Keep the last expression line here, for repeating.
|
||||||
static char *expr_line = NULL;
|
static char *expr_line = NULL;
|
||||||
|
|
||||||
@@ -3738,14 +3660,6 @@ void adjust_cursor_eol(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return true if lines starting with '#' should be left aligned.
|
|
||||||
bool preprocs_left(void)
|
|
||||||
{
|
|
||||||
return ((curbuf->b_p_si && !curbuf->b_p_cin)
|
|
||||||
|| (curbuf->b_p_cin && in_cinkeys('#', ' ', true)
|
|
||||||
&& curbuf->b_ind_hash_comment == 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @return the character name of the register with the given number
|
/// @return the character name of the register with the given number
|
||||||
int get_register_name(int num)
|
int get_register_name(int num)
|
||||||
{
|
{
|
||||||
|
@@ -33,8 +33,6 @@ struct block_def {
|
|||||||
colnr_T start_char_vcols; ///< number of vcols of pre-block char
|
colnr_T start_char_vcols; ///< number of vcols of pre-block char
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*Indenter)(void);
|
|
||||||
|
|
||||||
/// flags for do_put()
|
/// flags for do_put()
|
||||||
enum {
|
enum {
|
||||||
PUT_FIXINDENT = 1, ///< make indent look nice
|
PUT_FIXINDENT = 1, ///< make indent look nice
|
||||||
|
Reference in New Issue
Block a user