// Set the indent of the current line. // Leaves the cursor on the first non-blank in the line. // Caller must take care of undo. // "flags": // SIN_CHANGED: call changed_bytes() if the line was changed. // SIN_INSERT: insert the indent in front of the line. // SIN_UNDO: save line for undo before changing it. // @param size measured in spaces // Returns true if the line was changed. int set_indent(int size, int flags) { char_u *p; char_u *newline; char_u *oldline; char_u *s; int todo; int ind_len; // Measured in characters. int line_len; int doit = false; int ind_done = 0; // Measured in spaces. int tab_pad; int retval = false; // Number of initial whitespace chars when 'et' and 'pi' are both set. int orig_char_len = -1; // First check if there is anything to do and compute the number of // characters needed for the indent. todo = size; ind_len = 0; p = oldline = ml_get_curline(); // Calculate the buffer size for the new indent, and check to see if it // isn't already set. // If 'expandtab' isn't set: use TABs; if both 'expandtab' and // 'preserveindent' are set count the number of characters at the // beginning of the line to be copied. if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi)) { // If 'preserveindent' is set then reuse as much as possible of // the existing indent structure for the new indent. if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { ind_done = 0; // Count as many characters as we can use. while (todo > 0 && vim_iswhite(*p)) { if (*p == TAB) { tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); // Stop if this tab will overshoot the target. if (todo < tab_pad) { break; } todo -= tab_pad; ind_len++; ind_done += tab_pad; } else { todo--; ind_len++; ind_done++; } p++; } // Set initial number of whitespace chars to copy if we are // preserving indent but expandtab is set. if (curbuf->b_p_et) { orig_char_len = ind_len; } // Fill to next tabstop with a tab, if possible. tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); if ((todo >= tab_pad) && (orig_char_len == -1)) { doit = true; todo -= tab_pad; ind_len++; // ind_done += tab_pad; } } // Count tabs required for indent. while (todo >= (int)curbuf->b_p_ts) { if (*p != TAB) { doit = true; } else { p++; } todo -= (int)curbuf->b_p_ts; ind_len++; // ind_done += (int)curbuf->b_p_ts; } } // Count spaces required for indent. while (todo > 0) { if (*p != ' ') { doit = true; } else { p++; } todo--; ind_len++; // ind_done++; } // Return if the indent is OK already. if (!doit && !vim_iswhite(*p) && !(flags & SIN_INSERT)) { return false; } // Allocate memory for the new line. if (flags & SIN_INSERT) { p = oldline; } else { p = skipwhite(p); } line_len = (int)STRLEN(p) + 1; // If 'preserveindent' and 'expandtab' are both set keep the original // characters and allocate accordingly. We will fill the rest with spaces // after the if (!curbuf->b_p_et) below. if (orig_char_len != -1) { newline = alloc(orig_char_len + size - ind_done + line_len); todo = size - ind_done; // Set total length of indent in characters, which may have been // undercounted until now. ind_len = orig_char_len + todo; p = oldline; s = newline; while (orig_char_len > 0) { *s++ = *p++; orig_char_len--; } // Skip over any additional white space (useful when newindent is less // than old). while (vim_iswhite(*p)) { p++; } } else { todo = size; newline = alloc(ind_len + line_len); s = newline; } // Put the characters in the new line. // if 'expandtab' isn't set: use TABs if (!curbuf->b_p_et) { // If 'preserveindent' is set then reuse as much as possible of // the existing indent structure for the new indent. if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { p = oldline; ind_done = 0; while (todo > 0 && vim_iswhite(*p)) { if (*p == TAB) { tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); // Stop if this tab will overshoot the target. if (todo < tab_pad) { break; } todo -= tab_pad; ind_done += tab_pad; } else { todo--; ind_done++; } *s++ = *p++; } // Fill to next tabstop with a tab, if possible. tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); if (todo >= tab_pad) { *s++ = TAB; todo -= tab_pad; } p = skipwhite(p); } while (todo >= (int)curbuf->b_p_ts) { *s++ = TAB; todo -= (int)curbuf->b_p_ts; } } while (todo > 0) { *s++ = ' '; todo--; } memmove(s, p, (size_t)line_len); // Replace the line (unless undo fails). if (!(flags & SIN_UNDO) || (u_savesub(curwin->w_cursor.lnum) == OK)) { ml_replace(curwin->w_cursor.lnum, newline, false); if (flags & SIN_CHANGED) { changed_bytes(curwin->w_cursor.lnum, 0); } // Correct saved cursor position if it is in this line. if (saved_cursor.lnum == curwin->w_cursor.lnum) { if (saved_cursor.col >= (colnr_T)(p - oldline)) { // Cursor was after the indent, adjust for the number of // bytes added/removed. saved_cursor.col += ind_len - (colnr_T)(p - oldline); } else if (saved_cursor.col >= (colnr_T)(s - newline)) { // Cursor was in the indent, and is now after it, put it back // at the start of the indent (replacing spaces with TAB). saved_cursor.col = (colnr_T)(s - newline); } } retval = true; } else { vim_free(newline); } curwin->w_cursor.col = ind_len; return retval; }
static int luaV_buffer_newindex(lua_State *L) { buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1); linenr_T n = (linenr_T) luaL_checkinteger(L, 2); #ifdef HAVE_SANDBOX luaV_checksandbox(L); #endif if (n < 1 || n > b->b_ml.ml_line_count) luaL_error(L, "invalid line number"); if (lua_isnil(L, 3)) /* delete line */ { buf_T *buf = curbuf; curbuf = b; if (u_savedel(n, 1L) == FAIL) { curbuf = buf; luaL_error(L, "cannot save undo information"); } else if (ml_delete(n, FALSE) == FAIL) { curbuf = buf; luaL_error(L, "cannot delete line"); } else { deleted_lines_mark(n, 1L); if (b == curwin->w_buffer) /* fix cursor in current window? */ { if (curwin->w_cursor.lnum >= n) { if (curwin->w_cursor.lnum > n) { curwin->w_cursor.lnum -= 1; check_cursor_col(); } else check_cursor(); changed_cline_bef_curs(); } invalidate_botline(); } } curbuf = buf; } else if (lua_isstring(L, 3)) /* update line */ { buf_T *buf = curbuf; curbuf = b; if (u_savesub(n) == FAIL) { curbuf = buf; luaL_error(L, "cannot save undo information"); } else if (ml_replace(n, luaV_toline(L, 3), TRUE) == FAIL) { curbuf = buf; luaL_error(L, "cannot replace line"); } else changed_bytes(n, 0); curbuf = buf; if (b == curwin->w_buffer) check_cursor_col(); } else luaL_error(L, "wrong argument to change line"); return 0; }