static int coladvance2( pos_T *pos, bool addspaces, /* change the text to achieve our goal? */ bool finetune, /* change char offset for the exact column */ colnr_T wcol /* column to move to */ ) { int idx; char_u *ptr; char_u *line; colnr_T col = 0; int csize = 0; int one_more; int head = 0; one_more = (State & INSERT) || restart_edit != NUL || (VIsual_active && *p_sel != 'o') || ((ve_flags & VE_ONEMORE) && wcol < MAXCOL); line = ml_get_buf(curbuf, pos->lnum, false); if (wcol >= MAXCOL) { idx = (int)STRLEN(line) - 1 + one_more; col = wcol; if ((addspaces || finetune) && !VIsual_active) { curwin->w_curswant = linetabsize(line) + one_more; if (curwin->w_curswant > 0) --curwin->w_curswant; } } else { int width = curwin->w_width - win_col_off(curwin); if (finetune && curwin->w_p_wrap && curwin->w_width != 0 && wcol >= (colnr_T)width) { csize = linetabsize(line); if (csize > 0) csize--; if (wcol / width > (colnr_T)csize / width && ((State & INSERT) == 0 || (int)wcol > csize + 1)) { /* In case of line wrapping don't move the cursor beyond the * right screen edge. In Insert mode allow going just beyond * the last character (like what happens when typing and * reaching the right window edge). */ wcol = (csize / width + 1) * width - 1; } } ptr = line; while (col <= wcol && *ptr != NUL) { /* Count a tab for what it's worth (if list mode not on) */ csize = win_lbr_chartabsize(curwin, line, ptr, col, &head); MB_PTR_ADV(ptr); col += csize; } idx = (int)(ptr - line); /* * Handle all the special cases. The virtual_active() check * is needed to ensure that a virtual position off the end of * a line has the correct indexing. The one_more comparison * replaces an explicit add of one_more later on. */ if (col > wcol || (!virtual_active() && one_more == 0)) { idx -= 1; /* Don't count the chars from 'showbreak'. */ csize -= head; col -= csize; } if (virtual_active() && addspaces && ((col != wcol && col != wcol + 1) || csize > 1)) { /* 'virtualedit' is set: The difference between wcol and col is * filled with spaces. */ if (line[idx] == NUL) { /* Append spaces */ int correct = wcol - col; char_u *newline = xmallocz((size_t)(idx + correct)); memcpy(newline, line, (size_t)idx); memset(newline + idx, ' ', (size_t)correct); ml_replace(pos->lnum, newline, false); changed_bytes(pos->lnum, (colnr_T)idx); idx += correct; col = wcol; } else { /* Break a tab */ int linelen = (int)STRLEN(line); int correct = wcol - col - csize + 1; /* negative!! */ char_u *newline; if (-correct > csize) return FAIL; newline = xmallocz((size_t)(linelen - 1 + csize)); // Copy first idx chars memcpy(newline, line, (size_t)idx); // Replace idx'th char with csize spaces memset(newline + idx, ' ', (size_t)csize); // Copy the rest of the line memcpy(newline + idx + csize, line + idx + 1, (size_t)(linelen - idx - 1)); ml_replace(pos->lnum, newline, false); changed_bytes(pos->lnum, idx); idx += (csize - 1 + correct); col += correct; } } } if (idx < 0) pos->col = 0; else pos->col = idx; pos->coladd = 0; if (finetune) { if (wcol == MAXCOL) { /* The width of the last character is used to set coladd. */ if (!one_more) { colnr_T scol, ecol; getvcol(curwin, pos, &scol, NULL, &ecol); pos->coladd = ecol - scol; } } else { int b = (int)wcol - (int)col; /* The difference between wcol and col is used to set coladd. */ if (b > 0 && b < (MAXCOL - 2 * curwin->w_width)) pos->coladd = b; col += b; } } // Prevent from moving onto a trail byte. if (has_mbyte) { mark_mb_adjustpos(curbuf, pos); } if (col < wcol) return FAIL; return OK; }
// 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; }