neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

indent.c (57911B)


      1 #include <assert.h>
      2 #include <stdbool.h>
      3 #include <stdint.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 
      7 #include "nvim/ascii_defs.h"
      8 #include "nvim/assert_defs.h"
      9 #include "nvim/buffer.h"
     10 #include "nvim/buffer_defs.h"
     11 #include "nvim/change.h"
     12 #include "nvim/charset.h"
     13 #include "nvim/cursor.h"
     14 #include "nvim/drawscreen.h"
     15 #include "nvim/edit.h"
     16 #include "nvim/errors.h"
     17 #include "nvim/eval.h"
     18 #include "nvim/eval/typval.h"
     19 #include "nvim/eval/typval_defs.h"
     20 #include "nvim/eval/vars.h"
     21 #include "nvim/ex_cmds_defs.h"
     22 #include "nvim/ex_docmd.h"
     23 #include "nvim/extmark.h"
     24 #include "nvim/extmark_defs.h"
     25 #include "nvim/gettext_defs.h"
     26 #include "nvim/globals.h"
     27 #include "nvim/indent.h"
     28 #include "nvim/indent_c.h"
     29 #include "nvim/mark_defs.h"
     30 #include "nvim/mbyte.h"
     31 #include "nvim/mbyte_defs.h"
     32 #include "nvim/memline.h"
     33 #include "nvim/memory.h"
     34 #include "nvim/message.h"
     35 #include "nvim/move.h"
     36 #include "nvim/ops.h"
     37 #include "nvim/option.h"
     38 #include "nvim/option_defs.h"
     39 #include "nvim/option_vars.h"
     40 #include "nvim/os/input.h"
     41 #include "nvim/plines.h"
     42 #include "nvim/pos_defs.h"
     43 #include "nvim/regexp.h"
     44 #include "nvim/regexp_defs.h"
     45 #include "nvim/search.h"
     46 #include "nvim/state_defs.h"
     47 #include "nvim/strings.h"
     48 #include "nvim/textformat.h"
     49 #include "nvim/types_defs.h"
     50 #include "nvim/undo.h"
     51 #include "nvim/vim_defs.h"
     52 
     53 #include "indent.c.generated.h"
     54 
     55 /// Set the integer values corresponding to the string setting of 'vartabstop'.
     56 /// "array" will be set, caller must free it if needed.
     57 ///
     58 /// @return  false for an error.
     59 bool tabstop_set(char *var, colnr_T **array)
     60 {
     61  int valcount = 1;
     62 
     63  if (var[0] == NUL || (var[0] == '0' && var[1] == NUL)) {
     64    *array = NULL;
     65    return true;
     66  }
     67 
     68  for (char *cp = var; *cp != NUL; cp++) {
     69    if (cp == var || cp[-1] == ',') {
     70      char *end;
     71 
     72      if (strtol(cp, &end, 10) <= 0) {
     73        if (cp != end) {
     74          emsg(_(e_positive));
     75        } else {
     76          semsg(_(e_invarg2), cp);
     77        }
     78        return false;
     79      }
     80    }
     81 
     82    if (ascii_isdigit(*cp)) {
     83      continue;
     84    }
     85    if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL) {
     86      valcount++;
     87      continue;
     88    }
     89    semsg(_(e_invarg2), var);
     90    return false;
     91  }
     92 
     93  *array = (colnr_T *)xmalloc((unsigned)(valcount + 1) * sizeof(int));
     94  (*array)[0] = (colnr_T)valcount;
     95 
     96  int t = 1;
     97  for (char *cp = var; *cp != NUL;) {
     98    int n = atoi(cp);
     99 
    100    // Catch negative values, overflow and ridiculous big values.
    101    if (n <= 0 || n > TABSTOP_MAX) {
    102      semsg(_(e_invarg2), cp);
    103      XFREE_CLEAR(*array);
    104      return false;
    105    }
    106    (*array)[t++] = n;
    107    while (*cp != NUL && *cp != ',') {
    108      cp++;
    109    }
    110    if (*cp != NUL) {
    111      cp++;
    112    }
    113  }
    114 
    115  return true;
    116 }
    117 
    118 /// Calculate the number of screen spaces a tab will occupy.
    119 /// If "vts" is set then the tab widths are taken from that array,
    120 /// otherwise the value of ts is used.
    121 int tabstop_padding(colnr_T col, OptInt ts_arg, const colnr_T *vts)
    122  FUNC_ATTR_PURE
    123 {
    124  OptInt ts = ts_arg == 0 ? 8 : ts_arg;
    125  colnr_T tabcol = 0;
    126  int t;
    127  int padding = 0;
    128 
    129  if (vts == NULL || vts[0] == 0) {
    130    return (int)(ts - (col % ts));
    131  }
    132 
    133  const int tabcount = vts[0];
    134 
    135  for (t = 1; t <= tabcount; t++) {
    136    tabcol += vts[t];
    137    if (tabcol > col) {
    138      padding = tabcol - col;
    139      break;
    140    }
    141  }
    142  if (t > tabcount) {
    143    padding = vts[tabcount] - ((col - tabcol) % vts[tabcount]);
    144  }
    145 
    146  return padding;
    147 }
    148 
    149 /// Find the size of the tab that covers a particular column.
    150 ///
    151 /// If this is being called as part of a shift operation, col is not the cursor
    152 /// column but is the column number to the left of the first non-whitespace
    153 /// character in the line.  If the shift is to the left (left == true), then
    154 /// return the size of the tab interval to the left of the column.
    155 int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts, bool left)
    156 {
    157  if (vts == NULL || vts[0] == 0) {
    158    return (int)ts;
    159  }
    160 
    161  colnr_T tabcol = 0;  // Column of the tab stop under consideration.
    162  int t;  // Tabstop index in the list of variable tab stops.
    163  int tab_size = 0;  // Size of the tab stop interval to the right or left of the col.
    164  const int tabcount  // Number of tab stops in the list of variable tab stops.
    165    = vts[0];
    166  for (t = 1; t <= tabcount; t++) {
    167    tabcol += vts[t];
    168    if (tabcol > col) {
    169      // If shifting left (left == true), and if the column to the left of
    170      // the first first non-blank character (col) in the line is
    171      // already to the left of the first tabstop, set the shift amount
    172      // (tab_size) to just enough to shift the line to the left margin.
    173      // The value doesn't seem to matter as long as it is at least that
    174      // distance.
    175      if (left && (t == 1)) {
    176        tab_size = col;
    177      } else {
    178        tab_size = vts[t - (left ? 1 : 0)];
    179      }
    180      break;
    181    }
    182  }
    183  if (t > tabcount) {  // If the value of the index t is beyond the
    184                       // end of the list, use the tab stop value at
    185                       // the end of the list.
    186    tab_size = vts[tabcount];
    187  }
    188 
    189  return tab_size;
    190 }
    191 
    192 /// Find the column on which a tab starts.
    193 colnr_T tabstop_start(colnr_T col, int ts, colnr_T *vts)
    194 {
    195  colnr_T tabcol = 0;
    196 
    197  if (vts == NULL || vts[0] == 0) {
    198    return col - col % ts;
    199  }
    200 
    201  const int tabcount = vts[0];
    202  for (int t = 1; t <= tabcount; t++) {
    203    tabcol += vts[t];
    204    if (tabcol > col) {
    205      return (tabcol - vts[t]);
    206    }
    207  }
    208 
    209  const int excess = (tabcol % vts[tabcount]);
    210  return col - (col - excess) % vts[tabcount];
    211 }
    212 
    213 /// Find the number of tabs and spaces necessary to get from one column
    214 /// to another.
    215 void tabstop_fromto(colnr_T start_col, colnr_T end_col, int ts_arg, const colnr_T *vts, int *ntabs,
    216                    int *nspcs)
    217 {
    218  int spaces = end_col - start_col;
    219  colnr_T tabcol = 0;
    220  int padding = 0;
    221  int t;
    222  int ts = ts_arg == 0 ? (int)curbuf->b_p_ts : ts_arg;
    223  assert(ts != 0);  // suppress clang "Division by zero"
    224 
    225  if (vts == NULL || vts[0] == 0) {
    226    int tabs = 0;
    227 
    228    const int initspc = (ts - (start_col % ts));
    229    if (spaces >= initspc) {
    230      spaces -= initspc;
    231      tabs++;
    232    }
    233    tabs += (spaces / ts);
    234    spaces -= ((spaces / ts) * ts);
    235 
    236    *ntabs = tabs;
    237    *nspcs = spaces;
    238    return;
    239  }
    240 
    241  // Find the padding needed to reach the next tabstop.
    242  const int tabcount = vts[0];
    243  for (t = 1; t <= tabcount; t++) {
    244    tabcol += vts[t];
    245    if (tabcol > start_col) {
    246      padding = tabcol - start_col;
    247      break;
    248    }
    249  }
    250  if (t > tabcount) {
    251    padding = vts[tabcount] - ((start_col - tabcol) % vts[tabcount]);
    252  }
    253 
    254  // If the space needed is less than the padding no tabs can be used.
    255  if (spaces < padding) {
    256    *ntabs = 0;
    257    *nspcs = spaces;
    258    return;
    259  }
    260 
    261  *ntabs = 1;
    262  spaces -= padding;
    263 
    264  // At least one tab has been used. See if any more will fit.
    265  while (spaces != 0 && ++t <= tabcount) {
    266    padding = vts[t];
    267    if (spaces < padding) {
    268      *nspcs = spaces;
    269      return;
    270    }
    271    *ntabs += 1;
    272    spaces -= padding;
    273  }
    274 
    275  *ntabs += spaces / (int)vts[tabcount];
    276  *nspcs = spaces % (int)vts[tabcount];
    277 }
    278 
    279 /// See if two tabstop arrays contain the same values.
    280 static bool tabstop_eq(const colnr_T *ts1, const colnr_T *ts2)
    281 {
    282  if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0)) {
    283    return false;
    284  }
    285  if (ts1 == ts2) {
    286    return true;
    287  }
    288  if (ts1[0] != ts2[0]) {
    289    return false;
    290  }
    291 
    292  for (int t = 1; t <= ts1[0]; t++) {
    293    if (ts1[t] != ts2[t]) {
    294      return false;
    295    }
    296  }
    297 
    298  return true;
    299 }
    300 
    301 /// Copy a tabstop array, allocating space for the new array.
    302 int *tabstop_copy(const int *oldts)
    303 {
    304  if (oldts == 0) {
    305    return 0;
    306  }
    307 
    308  int *newts = xmalloc((unsigned)(oldts[0] + 1) * sizeof(int));
    309  for (int t = 0; t <= oldts[0]; t++) {
    310    newts[t] = oldts[t];
    311  }
    312 
    313  return newts;
    314 }
    315 
    316 /// Return a count of the number of tabstops.
    317 int tabstop_count(colnr_T *ts)
    318 {
    319  return ts != NULL ? (int)ts[0] : 0;
    320 }
    321 
    322 /// Return the first tabstop, or 8 if there are no tabstops defined.
    323 int tabstop_first(colnr_T *ts)
    324 {
    325  return ts != NULL ? (int)ts[1] : 8;
    326 }
    327 
    328 /// Return the effective shiftwidth value for current buffer, using the
    329 /// 'tabstop' value when 'shiftwidth' is zero.
    330 int get_sw_value(buf_T *buf)
    331 {
    332  int result = get_sw_value_col(buf, 0, false);
    333  return result;
    334 }
    335 
    336 /// Idem, using "pos".
    337 static int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left)
    338 {
    339  pos_T save_cursor = curwin->w_cursor;
    340 
    341  curwin->w_cursor = *pos;
    342  int sw_value = get_sw_value_col(buf, get_nolist_virtcol(), left);
    343  curwin->w_cursor = save_cursor;
    344  return sw_value;
    345 }
    346 
    347 /// Idem, using the first non-black in the current line.
    348 int get_sw_value_indent(buf_T *buf, bool left)
    349 {
    350  pos_T pos = curwin->w_cursor;
    351 
    352  pos.col = (colnr_T)getwhitecols_curline();
    353  return get_sw_value_pos(buf, &pos, left);
    354 }
    355 
    356 /// Idem, using virtual column "col".
    357 int get_sw_value_col(buf_T *buf, colnr_T col, bool left)
    358 {
    359  return buf->b_p_sw ? (int)buf->b_p_sw
    360                     : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array, left);
    361 }
    362 
    363 /// Return the effective softtabstop value for the current buffer,
    364 /// using the shiftwidth  value when 'softtabstop' is negative.
    365 int get_sts_value(void)
    366 {
    367  int result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : (int)curbuf->b_p_sts;
    368  return result;
    369 }
    370 
    371 /// Count the size (in window cells) of the indent in the current line.
    372 int get_indent(void)
    373 {
    374  return indent_size_ts(get_cursor_line_ptr(), curbuf->b_p_ts, curbuf->b_p_vts_array);
    375 }
    376 
    377 /// Count the size (in window cells) of the indent in line "lnum".
    378 int get_indent_lnum(linenr_T lnum)
    379 {
    380  return indent_size_ts(ml_get(lnum), curbuf->b_p_ts, curbuf->b_p_vts_array);
    381 }
    382 
    383 /// Count the size (in window cells) of the indent in line "lnum" of buffer "buf".
    384 int get_indent_buf(buf_T *buf, linenr_T lnum)
    385 {
    386  return indent_size_ts(ml_get_buf(buf, lnum), buf->b_p_ts, buf->b_p_vts_array);
    387 }
    388 
    389 /// Compute the size of the indent (in window cells) in line "ptr",
    390 /// without tabstops (count tab as ^I or <09>).
    391 int indent_size_no_ts(char const *ptr)
    392  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
    393 {
    394  int tab_size = byte2cells(TAB);
    395 
    396  int vcol = 0;
    397  while (true) {
    398    char const c = *ptr++;
    399    if (c == ' ') {
    400      vcol++;
    401    } else if (c == TAB) {
    402      vcol += tab_size;
    403    } else {
    404      return vcol;
    405    }
    406  }
    407 }
    408 
    409 /// Compute the size of the indent (in window cells) in line "ptr",
    410 /// using tabstops
    411 int indent_size_ts(char const *ptr, OptInt ts, colnr_T *vts)
    412  FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_PURE
    413 {
    414  assert(char2cells(' ') == 1);
    415 
    416  int vcol = 0;
    417  int tabstop_width, next_tab_vcol;
    418 
    419  if (vts == NULL || vts[0] < 1) {  // tab has fixed width
    420    // can ts be 0 ? This is from tabstop_padding().
    421    tabstop_width = (int)(ts == 0 ? 8 : ts);
    422    next_tab_vcol = tabstop_width;
    423  } else {  // tab has variable width
    424    colnr_T *cur_tabstop = vts + 1;
    425    colnr_T *const last_tabstop = vts + vts[0];
    426 
    427    while (cur_tabstop != last_tabstop) {
    428      int cur_vcol = vcol;
    429      vcol += *cur_tabstop++;
    430      assert(cur_vcol < vcol);
    431 
    432      do {
    433        char const c = *ptr++;
    434        if (c == ' ') {
    435          cur_vcol++;
    436        } else if (c == TAB) {
    437          break;
    438        } else {
    439          return cur_vcol;
    440        }
    441      } while (cur_vcol != vcol);
    442    }
    443 
    444    tabstop_width = *last_tabstop;
    445    next_tab_vcol = vcol + tabstop_width;
    446  }
    447 
    448  assert(tabstop_width != 0);
    449  while (true) {
    450    char const c = *ptr++;
    451    if (c == ' ') {
    452      vcol++;
    453      next_tab_vcol += (vcol == next_tab_vcol) ? tabstop_width : 0;
    454    } else if (c == TAB) {
    455      vcol = next_tab_vcol;
    456      next_tab_vcol += tabstop_width;
    457    } else {
    458      return vcol;
    459    }
    460  }
    461 }
    462 
    463 /// Set the indent of the current line.
    464 /// Leaves the cursor on the first non-blank in the line.
    465 /// Caller must take care of undo.
    466 /// "flags":
    467 ///  SIN_CHANGED:    call changed_bytes() if the line was changed.
    468 ///  SIN_INSERT: insert the indent in front of the line.
    469 ///  SIN_UNDO:   save line for undo before changing it.
    470 ///  SIN_NOMARK: don't move extmarks (because just after ml_append or something)
    471 ///  @param size measured in spaces
    472 ///
    473 /// @return  true if the line was changed.
    474 bool set_indent(int size, int flags)
    475 {
    476  char *newline;
    477  char *oldline;
    478  char *s;
    479  int doit = false;
    480  int ind_done = 0;  // Measured in spaces.
    481  int tab_pad;
    482  bool retval = false;
    483 
    484  // Number of initial whitespace chars when 'et' and 'pi' are both set.
    485  int orig_char_len = -1;
    486 
    487  // First check if there is anything to do and compute the number of
    488  // characters needed for the indent.
    489  int todo = size;
    490  int ind_len = 0;  // Measured in characters.
    491  char *p = oldline = get_cursor_line_ptr();
    492  int line_len = get_cursor_line_len() + 1;  // size of the line (including the NUL)
    493 
    494  // Calculate the buffer size for the new indent, and check to see if it
    495  // isn't already set.
    496  // If 'expandtab' isn't set: use TABs; if both 'expandtab' and
    497  // 'preserveindent' are set count the number of characters at the
    498  // beginning of the line to be copied.
    499  if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi)) {
    500    int ind_col = 0;
    501    // If 'preserveindent' is set then reuse as much as possible of
    502    // the existing indent structure for the new indent.
    503    if (!(flags & SIN_INSERT) && curbuf->b_p_pi) {
    504      ind_done = 0;
    505 
    506      // Count as many characters as we can use.
    507      while (todo > 0 && ascii_iswhite(*p)) {
    508        if (*p == TAB) {
    509          tab_pad = tabstop_padding(ind_done,
    510                                    curbuf->b_p_ts,
    511                                    curbuf->b_p_vts_array);
    512 
    513          // Stop if this tab will overshoot the target.
    514          if (todo < tab_pad) {
    515            break;
    516          }
    517          todo -= tab_pad;
    518          ind_len++;
    519          ind_done += tab_pad;
    520        } else {
    521          todo--;
    522          ind_len++;
    523          ind_done++;
    524        }
    525        p++;
    526      }
    527 
    528      // These diverge from this point.
    529      ind_col = ind_done;
    530      // Set initial number of whitespace chars to copy if we are
    531      // preserving indent but expandtab is set.
    532      if (curbuf->b_p_et) {
    533        orig_char_len = ind_len;
    534      }
    535      // Fill to next tabstop with a tab, if possible.
    536      tab_pad = tabstop_padding(ind_done,
    537                                curbuf->b_p_ts,
    538                                curbuf->b_p_vts_array);
    539      if ((todo >= tab_pad) && (orig_char_len == -1)) {
    540        doit = true;
    541        todo -= tab_pad;
    542        ind_len++;
    543 
    544        // ind_done += tab_pad;
    545        ind_col += tab_pad;
    546      }
    547    }
    548 
    549    // Count tabs required for indent.
    550    while (true) {
    551      tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts, curbuf->b_p_vts_array);
    552      if (todo < tab_pad) {
    553        break;
    554      }
    555      if (*p != TAB) {
    556        doit = true;
    557      } else {
    558        p++;
    559      }
    560      todo -= tab_pad;
    561      ind_len++;
    562      ind_col += tab_pad;
    563    }
    564  }
    565 
    566  // Count spaces required for indent.
    567  while (todo > 0) {
    568    if (*p != ' ') {
    569      doit = true;
    570    } else {
    571      p++;
    572    }
    573    todo--;
    574    ind_len++;
    575 
    576    // ind_done++;
    577  }
    578 
    579  // Return if the indent is OK already.
    580  if (!doit && !ascii_iswhite(*p) && !(flags & SIN_INSERT)) {
    581    return false;
    582  }
    583 
    584  // Allocate memory for the new line.
    585  if (flags & SIN_INSERT) {
    586    p = oldline;
    587  } else {
    588    p = skipwhite(p);
    589    line_len -= (int)(p - oldline);
    590  }
    591 
    592  // If 'preserveindent' and 'expandtab' are both set keep the original
    593  // characters and allocate accordingly.  We will fill the rest with spaces
    594  // after the if (!curbuf->b_p_et) below.
    595  int skipcols = 0;  // number of columns (in bytes) that were presved
    596  if (orig_char_len != -1) {
    597    int newline_size;  // = orig_char_len + size - ind_done + line_len
    598    STRICT_ADD(orig_char_len, size, &newline_size, int);
    599    STRICT_SUB(newline_size, ind_done, &newline_size, int);
    600    STRICT_ADD(newline_size, line_len, &newline_size, int);
    601    assert(newline_size >= 0);
    602    newline = xmalloc((size_t)newline_size);
    603    todo = size - ind_done;
    604 
    605    // Set total length of indent in characters, which may have been
    606    // undercounted until now.
    607    ind_len = orig_char_len + todo;
    608    p = oldline;
    609    s = newline;
    610    skipcols = orig_char_len;
    611 
    612    while (orig_char_len > 0) {
    613      *s++ = *p++;
    614      orig_char_len--;
    615    }
    616 
    617    // Skip over any additional white space (useful when newindent is less
    618    // than old).
    619    while (ascii_iswhite(*p)) {
    620      p++;
    621    }
    622  } else {
    623    todo = size;
    624    assert(ind_len + line_len >= 0);
    625    size_t newline_size;
    626    STRICT_ADD(ind_len, line_len, &newline_size, size_t);
    627    newline = xmalloc(newline_size);
    628    s = newline;
    629  }
    630 
    631  // Put the characters in the new line.
    632  // if 'expandtab' isn't set: use TABs
    633  if (!curbuf->b_p_et) {
    634    // If 'preserveindent' is set then reuse as much as possible of
    635    // the existing indent structure for the new indent.
    636    if (!(flags & SIN_INSERT) && curbuf->b_p_pi) {
    637      p = oldline;
    638      ind_done = 0;
    639 
    640      while (todo > 0 && ascii_iswhite(*p)) {
    641        if (*p == TAB) {
    642          tab_pad = tabstop_padding(ind_done,
    643                                    curbuf->b_p_ts,
    644                                    curbuf->b_p_vts_array);
    645 
    646          // Stop if this tab will overshoot the target.
    647          if (todo < tab_pad) {
    648            break;
    649          }
    650          todo -= tab_pad;
    651          ind_done += tab_pad;
    652        } else {
    653          todo--;
    654          ind_done++;
    655        }
    656        *s++ = *p++;
    657        skipcols++;
    658      }
    659 
    660      // Fill to next tabstop with a tab, if possible.
    661      tab_pad = tabstop_padding(ind_done,
    662                                curbuf->b_p_ts,
    663                                curbuf->b_p_vts_array);
    664 
    665      if (todo >= tab_pad) {
    666        *s++ = TAB;
    667        todo -= tab_pad;
    668        ind_done += tab_pad;
    669      }
    670      p = skipwhite(p);
    671    }
    672 
    673    while (true) {
    674      tab_pad = tabstop_padding(ind_done,
    675                                curbuf->b_p_ts,
    676                                curbuf->b_p_vts_array);
    677      if (todo < tab_pad) {
    678        break;
    679      }
    680      *s++ = TAB;
    681      todo -= tab_pad;
    682      ind_done += tab_pad;
    683    }
    684  }
    685 
    686  while (todo > 0) {
    687    *s++ = ' ';
    688    todo--;
    689  }
    690  memmove(s, p, (size_t)line_len);
    691 
    692  // Replace the line (unless undo fails).
    693  if (!(flags & SIN_UNDO) || (u_savesub(curwin->w_cursor.lnum) == OK)) {
    694    const colnr_T old_offset = (colnr_T)(p - oldline);
    695    const colnr_T new_offset = (colnr_T)(s - newline);
    696 
    697    // this may free "newline"
    698    ml_replace(curwin->w_cursor.lnum, newline, false);
    699    if (!(flags & SIN_NOMARK)) {
    700      extmark_splice_cols(curbuf,
    701                          (int)curwin->w_cursor.lnum - 1,
    702                          skipcols,
    703                          old_offset - skipcols,
    704                          new_offset - skipcols,
    705                          kExtmarkUndo);
    706    }
    707 
    708    if (flags & SIN_CHANGED) {
    709      changed_bytes(curwin->w_cursor.lnum, 0);
    710    }
    711 
    712    // Correct saved cursor position if it is in this line.
    713    if (saved_cursor.lnum == curwin->w_cursor.lnum) {
    714      if (saved_cursor.col >= old_offset) {
    715        // Cursor was after the indent, adjust for the number of
    716        // bytes added/removed.
    717        saved_cursor.col += ind_len - old_offset;
    718      } else if (saved_cursor.col >= new_offset) {
    719        // Cursor was in the indent, and is now after it, put it back
    720        // at the start of the indent (replacing spaces with TAB).
    721        saved_cursor.col = new_offset;
    722      }
    723    }
    724    retval = true;
    725  } else {
    726    xfree(newline);
    727  }
    728  curwin->w_cursor.col = ind_len;
    729  return retval;
    730 }
    731 
    732 // Return the indent of the current line after a number.  Return -1 if no
    733 // number was found.  Used for 'n' in 'formatoptions': numbered list.
    734 // Since a pattern is used it can actually handle more than numbers.
    735 int get_number_indent(linenr_T lnum)
    736 {
    737  colnr_T col;
    738  pos_T pos;
    739  regmatch_T regmatch;
    740  int lead_len = 0;  // Length of comment leader.
    741 
    742  if (lnum > curbuf->b_ml.ml_line_count) {
    743    return -1;
    744  }
    745  pos.lnum = 0;
    746 
    747  // In format_lines() (i.e. not insert mode), fo+=q is needed too...
    748  if ((State & MODE_INSERT) || has_format_option(FO_Q_COMS)) {
    749    lead_len = get_leader_len(ml_get(lnum), NULL, false, true);
    750  }
    751  regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
    752 
    753  if (regmatch.regprog != NULL) {
    754    regmatch.rm_ic = false;
    755 
    756    // vim_regexec() expects a pointer to a line.  This lets us
    757    // start matching for the flp beyond any comment leader...
    758    if (vim_regexec(&regmatch, ml_get(lnum) + lead_len, 0)) {
    759      pos.lnum = lnum;
    760      pos.col = (colnr_T)(*regmatch.endp - ml_get(lnum));
    761      pos.coladd = 0;
    762    }
    763    vim_regfree(regmatch.regprog);
    764  }
    765 
    766  if ((pos.lnum == 0) || (*ml_get_pos(&pos) == NUL)) {
    767    return -1;
    768  }
    769  getvcol(curwin, &pos, &col, NULL, NULL);
    770  return (int)col;
    771 }
    772 
    773 /// Check "briopt" as 'breakindentopt' and update the members of "wp".
    774 /// This is called when 'breakindentopt' is changed and when a window is
    775 /// initialized
    776 ///
    777 /// @param briopt  when NULL: use "wp->w_p_briopt"
    778 /// @param wp      when NULL: only check "briopt"
    779 ///
    780 /// @return  FAIL for failure, OK otherwise.
    781 bool briopt_check(char *briopt, win_T *wp)
    782 {
    783  int bri_shift = 0;
    784  int bri_min = 20;
    785  bool bri_sbr = false;
    786  int bri_list = 0;
    787  int bri_vcol = 0;
    788 
    789  char *p = empty_string_option;
    790  if (briopt != NULL) {
    791    p = briopt;
    792  } else if (wp != NULL) {
    793    p = wp->w_p_briopt;
    794  }
    795 
    796  while (*p != NUL) {
    797    // Note: Keep this in sync with opt_briopt_values.
    798    if (strncmp(p, "shift:", 6) == 0
    799        && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) {
    800      p += 6;
    801      bri_shift = getdigits_int(&p, true, 0);
    802    } else if (strncmp(p, "min:", 4) == 0 && ascii_isdigit(p[4])) {
    803      p += 4;
    804      bri_min = getdigits_int(&p, true, 0);
    805    } else if (strncmp(p, "sbr", 3) == 0) {
    806      p += 3;
    807      bri_sbr = true;
    808    } else if (strncmp(p, "list:", 5) == 0) {
    809      p += 5;
    810      bri_list = (int)getdigits(&p, false, 0);
    811    } else if (strncmp(p, "column:", 7) == 0) {
    812      p += 7;
    813      bri_vcol = (int)getdigits(&p, false, 0);
    814    }
    815    if (*p != ',' && *p != NUL) {
    816      return false;
    817    }
    818    if (*p == ',') {
    819      p++;
    820    }
    821  }
    822 
    823  if (wp == NULL) {
    824    return OK;
    825  }
    826 
    827  wp->w_briopt_shift = bri_shift;
    828  wp->w_briopt_min = bri_min;
    829  wp->w_briopt_sbr = bri_sbr;
    830  wp->w_briopt_list = bri_list;
    831  wp->w_briopt_vcol = bri_vcol;
    832 
    833  return true;
    834 }
    835 
    836 // Return appropriate space number for breakindent, taking influencing
    837 // parameters into account. Window must be specified, since it is not
    838 // necessarily always the current one.
    839 int get_breakindent_win(win_T *wp, char *line)
    840  FUNC_ATTR_NONNULL_ALL
    841 {
    842  static int prev_indent = 0;  // cached indent value
    843  static OptInt prev_ts = 0;  // cached tabstop value
    844  static colnr_T *prev_vts = NULL;  // cached vartabs values
    845  static int prev_fnum = 0;  // cached buffer number
    846  static char *prev_line = NULL;  // cached copy of "line"
    847  static varnumber_T prev_tick = 0;  // changedtick of cached value
    848  static int prev_list = 0;  // cached list indent
    849  static int prev_listopt = 0;  // cached w_p_briopt_list value
    850  static bool prev_no_ts = false;  // cached no_ts value
    851  static unsigned prev_dy_uhex = 0;   // cached 'display' "uhex" value
    852  static char *prev_flp = NULL;  // cached formatlistpat value
    853  int bri = 0;
    854  // window width minus window margin space, i.e. what rests for text
    855  const int eff_wwidth = wp->w_view_width - win_col_off(wp) + win_col_off2(wp);
    856 
    857  // In list mode, if 'listchars' "tab" isn't set, a TAB is displayed as ^I.
    858  const bool no_ts = wp->w_p_list && wp->w_p_lcs_chars.tab1 == NUL;
    859 
    860  // Used cached indent, unless
    861  // - buffer changed, or
    862  // - 'tabstop' changed, or
    863  // - 'vartabstop' changed, or
    864  // - buffer was changed, or
    865  // - 'breakindentopt' "list" changed, or
    866  // - 'list' or 'listchars' "tab" changed, or
    867  // - 'display' "uhex" flag changed, or
    868  // - 'formatlistpat' changed, or
    869  // - line changed.
    870  if (prev_fnum != wp->w_buffer->b_fnum
    871      || prev_ts != wp->w_buffer->b_p_ts
    872      || prev_vts != wp->w_buffer->b_p_vts_array
    873      || prev_tick != buf_get_changedtick(wp->w_buffer)
    874      || prev_listopt != wp->w_briopt_list
    875      || prev_no_ts != no_ts
    876      || prev_dy_uhex != (dy_flags & kOptDyFlagUhex)
    877      || prev_flp == NULL
    878      || strcmp(prev_flp, get_flp_value(wp->w_buffer)) != 0
    879      || prev_line == NULL || strcmp(prev_line, line) != 0) {
    880    prev_fnum = wp->w_buffer->b_fnum;
    881    xfree(prev_line);
    882    prev_line = xstrdup(line);
    883    prev_ts = wp->w_buffer->b_p_ts;
    884    prev_vts = wp->w_buffer->b_p_vts_array;
    885    if (wp->w_briopt_vcol == 0) {
    886      if (no_ts) {
    887        prev_indent = indent_size_no_ts(line);
    888      } else {
    889        prev_indent = indent_size_ts(line, wp->w_buffer->b_p_ts,
    890                                     wp->w_buffer->b_p_vts_array);
    891      }
    892    }
    893    prev_tick = buf_get_changedtick(wp->w_buffer);
    894    prev_listopt = wp->w_briopt_list;
    895    prev_list = 0;
    896    prev_no_ts = no_ts;
    897    prev_dy_uhex = (dy_flags & kOptDyFlagUhex);
    898    xfree(prev_flp);
    899    prev_flp = xstrdup(get_flp_value(wp->w_buffer));
    900    // add additional indent for numbered lists
    901    if (wp->w_briopt_list != 0 && wp->w_briopt_vcol == 0) {
    902      regmatch_T regmatch = {
    903        .regprog = vim_regcomp(prev_flp, RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT),
    904      };
    905      if (regmatch.regprog != NULL) {
    906        regmatch.rm_ic = false;
    907        if (vim_regexec(&regmatch, line, 0)) {
    908          if (wp->w_briopt_list > 0) {
    909            prev_list += wp->w_briopt_list;
    910          } else {
    911            char *ptr = *regmatch.startp;
    912            char *end_ptr = *regmatch.endp;
    913            int indent = 0;
    914            // Compute the width of the matched text.
    915            // Use win_chartabsize() so that TAB size is correct,
    916            // while wrapping is ignored.
    917            while (ptr < end_ptr) {
    918              indent += win_chartabsize(wp, ptr, indent);
    919              MB_PTR_ADV(ptr);
    920            }
    921            prev_indent = indent;
    922          }
    923        }
    924        vim_regfree(regmatch.regprog);
    925      }
    926    }
    927  }
    928  if (wp->w_briopt_vcol != 0) {
    929    // column value has priority
    930    bri = wp->w_briopt_vcol;
    931    prev_list = 0;
    932  } else {
    933    bri = prev_indent + wp->w_briopt_shift;
    934  }
    935 
    936  // Add offset for number column, if 'n' is in 'cpoptions'
    937  bri += win_col_off2(wp);
    938 
    939  // add additional indent for numbered lists
    940  if (wp->w_briopt_list > 0) {
    941    bri += prev_list;
    942  }
    943 
    944  // indent minus the length of the showbreak string
    945  if (wp->w_briopt_sbr) {
    946    bri -= vim_strsize(get_showbreak_value(wp));
    947  }
    948 
    949  // never indent past left window margin
    950  if (bri < 0) {
    951    bri = 0;
    952  } else if (bri > eff_wwidth - wp->w_briopt_min) {
    953    // always leave at least bri_min characters on the left,
    954    // if text width is sufficient
    955    bri = (eff_wwidth - wp->w_briopt_min < 0)
    956          ? 0 : eff_wwidth - wp->w_briopt_min;
    957  }
    958 
    959  return bri;
    960 }
    961 
    962 // When extra == 0: Return true if the cursor is before or on the first
    963 // non-blank in the line.
    964 // When extra == 1: Return true if the cursor is before the first non-blank in
    965 // the line.
    966 bool inindent(int extra)
    967 {
    968  char *ptr;
    969  colnr_T col;
    970 
    971  for (col = 0, ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr); col++) {
    972    ptr++;
    973  }
    974 
    975  if (col >= curwin->w_cursor.col + extra) {
    976    return true;
    977  }
    978  return false;
    979 }
    980 
    981 /// Handle reindenting a block of lines.
    982 void op_reindent(oparg_T *oap, Indenter how)
    983 {
    984  int i = 0;
    985  linenr_T first_changed = 0;
    986  linenr_T last_changed = 0;
    987  linenr_T start_lnum = curwin->w_cursor.lnum;
    988 
    989  // Don't even try when 'modifiable' is off.
    990  if (!MODIFIABLE(curbuf)) {
    991    emsg(_(e_modifiable));
    992    return;
    993  }
    994 
    995  // Save for undo.  Do this once for all lines, much faster than doing this
    996  // for each line separately, especially when undoing.
    997  if (u_savecommon(curbuf, start_lnum - 1, start_lnum + oap->line_count,
    998                   start_lnum + oap->line_count, false) == OK) {
    999    int amount;
   1000    for (i = oap->line_count - 1; i >= 0 && !got_int; i--) {
   1001      // it's a slow thing to do, so give feedback so there's no worry
   1002      // that the computer's just hung.
   1003 
   1004      if (i > 1
   1005          && (i % 50 == 0 || i == oap->line_count - 1)
   1006          && oap->line_count > p_report) {
   1007        smsg(0, _("%" PRId64 " lines to indent... "), (int64_t)i);
   1008      }
   1009 
   1010      // Be vi-compatible: For lisp indenting the first line is not
   1011      // indented, unless there is only one line.
   1012      if (i != oap->line_count - 1 || oap->line_count == 1
   1013          || how != get_lisp_indent) {
   1014        char *l = skipwhite(get_cursor_line_ptr());
   1015        if (*l == NUL) {                      // empty or blank line
   1016          amount = 0;
   1017        } else {
   1018          amount = how();                     // get the indent for this line
   1019        }
   1020        if (amount >= 0 && set_indent(amount, 0)) {
   1021          // did change the indent, call changed_lines() later
   1022          if (first_changed == 0) {
   1023            first_changed = curwin->w_cursor.lnum;
   1024          }
   1025          last_changed = curwin->w_cursor.lnum;
   1026        }
   1027      }
   1028      curwin->w_cursor.lnum++;
   1029      curwin->w_cursor.col = 0;      // make sure it's valid
   1030    }
   1031  }
   1032 
   1033  // put cursor on first non-blank of indented line
   1034  curwin->w_cursor.lnum = start_lnum;
   1035  beginline(BL_SOL | BL_FIX);
   1036 
   1037  // Mark changed lines so that they will be redrawn.  When Visual
   1038  // highlighting was present, need to continue until the last line.  When
   1039  // there is no change still need to remove the Visual highlighting.
   1040  if (last_changed != 0) {
   1041    changed_lines(curbuf, first_changed, 0,
   1042                  oap->is_VIsual ? start_lnum + oap->line_count
   1043                                 : last_changed + 1, 0, true);
   1044  } else if (oap->is_VIsual) {
   1045    redraw_curbuf_later(UPD_INVERTED);
   1046  }
   1047 
   1048  if (oap->line_count > p_report) {
   1049    i = oap->line_count - (i + 1);
   1050    smsg(0, NGETTEXT("%" PRId64 " line indented ", "%" PRId64 " lines indented ", i), (int64_t)i);
   1051  }
   1052  if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
   1053    // set '[ and '] marks
   1054    curbuf->b_op_start = oap->start;
   1055    curbuf->b_op_end = oap->end;
   1056  }
   1057 }
   1058 
   1059 /// @return  true if lines starting with '#' should be left aligned.
   1060 bool preprocs_left(void)
   1061 {
   1062  return ((curbuf->b_p_si && !curbuf->b_p_cin)
   1063          || (curbuf->b_p_cin && in_cinkeys('#', ' ', true)
   1064              && curbuf->b_ind_hash_comment == 0));
   1065 }
   1066 
   1067 /// @return  true if the conditions are OK for smart indenting.
   1068 bool may_do_si(void)
   1069 {
   1070  return curbuf->b_p_si && !curbuf->b_p_cin && *curbuf->b_p_inde == NUL && !p_paste;
   1071 }
   1072 
   1073 // Try to do some very smart auto-indenting.
   1074 // Used when inserting a "normal" character.
   1075 void ins_try_si(int c)
   1076 {
   1077  pos_T *pos;
   1078 
   1079  // do some very smart indenting when entering '{' or '}'
   1080  if (((did_si || can_si_back) && c == '{') || (can_si && c == '}' && inindent(0))) {
   1081    pos_T old_pos;
   1082    char *ptr;
   1083    int i;
   1084    bool temp;
   1085    // for '}' set indent equal to indent of line containing matching '{'
   1086    if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) {
   1087      old_pos = curwin->w_cursor;
   1088      // If the matching '{' has a ')' immediately before it (ignoring
   1089      // white-space), then line up with the start of the line
   1090      // containing the matching '(' if there is one.  This handles the
   1091      // case where an "if (..\n..) {" statement continues over multiple
   1092      // lines -- webb
   1093      ptr = ml_get(pos->lnum);
   1094      i = pos->col;
   1095      if (i > 0) {              // skip blanks before '{'
   1096        while (--i > 0 && ascii_iswhite(ptr[i])) {}
   1097      }
   1098      curwin->w_cursor.lnum = pos->lnum;
   1099      curwin->w_cursor.col = i;
   1100      if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) {
   1101        curwin->w_cursor = *pos;
   1102      }
   1103      i = get_indent();
   1104      curwin->w_cursor = old_pos;
   1105      if (State & VREPLACE_FLAG) {
   1106        change_indent(INDENT_SET, i, false, true);
   1107      } else {
   1108        set_indent(i, SIN_CHANGED);
   1109      }
   1110    } else if (curwin->w_cursor.col > 0) {
   1111      // when inserting '{' after "O" reduce indent, but not
   1112      // more than indent of previous line
   1113      temp = true;
   1114      if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) {
   1115        old_pos = curwin->w_cursor;
   1116        i = get_indent();
   1117        while (curwin->w_cursor.lnum > 1) {
   1118          ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
   1119 
   1120          // ignore empty lines and lines starting with '#'.
   1121          if (*ptr != '#' && *ptr != NUL) {
   1122            break;
   1123          }
   1124        }
   1125        if (get_indent() >= i) {
   1126          temp = false;
   1127        }
   1128        curwin->w_cursor = old_pos;
   1129      }
   1130      if (temp) {
   1131        shift_line(true, false, 1, true);
   1132      }
   1133    }
   1134  }
   1135 
   1136  // set indent of '#' always to 0
   1137  if (curwin->w_cursor.col > 0 && can_si && c == '#' && inindent(0)) {
   1138    // remember current indent for next line
   1139    old_indent = get_indent();
   1140    set_indent(0, SIN_CHANGED);
   1141  }
   1142 
   1143  // Adjust ai_col, the char at this position can be deleted.
   1144  ai_col = MIN(ai_col, curwin->w_cursor.col);
   1145 }
   1146 
   1147 /// Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
   1148 /// Keep the cursor on the same character.
   1149 /// type == INDENT_INC   increase indent (for CTRL-T or <Tab>)
   1150 /// type == INDENT_DEC   decrease indent (for CTRL-D)
   1151 /// type == INDENT_SET   set indent to "amount"
   1152 ///
   1153 /// @param round               if true, round the indent to 'shiftwidth' (only with _INC and _Dec).
   1154 /// @param call_changed_bytes  call changed_bytes()
   1155 void change_indent(int type, int amount, int round, bool call_changed_bytes)
   1156 {
   1157  int insstart_less;                    // reduction for Insstart.col
   1158  colnr_T orig_col = 0;                 // init for GCC
   1159  char *orig_line = NULL;     // init for GCC
   1160 
   1161  // MODE_VREPLACE state needs to know what the line was like before changing
   1162  if (State & VREPLACE_FLAG) {
   1163    orig_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
   1164    orig_col = curwin->w_cursor.col;
   1165  }
   1166 
   1167  // for the following tricks we don't want list mode
   1168  int save_p_list = curwin->w_p_list;
   1169  curwin->w_p_list = false;
   1170  colnr_T vc = getvcol_nolist(&curwin->w_cursor);
   1171  int vcol = vc;
   1172 
   1173  // For Replace mode we need to fix the replace stack later, which is only
   1174  // possible when the cursor is in the indent.  Remember the number of
   1175  // characters before the cursor if it's possible.
   1176  int start_col = curwin->w_cursor.col;
   1177 
   1178  // determine offset from first non-blank
   1179  int new_cursor_col = curwin->w_cursor.col;
   1180  beginline(BL_WHITE);
   1181  new_cursor_col -= curwin->w_cursor.col;
   1182 
   1183  insstart_less = curwin->w_cursor.col;
   1184 
   1185  // If the cursor is in the indent, compute how many screen columns the
   1186  // cursor is to the left of the first non-blank.
   1187  if (new_cursor_col < 0) {
   1188    vcol = get_indent() - vcol;
   1189  }
   1190 
   1191  if (new_cursor_col > 0) {         // can't fix replace stack
   1192    start_col = -1;
   1193  }
   1194 
   1195  // Set the new indent.  The cursor will be put on the first non-blank.
   1196  if (type == INDENT_SET) {
   1197    set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
   1198  } else {
   1199    int save_State = State;
   1200 
   1201    // Avoid being called recursively.
   1202    if (State & VREPLACE_FLAG) {
   1203      State = MODE_INSERT;
   1204    }
   1205    shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
   1206    State = save_State;
   1207  }
   1208  insstart_less -= curwin->w_cursor.col;
   1209 
   1210  // Try to put cursor on same character.
   1211  // If the cursor is at or after the first non-blank in the line,
   1212  // compute the cursor column relative to the column of the first
   1213  // non-blank character.
   1214  // If we are not in insert mode, leave the cursor on the first non-blank.
   1215  // If the cursor is before the first non-blank, position it relative
   1216  // to the first non-blank, counted in screen columns.
   1217  if (new_cursor_col >= 0) {
   1218    // When changing the indent while the cursor is touching it, reset
   1219    // Insstart_col to 0.
   1220    if (new_cursor_col == 0) {
   1221      insstart_less = MAXCOL;
   1222    }
   1223    new_cursor_col += curwin->w_cursor.col;
   1224  } else if (!(State & MODE_INSERT)) {
   1225    new_cursor_col = curwin->w_cursor.col;
   1226  } else {
   1227    // Compute the screen column where the cursor should be.
   1228    vcol = get_indent() - vcol;
   1229    int const end_vcol = (colnr_T)((vcol < 0) ? 0 : vcol);
   1230    curwin->w_virtcol = end_vcol;
   1231 
   1232    // Advance the cursor until we reach the right screen column.
   1233    new_cursor_col = 0;
   1234    char *const line = get_cursor_line_ptr();
   1235    vcol = 0;
   1236    if (*line != NUL) {
   1237      CharsizeArg csarg;
   1238      CSType cstype = init_charsize_arg(&csarg, curwin, 0, line);
   1239      StrCharInfo ci = utf_ptr2StrCharInfo(line);
   1240      while (true) {
   1241        int next_vcol = vcol + win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width;
   1242        if (next_vcol > end_vcol) {
   1243          break;
   1244        }
   1245        vcol = next_vcol;
   1246        ci = utfc_next(ci);
   1247        if (*ci.ptr == NUL) {
   1248          break;
   1249        }
   1250      }
   1251      new_cursor_col = (int)(ci.ptr - line);
   1252    }
   1253 
   1254    // May need to insert spaces to be able to position the cursor on
   1255    // the right screen column.
   1256    if (vcol != (int)curwin->w_virtcol) {
   1257      curwin->w_cursor.col = (colnr_T)new_cursor_col;
   1258      const size_t ptrlen = (size_t)(curwin->w_virtcol - vcol);
   1259      char *ptr = xmallocz(ptrlen);
   1260      memset(ptr, ' ', ptrlen);
   1261      new_cursor_col += (int)ptrlen;
   1262      ins_str(ptr, ptrlen);
   1263      xfree(ptr);
   1264    }
   1265 
   1266    // When changing the indent while the cursor is in it, reset
   1267    // Insstart_col to 0.
   1268    insstart_less = MAXCOL;
   1269  }
   1270 
   1271  curwin->w_p_list = save_p_list;
   1272  curwin->w_cursor.col = MAX(0, (colnr_T)new_cursor_col);
   1273  curwin->w_set_curswant = true;
   1274  changed_cline_bef_curs(curwin);
   1275 
   1276  // May have to adjust the start of the insert.
   1277  if (State & MODE_INSERT) {
   1278    if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) {
   1279      if ((int)Insstart.col <= insstart_less) {
   1280        Insstart.col = 0;
   1281      } else {
   1282        Insstart.col -= insstart_less;
   1283      }
   1284    }
   1285    if ((int)ai_col <= insstart_less) {
   1286      ai_col = 0;
   1287    } else {
   1288      ai_col -= insstart_less;
   1289    }
   1290  }
   1291 
   1292  // For MODE_REPLACE state, may have to fix the replace stack, if it's
   1293  // possible.  If the number of characters before the cursor decreased, need
   1294  // to pop a few characters from the replace stack.
   1295  // If the number of characters before the cursor increased, need to push a
   1296  // few NULs onto the replace stack.
   1297  if (REPLACE_NORMAL(State) && start_col >= 0) {
   1298    while (start_col > (int)curwin->w_cursor.col) {
   1299      replace_join(0);              // remove a NUL from the replace stack
   1300      start_col--;
   1301    }
   1302    while (start_col < (int)curwin->w_cursor.col) {
   1303      replace_push_nul();
   1304      start_col++;
   1305    }
   1306  }
   1307 
   1308  // For MODE_VREPLACE state, we also have to fix the replace stack.  In this
   1309  // case it is always possible because we backspace over the whole line and
   1310  // then put it back again the way we wanted it.
   1311  if (State & VREPLACE_FLAG) {
   1312    // Save new line
   1313    char *new_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
   1314 
   1315    // We only put back the new line up to the cursor
   1316    new_line[curwin->w_cursor.col] = NUL;
   1317    int new_col = curwin->w_cursor.col;
   1318 
   1319    // Put back original line
   1320    ml_replace(curwin->w_cursor.lnum, orig_line, false);
   1321    curwin->w_cursor.col = orig_col;
   1322 
   1323    curbuf_splice_pending++;
   1324 
   1325    // Backspace from cursor to start of line
   1326    backspace_until_column(0);
   1327 
   1328    // Insert new stuff into line again
   1329    ins_bytes(new_line);
   1330 
   1331    xfree(new_line);
   1332 
   1333    curbuf_splice_pending--;
   1334 
   1335    // TODO(bfredl): test for crazy edge cases, like we stand on a TAB or
   1336    // something? does this even do the right text change then?
   1337    int delta = orig_col - new_col;
   1338    extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1, new_col,
   1339                        delta < 0 ? -delta : 0,
   1340                        delta > 0 ? delta : 0,
   1341                        kExtmarkUndo);
   1342  }
   1343 }
   1344 
   1345 /// Copy the indent from ptr to the current line (and fill to size).
   1346 /// Leaves the cursor on the first non-blank in the line.
   1347 ///
   1348 /// @return true if the line was changed.
   1349 bool copy_indent(int size, char *src)
   1350 {
   1351  char *p = NULL;
   1352  char *line = NULL;
   1353  int ind_len;
   1354  int line_len = 0;
   1355  int tab_pad;
   1356 
   1357  // Round 1: compute the number of characters needed for the indent
   1358  // Round 2: copy the characters.
   1359  for (int round = 1; round <= 2; round++) {
   1360    int todo = size;
   1361    ind_len = 0;
   1362    int ind_done = 0;
   1363    int ind_col = 0;
   1364    char *s = src;
   1365 
   1366    // Count/copy the usable portion of the source line.
   1367    while (todo > 0 && ascii_iswhite(*s)) {
   1368      if (*s == TAB) {
   1369        tab_pad = tabstop_padding(ind_done,
   1370                                  curbuf->b_p_ts,
   1371                                  curbuf->b_p_vts_array);
   1372 
   1373        // Stop if this tab will overshoot the target.
   1374        if (todo < tab_pad) {
   1375          break;
   1376        }
   1377        todo -= tab_pad;
   1378        ind_done += tab_pad;
   1379        ind_col += tab_pad;
   1380      } else {
   1381        todo--;
   1382        ind_done++;
   1383        ind_col++;
   1384      }
   1385      ind_len++;
   1386 
   1387      if (p != NULL) {
   1388        *p++ = *s;
   1389      }
   1390      s++;
   1391    }
   1392 
   1393    // Fill to next tabstop with a tab, if possible.
   1394    tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts, curbuf->b_p_vts_array);
   1395 
   1396    if ((todo >= tab_pad) && !curbuf->b_p_et) {
   1397      todo -= tab_pad;
   1398      ind_len++;
   1399      ind_col += tab_pad;
   1400 
   1401      if (p != NULL) {
   1402        *p++ = TAB;
   1403      }
   1404    }
   1405 
   1406    // Add tabs required for indent.
   1407    if (!curbuf->b_p_et) {
   1408      while (true) {
   1409        tab_pad = tabstop_padding(ind_col,
   1410                                  curbuf->b_p_ts,
   1411                                  curbuf->b_p_vts_array);
   1412        if (todo < tab_pad) {
   1413          break;
   1414        }
   1415        todo -= tab_pad;
   1416        ind_len++;
   1417        ind_col += tab_pad;
   1418        if (p != NULL) {
   1419          *p++ = TAB;
   1420        }
   1421      }
   1422    }
   1423 
   1424    // Count/add spaces required for indent.
   1425    while (todo > 0) {
   1426      todo--;
   1427      ind_len++;
   1428 
   1429      if (p != NULL) {
   1430        *p++ = ' ';
   1431      }
   1432    }
   1433 
   1434    if (p == NULL) {
   1435      // Allocate memory for the result: the copied indent, new indent
   1436      // and the rest of the line.
   1437      line_len = get_cursor_line_len() + 1;
   1438      assert(ind_len + line_len >= 0);
   1439      size_t line_size;
   1440      STRICT_ADD(ind_len, line_len, &line_size, size_t);
   1441      line = xmalloc(line_size);
   1442      p = line;
   1443    }
   1444  }
   1445 
   1446  // Append the original line
   1447  memmove(p, get_cursor_line_ptr(), (size_t)line_len);
   1448 
   1449  // Replace the line
   1450  ml_replace(curwin->w_cursor.lnum, line, false);
   1451 
   1452  // Put the cursor after the indent.
   1453  curwin->w_cursor.col = ind_len;
   1454  return true;
   1455 }
   1456 
   1457 /// Give a "resulting text too long" error and maybe set got_int.
   1458 static void emsg_text_too_long(void)
   1459 {
   1460  emsg(_(e_resulting_text_too_long));
   1461  // when not inside a try/catch set got_int to break out of any loop
   1462  if (trylevel == 0) {
   1463    got_int = true;
   1464  }
   1465 }
   1466 
   1467 /// ":retab".
   1468 void ex_retab(exarg_T *eap)
   1469 {
   1470  bool got_tab = false;
   1471  int num_spaces = 0;
   1472  int start_col = 0;                   // For start of white-space string
   1473  int64_t start_vcol = 0;                  // For start of white-space string
   1474  char *new_line = (char *)1;  // init to non-NULL
   1475  colnr_T *new_vts_array = NULL;
   1476  char *new_ts_str;  // string value of tab argument
   1477 
   1478  linenr_T first_line = 0;              // first changed line
   1479  linenr_T last_line = 0;               // last changed line
   1480  bool is_indent_only = false;
   1481 
   1482  int save_list = curwin->w_p_list;
   1483  curwin->w_p_list = 0;             // don't want list mode here
   1484 
   1485  char *ptr = eap->arg;
   1486  if (strncmp(ptr, "-indentonly", 11) == 0 && ascii_iswhite_or_nul(ptr[11])) {
   1487    is_indent_only = true;
   1488    ptr = skipwhite(ptr + 11);
   1489  }
   1490 
   1491  new_ts_str = ptr;
   1492  if (!tabstop_set(ptr, &new_vts_array)) {
   1493    return;
   1494  }
   1495  while (ascii_isdigit(*ptr) || *ptr == ',') {
   1496    ptr++;
   1497  }
   1498 
   1499  // This ensures that either new_vts_array and new_ts_str are freshly
   1500  // allocated, or new_vts_array points to an existing array and new_ts_str
   1501  // is null.
   1502  if (new_vts_array == NULL) {
   1503    new_vts_array = curbuf->b_p_vts_array;
   1504    new_ts_str = NULL;
   1505  } else {
   1506    new_ts_str = xmemdupz(new_ts_str, (size_t)(ptr - new_ts_str));
   1507  }
   1508  for (linenr_T lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) {
   1509    ptr = ml_get(lnum);
   1510    int old_len = ml_get_len(lnum);
   1511    int col = 0;
   1512    int64_t vcol = 0;
   1513    bool did_undo = false;  // called u_save for current line
   1514    while (true) {
   1515      if (ascii_iswhite(ptr[col])) {
   1516        if (!got_tab && num_spaces == 0) {
   1517          // First consecutive white-space
   1518          start_vcol = vcol;
   1519          start_col = col;
   1520        }
   1521        if (ptr[col] == ' ') {
   1522          num_spaces++;
   1523        } else {
   1524          got_tab = true;
   1525        }
   1526      } else {
   1527        if (got_tab || (eap->forceit && num_spaces > 1)) {
   1528          // Retabulate this string of white-space
   1529 
   1530          // len is virtual length of white string
   1531          int len = num_spaces = (int)(vcol - start_vcol);
   1532          int num_tabs = 0;
   1533          if (!curbuf->b_p_et) {
   1534            int t, s;
   1535 
   1536            tabstop_fromto((colnr_T)start_vcol, (colnr_T)vcol,
   1537                           (int)curbuf->b_p_ts, new_vts_array, &t, &s);
   1538            num_tabs = t;
   1539            num_spaces = s;
   1540          }
   1541          if (curbuf->b_p_et || got_tab
   1542              || (num_spaces + num_tabs < len)) {
   1543            if (did_undo == false) {
   1544              did_undo = true;
   1545              if (u_save((linenr_T)(lnum - 1),
   1546                         (linenr_T)(lnum + 1)) == FAIL) {
   1547                new_line = NULL;  // flag out-of-memory
   1548                break;
   1549              }
   1550            }
   1551 
   1552            // len is actual number of white characters used
   1553            len = num_spaces + num_tabs;
   1554            const int new_len = old_len - col + start_col + len + 1;
   1555            if (new_len <= 0 || new_len >= MAXCOL) {
   1556              emsg_text_too_long();
   1557              break;
   1558            }
   1559            new_line = xmalloc((size_t)new_len);
   1560 
   1561            if (start_col > 0) {
   1562              memmove(new_line, ptr, (size_t)start_col);
   1563            }
   1564            memmove(new_line + start_col + len,
   1565                    ptr + col, (size_t)old_len - (size_t)col + 1);
   1566            ptr = new_line + start_col;
   1567            for (col = 0; col < len; col++) {
   1568              ptr[col] = (col < num_tabs) ? '\t' : ' ';
   1569            }
   1570            if (ml_replace(lnum, new_line, false) == OK) {
   1571              // "new_line" may have been copied
   1572              new_line = curbuf->b_ml.ml_line_ptr;
   1573              extmark_splice_cols(curbuf, lnum - 1, 0, (colnr_T)old_len,
   1574                                  (colnr_T)new_len - 1, kExtmarkUndo);
   1575            }
   1576            if (first_line == 0) {
   1577              first_line = lnum;
   1578            }
   1579            last_line = lnum;
   1580            ptr = new_line;
   1581            old_len = new_len - 1;
   1582            col = start_col + len;
   1583          }
   1584        }
   1585        got_tab = false;
   1586        num_spaces = 0;
   1587 
   1588        if (is_indent_only) {
   1589          break;
   1590        }
   1591      }
   1592      if (ptr[col] == NUL) {
   1593        break;
   1594      }
   1595      vcol += win_chartabsize(curwin, ptr + col, (colnr_T)vcol);
   1596      if (vcol >= MAXCOL) {
   1597        emsg_text_too_long();
   1598        break;
   1599      }
   1600      col += utfc_ptr2len(ptr + col);
   1601    }
   1602    if (new_line == NULL) {                 // out of memory
   1603      break;
   1604    }
   1605    line_breakcheck();
   1606  }
   1607  if (got_int) {
   1608    emsg(_(e_interr));
   1609  }
   1610 
   1611  // If a single value was given then it can be considered equal to
   1612  // either the value of 'tabstop' or the value of 'vartabstop'.
   1613  if (tabstop_count(curbuf->b_p_vts_array) == 0
   1614      && tabstop_count(new_vts_array) == 1
   1615      && curbuf->b_p_ts == tabstop_first(new_vts_array)) {
   1616    // not changed
   1617  } else if (tabstop_count(curbuf->b_p_vts_array) > 0
   1618             && tabstop_eq(curbuf->b_p_vts_array, new_vts_array)) {
   1619    // not changed
   1620  } else {
   1621    redraw_curbuf_later(UPD_NOT_VALID);
   1622  }
   1623  if (first_line != 0) {
   1624    changed_lines(curbuf, first_line, 0, last_line + 1, 0, true);
   1625  }
   1626 
   1627  curwin->w_p_list = save_list;         // restore 'list'
   1628 
   1629  if (new_ts_str != NULL) {  // set the new tabstop
   1630    // If 'vartabstop' is in use or if the value given to retab has more
   1631    // than one tabstop then update 'vartabstop'.
   1632    colnr_T *old_vts_ary = curbuf->b_p_vts_array;
   1633 
   1634    if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1) {
   1635      set_option_direct(kOptVartabstop, CSTR_AS_OPTVAL(new_ts_str), OPT_LOCAL, 0);
   1636      curbuf->b_p_vts_array = new_vts_array;
   1637      xfree(old_vts_ary);
   1638    } else {
   1639      // 'vartabstop' wasn't in use and a single value was given to
   1640      // retab then update 'tabstop'.
   1641      curbuf->b_p_ts = tabstop_first(new_vts_array);
   1642      xfree(new_vts_array);
   1643    }
   1644    xfree(new_ts_str);
   1645  }
   1646  coladvance(curwin, curwin->w_curswant);
   1647 
   1648  u_clearline(curbuf);
   1649 }
   1650 
   1651 /// Get indent level from 'indentexpr'.
   1652 int get_expr_indent(void)
   1653 {
   1654  bool use_sandbox = was_set_insecurely(curwin, kOptIndentexpr, OPT_LOCAL);
   1655  const sctx_T save_sctx = current_sctx;
   1656 
   1657  // Save and restore cursor position and curswant, in case it was changed
   1658  // * via :normal commands.
   1659  pos_T save_pos = curwin->w_cursor;
   1660  colnr_T save_curswant = curwin->w_curswant;
   1661  bool save_set_curswant = curwin->w_set_curswant;
   1662  set_vim_var_nr(VV_LNUM, (varnumber_T)curwin->w_cursor.lnum);
   1663 
   1664  if (use_sandbox) {
   1665    sandbox++;
   1666  }
   1667  textlock++;
   1668  current_sctx = curbuf->b_p_script_ctx[kBufOptIndentexpr];
   1669 
   1670  // Need to make a copy, the 'indentexpr' option could be changed while
   1671  // evaluating it.
   1672  char *inde_copy = xstrdup(curbuf->b_p_inde);
   1673  int indent = (int)eval_to_number(inde_copy, true);
   1674  xfree(inde_copy);
   1675 
   1676  if (use_sandbox) {
   1677    sandbox--;
   1678  }
   1679  textlock--;
   1680  current_sctx = save_sctx;
   1681 
   1682  // Restore the cursor position so that 'indentexpr' doesn't need to.
   1683  // Pretend to be in Insert mode, allow cursor past end of line for "o"
   1684  // command.
   1685  int save_State = State;
   1686  State = MODE_INSERT;
   1687  curwin->w_cursor = save_pos;
   1688  curwin->w_curswant = save_curswant;
   1689  curwin->w_set_curswant = save_set_curswant;
   1690  check_cursor(curwin);
   1691  State = save_State;
   1692 
   1693  // Reset did_throw, unless 'debug' has "throw" and inside a try/catch.
   1694  if (did_throw && (vim_strchr(p_debug, 't') == NULL || trylevel == 0)) {
   1695    handle_did_throw();
   1696    did_throw = false;
   1697  }
   1698 
   1699  // If there is an error, just keep the current indent.
   1700  if (indent < 0) {
   1701    indent = get_indent();
   1702  }
   1703 
   1704  return indent;
   1705 }
   1706 
   1707 // When 'p' is present in 'cpoptions, a Vi compatible method is used.
   1708 // The incompatible newer method is quite a bit better at indenting
   1709 // code in lisp-like languages than the traditional one; it's still
   1710 // mostly heuristics however -- Dirk van Deun, dirk@rave.org
   1711 
   1712 // TODO(unknown):
   1713 // Findmatch() should be adapted for lisp, also to make showmatch
   1714 // work correctly: now (v5.3) it seems all C/C++ oriented:
   1715 // - it does not recognize the #\( and #\) notations as character literals
   1716 // - it doesn't know about comments starting with a semicolon
   1717 // - it incorrectly interprets '(' as a character literal
   1718 // All this messes up get_lisp_indent in some rare cases.
   1719 // Update from Sergey Khorev:
   1720 // I tried to fix the first two issues.
   1721 int get_lisp_indent(void)
   1722 {
   1723  pos_T *pos;
   1724  pos_T paren;
   1725  int amount;
   1726 
   1727  pos_T realpos = curwin->w_cursor;
   1728  curwin->w_cursor.col = 0;
   1729 
   1730  if ((pos = findmatch(NULL, '(')) == NULL) {
   1731    pos = findmatch(NULL, '[');
   1732  } else {
   1733    paren = *pos;
   1734    pos = findmatch(NULL, '[');
   1735 
   1736    if ((pos == NULL) || lt(*pos, paren)) {
   1737      pos = &paren;
   1738    }
   1739  }
   1740 
   1741  if (pos != NULL) {
   1742    // Extra trick: Take the indent of the first previous non-white
   1743    // line that is at the same () level.
   1744    amount = -1;
   1745    int parencount = 0;
   1746 
   1747    while (--curwin->w_cursor.lnum >= pos->lnum) {
   1748      if (linewhite(curwin->w_cursor.lnum)) {
   1749        continue;
   1750      }
   1751 
   1752      for (char *that = get_cursor_line_ptr(); *that != NUL; that++) {
   1753        if (*that == ';') {
   1754          while (*(that + 1) != NUL) {
   1755            that++;
   1756          }
   1757          continue;
   1758        }
   1759 
   1760        if (*that == '\\') {
   1761          if (*(that + 1) != NUL) {
   1762            that++;
   1763          }
   1764          continue;
   1765        }
   1766 
   1767        if ((*that == '"') && (*(that + 1) != NUL)) {
   1768          while (*++that && *that != '"') {
   1769            // Skipping escaped characters in the string
   1770            if (*that == '\\') {
   1771              if (*++that == NUL) {
   1772                break;
   1773              }
   1774              if (that[1] == NUL) {
   1775                that++;
   1776                break;
   1777              }
   1778            }
   1779          }
   1780          if (*that == NUL) {
   1781            break;
   1782          }
   1783        }
   1784        if ((*that == '(') || (*that == '[')) {
   1785          parencount++;
   1786        } else if ((*that == ')') || (*that == ']')) {
   1787          parencount--;
   1788        }
   1789      }
   1790 
   1791      if (parencount == 0) {
   1792        amount = get_indent();
   1793        break;
   1794      }
   1795    }
   1796 
   1797    if (amount == -1) {
   1798      curwin->w_cursor.lnum = pos->lnum;
   1799      curwin->w_cursor.col = pos->col;
   1800      colnr_T col = pos->col;
   1801 
   1802      char *line = get_cursor_line_ptr();
   1803 
   1804      CharsizeArg csarg;
   1805      CSType cstype = init_charsize_arg(&csarg, curwin, pos->lnum, line);
   1806 
   1807      StrCharInfo sci = utf_ptr2StrCharInfo(line);
   1808      amount = 0;
   1809      while (*sci.ptr != NUL && col > 0) {
   1810        amount += win_charsize(cstype, amount, sci.ptr, sci.chr.value, &csarg).width;
   1811        sci = utfc_next(sci);
   1812        col--;
   1813      }
   1814      char *that = sci.ptr;
   1815 
   1816      // Some keywords require "body" indenting rules (the
   1817      // non-standard-lisp ones are Scheme special forms):
   1818      // (let ((a 1))    instead    (let ((a 1))
   1819      //   (...))       of       (...))
   1820      if (((*that == '(') || (*that == '[')) && lisp_match(that + 1)) {
   1821        amount += 2;
   1822      } else {
   1823        if (*that != NUL) {
   1824          that++;
   1825          amount++;
   1826        }
   1827        colnr_T firsttry = amount;
   1828 
   1829        while (ascii_iswhite(*that)) {
   1830          amount += win_charsize(cstype, amount, that, (uint8_t)(*that), &csarg).width;
   1831          that++;
   1832        }
   1833 
   1834        if (*that && (*that != ';')) {
   1835          // Not a comment line.
   1836          // Test *that != '(' to accommodate first let/do
   1837          // argument if it is more than one line.
   1838          if ((*that != '(') && (*that != '[')) {
   1839            firsttry++;
   1840          }
   1841 
   1842          parencount = 0;
   1843 
   1844          CharInfo ci = utf_ptr2CharInfo(that);
   1845          if (((ci.value != '"') && (ci.value != '\'') && (ci.value != '#')
   1846               && ((ci.value < '0') || (ci.value > '9')))) {
   1847            int quotecount = 0;
   1848            while (*that && (!ascii_iswhite(ci.value) || quotecount || parencount)) {
   1849              if (ci.value == '"') {
   1850                quotecount = !quotecount;
   1851              }
   1852              if (((ci.value == '(') || (ci.value == '[')) && !quotecount) {
   1853                parencount++;
   1854              }
   1855              if (((ci.value == ')') || (ci.value == ']')) && !quotecount) {
   1856                parencount--;
   1857              }
   1858              if ((ci.value == '\\') && (*(that + 1) != NUL)) {
   1859                amount += win_charsize(cstype, amount, that, ci.value, &csarg).width;
   1860                StrCharInfo next_sci = utfc_next((StrCharInfo){ that, ci });
   1861                that = next_sci.ptr;
   1862                ci = next_sci.chr;
   1863              }
   1864 
   1865              amount += win_charsize(cstype, amount, that, ci.value, &csarg).width;
   1866              StrCharInfo next_sci = utfc_next((StrCharInfo){ that, ci });
   1867              that = next_sci.ptr;
   1868              ci = next_sci.chr;
   1869            }
   1870          }
   1871 
   1872          while (ascii_iswhite(*that)) {
   1873            amount += win_charsize(cstype, amount, that, (uint8_t)(*that), &csarg).width;
   1874            that++;
   1875          }
   1876 
   1877          if (!*that || (*that == ';')) {
   1878            amount = firsttry;
   1879          }
   1880        }
   1881      }
   1882    }
   1883  } else {
   1884    amount = 0;  // No matching '(' or '[' found, use zero indent.
   1885  }
   1886  curwin->w_cursor = realpos;
   1887 
   1888  return amount;
   1889 }
   1890 
   1891 static int lisp_match(char *p)
   1892 {
   1893  char buf[512];
   1894  char *word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords;
   1895 
   1896  while (*word != NUL) {
   1897    size_t len = copy_option_part(&word, buf, sizeof(buf), ",");
   1898    if ((strncmp(buf, p, len) == 0) && ascii_iswhite_or_nul(p[len])) {
   1899      return true;
   1900    }
   1901  }
   1902  return false;
   1903 }
   1904 
   1905 /// Re-indent the current line, based on the current contents of it and the
   1906 /// surrounding lines. Fixing the cursor position seems really easy -- I'm very
   1907 /// confused what all the part that handles Control-T is doing that I'm not.
   1908 /// "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
   1909 void fixthisline(IndentGetter get_the_indent)
   1910 {
   1911  int amount = get_the_indent();
   1912 
   1913  if (amount < 0) {
   1914    return;
   1915  }
   1916 
   1917  change_indent(INDENT_SET, amount, false, true);
   1918  if (linewhite(curwin->w_cursor.lnum)) {
   1919    did_ai = true;  // delete the indent if the line stays empty
   1920  }
   1921 }
   1922 
   1923 /// Return true if 'indentexpr' should be used for Lisp indenting.
   1924 /// Caller may want to check 'autoindent'.
   1925 bool use_indentexpr_for_lisp(void)
   1926 {
   1927  return curbuf->b_p_lisp
   1928         && *curbuf->b_p_inde != NUL
   1929         && strcmp(curbuf->b_p_lop, "expr:1") == 0;
   1930 }
   1931 
   1932 /// Fix indent for 'lisp' and 'cindent'.
   1933 void fix_indent(void)
   1934 {
   1935  if (p_paste) {
   1936    return;  // no auto-indenting when 'paste' is set
   1937  }
   1938  if (curbuf->b_p_lisp && curbuf->b_p_ai) {
   1939    if (use_indentexpr_for_lisp()) {
   1940      do_c_expr_indent();
   1941    } else {
   1942      fixthisline(get_lisp_indent);
   1943    }
   1944  } else if (cindent_on()) {
   1945    do_c_expr_indent();
   1946  }
   1947 }
   1948 
   1949 /// "indent()" function
   1950 void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   1951 {
   1952  const linenr_T lnum = tv_get_lnum(argvars);
   1953  if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
   1954    rettv->vval.v_number = get_indent_lnum(lnum);
   1955  } else {
   1956    rettv->vval.v_number = -1;
   1957  }
   1958 }
   1959 
   1960 /// "lispindent(lnum)" function
   1961 void f_lispindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   1962 {
   1963  const pos_T pos = curwin->w_cursor;
   1964  const linenr_T lnum = tv_get_lnum(argvars);
   1965  if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
   1966    curwin->w_cursor.lnum = lnum;
   1967    rettv->vval.v_number = get_lisp_indent();
   1968    curwin->w_cursor = pos;
   1969  } else {
   1970    rettv->vval.v_number = -1;
   1971  }
   1972 }