neovim

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

undo.c (97307B)


      1 // undo.c: multi level undo facility
      2 
      3 // The saved lines are stored in a list of lists (one for each buffer):
      4 //
      5 // b_u_oldhead------------------------------------------------+
      6 //                                                            |
      7 //                                                            V
      8 //                +--------------+    +--------------+    +--------------+
      9 // b_u_newhead--->| u_header     |    | u_header     |    | u_header     |
     10 //                |     uh_next------>|     uh_next------>|     uh_next---->NULL
     11 //         NULL<--------uh_prev  |<---------uh_prev  |<---------uh_prev  |
     12 //                |     uh_entry |    |     uh_entry |    |     uh_entry |
     13 //                +--------|-----+    +--------|-----+    +--------|-----+
     14 //                         |                   |                   |
     15 //                         V                   V                   V
     16 //                +--------------+    +--------------+    +--------------+
     17 //                | u_entry      |    | u_entry      |    | u_entry      |
     18 //                |     ue_next  |    |     ue_next  |    |     ue_next  |
     19 //                +--------|-----+    +--------|-----+    +--------|-----+
     20 //                         |                   |                   |
     21 //                         V                   V                   V
     22 //                +--------------+            NULL                NULL
     23 //                | u_entry      |
     24 //                |     ue_next  |
     25 //                +--------|-----+
     26 //                         |
     27 //                         V
     28 //                        etc.
     29 //
     30 // Each u_entry list contains the information for one undo or redo.
     31 // curbuf->b_u_curhead points to the header of the last undo (the next redo),
     32 // or is NULL if nothing has been undone (end of the branch).
     33 //
     34 // For keeping alternate undo/redo branches the uh_alt field is used.  Thus at
     35 // each point in the list a branch may appear for an alternate to redo.  The
     36 // uh_seq field is numbered sequentially to be able to find a newer or older
     37 // branch.
     38 //
     39 //                 +---------------+    +---------------+
     40 // b_u_oldhead --->| u_header      |    | u_header      |
     41 //                 |   uh_alt_next ---->|   uh_alt_next ----> NULL
     42 //         NULL <----- uh_alt_prev |<------ uh_alt_prev |
     43 //                 |   uh_prev     |    |   uh_prev     |
     44 //                 +-----|---------+    +-----|---------+
     45 //                       |                    |
     46 //                       V                    V
     47 //                 +---------------+    +---------------+
     48 //                 | u_header      |    | u_header      |
     49 //                 |   uh_alt_next |    |   uh_alt_next |
     50 // b_u_newhead --->|   uh_alt_prev |    |   uh_alt_prev |
     51 //                 |   uh_prev     |    |   uh_prev     |
     52 //                 +-----|---------+    +-----|---------+
     53 //                       |                    |
     54 //                       V                    V
     55 //                     NULL             +---------------+    +---------------+
     56 //                                      | u_header      |    | u_header      |
     57 //                                      |   uh_alt_next ---->|   uh_alt_next |
     58 //                                      |   uh_alt_prev |<------ uh_alt_prev |
     59 //                                      |   uh_prev     |    |   uh_prev     |
     60 //                                      +-----|---------+    +-----|---------+
     61 //                                            |                    |
     62 //                                           etc.                 etc.
     63 //
     64 //
     65 // All data is allocated and will all be freed when the buffer is unloaded.
     66 
     67 // Uncomment the next line for including the u_check() function.  This warns
     68 // for errors in the debug information.
     69 // #define U_DEBUG 1
     70 #define UH_MAGIC 0x18dade       // value for uh_magic when in use
     71 #define UE_MAGIC 0xabc123       // value for ue_magic when in use
     72 
     73 #include <assert.h>
     74 #include <fcntl.h>
     75 #include <inttypes.h>
     76 #include <stdbool.h>
     77 #include <stdio.h>
     78 #include <stdlib.h>
     79 #include <string.h>
     80 #include <time.h>
     81 #include <uv.h>
     82 
     83 #include "auto/config.h"
     84 #include "klib/kvec.h"
     85 #include "nvim/ascii_defs.h"
     86 #include "nvim/autocmd.h"
     87 #include "nvim/buffer.h"
     88 #include "nvim/buffer_defs.h"
     89 #include "nvim/buffer_updates.h"
     90 #include "nvim/change.h"
     91 #include "nvim/cursor.h"
     92 #include "nvim/drawscreen.h"
     93 #include "nvim/edit.h"
     94 #include "nvim/errors.h"
     95 #include "nvim/eval/funcs.h"
     96 #include "nvim/eval/typval.h"
     97 #include "nvim/ex_cmds_defs.h"
     98 #include "nvim/ex_docmd.h"
     99 #include "nvim/ex_getln.h"
    100 #include "nvim/extmark.h"
    101 #include "nvim/extmark_defs.h"
    102 #include "nvim/fileio.h"
    103 #include "nvim/fold.h"
    104 #include "nvim/garray.h"
    105 #include "nvim/garray_defs.h"
    106 #include "nvim/getchar.h"
    107 #include "nvim/gettext_defs.h"
    108 #include "nvim/globals.h"
    109 #include "nvim/highlight_defs.h"
    110 #include "nvim/macros_defs.h"
    111 #include "nvim/mark.h"
    112 #include "nvim/mark_defs.h"
    113 #include "nvim/mbyte.h"
    114 #include "nvim/memline.h"
    115 #include "nvim/memline_defs.h"
    116 #include "nvim/memory.h"
    117 #include "nvim/message.h"
    118 #include "nvim/option.h"
    119 #include "nvim/option_vars.h"
    120 #include "nvim/os/fs.h"
    121 #include "nvim/os/fs_defs.h"
    122 #include "nvim/os/input.h"
    123 #include "nvim/os/os_defs.h"
    124 #include "nvim/os/time.h"
    125 #include "nvim/os/time_defs.h"
    126 #include "nvim/path.h"
    127 #include "nvim/pos_defs.h"
    128 #include "nvim/sha256.h"
    129 #include "nvim/spell.h"
    130 #include "nvim/state.h"
    131 #include "nvim/strings.h"
    132 #include "nvim/types_defs.h"
    133 #include "nvim/undo.h"
    134 #include "nvim/undo_defs.h"
    135 #include "nvim/vim_defs.h"
    136 
    137 /// Structure passed around between undofile functions.
    138 typedef struct {
    139  buf_T *bi_buf;
    140  FILE *bi_fp;
    141 } bufinfo_T;
    142 
    143 #include "undo.c.generated.h"
    144 
    145 static const char e_undo_list_corrupt[]
    146  = N_("E439: Undo list corrupt");
    147 static const char e_undo_line_missing[]
    148  = N_("E440: Undo line missing");
    149 static const char e_write_error_in_undo_file_str[]
    150  = N_("E829: Write error in undo file: %s");
    151 
    152 // used in undo_end() to report number of added and deleted lines
    153 static int u_newcount, u_oldcount;
    154 
    155 // When 'u' flag included in 'cpoptions', we behave like vi.  Need to remember
    156 // the action that "u" should do.
    157 static bool undo_undoes = false;
    158 
    159 static int lastmark = 0;
    160 
    161 #if defined(U_DEBUG)
    162 // Check the undo structures for being valid.  Print a warning when something
    163 // looks wrong.
    164 static int seen_b_u_curhead;
    165 static int seen_b_u_newhead;
    166 static int header_count;
    167 
    168 static void u_check_tree(u_header_T *uhp, u_header_T *exp_uh_next, u_header_T *exp_uh_alt_prev)
    169 {
    170  if (uhp == NULL) {
    171    return;
    172  }
    173  header_count++;
    174  if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1) {
    175    emsg("b_u_curhead found twice (looping?)");
    176    return;
    177  }
    178  if (uhp == curbuf->b_u_newhead && ++seen_b_u_newhead > 1) {
    179    emsg("b_u_newhead found twice (looping?)");
    180    return;
    181  }
    182 
    183  if (uhp->uh_magic != UH_MAGIC) {
    184    emsg("uh_magic wrong (may be using freed memory)");
    185  } else {
    186    // Check pointers back are correct.
    187    if (uhp->uh_next.ptr != exp_uh_next) {
    188      emsg("uh_next wrong");
    189      smsg(0, "expected: 0x%x, actual: 0x%x",
    190           exp_uh_next, uhp->uh_next.ptr);
    191    }
    192    if (uhp->uh_alt_prev.ptr != exp_uh_alt_prev) {
    193      emsg("uh_alt_prev wrong");
    194      smsg(0, "expected: 0x%x, actual: 0x%x",
    195           exp_uh_alt_prev, uhp->uh_alt_prev.ptr);
    196    }
    197 
    198    // Check the undo tree at this header.
    199    for (u_entry_T *uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) {
    200      if (uep->ue_magic != UE_MAGIC) {
    201        emsg("ue_magic wrong (may be using freed memory)");
    202        break;
    203      }
    204    }
    205 
    206    // Check the next alt tree.
    207    u_check_tree(uhp->uh_alt_next.ptr, uhp->uh_next.ptr, uhp);
    208 
    209    // Check the next header in this branch.
    210    u_check_tree(uhp->uh_prev.ptr, uhp, NULL);
    211  }
    212 }
    213 
    214 static void u_check(int newhead_may_be_NULL)
    215 {
    216  seen_b_u_newhead = 0;
    217  seen_b_u_curhead = 0;
    218  header_count = 0;
    219 
    220  u_check_tree(curbuf->b_u_oldhead, NULL, NULL);
    221 
    222  if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL
    223      && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL)) {
    224    semsg("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead);
    225  }
    226  if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0) {
    227    semsg("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead);
    228  }
    229  if (header_count != curbuf->b_u_numhead) {
    230    emsg("b_u_numhead invalid");
    231    smsg(0, "expected: %" PRId64 ", actual: %" PRId64,
    232         (int64_t)header_count, (int64_t)curbuf->b_u_numhead);
    233  }
    234 }
    235 
    236 #endif
    237 
    238 /// Save the current line for both the "u" and "U" command.
    239 /// Careful: may trigger autocommands that reload the buffer.
    240 /// Returns OK or FAIL.
    241 int u_save_cursor(void)
    242 {
    243  linenr_T cur = curwin->w_cursor.lnum;
    244  linenr_T top = cur > 0 ? cur - 1 : 0;
    245  linenr_T bot = cur + 1;
    246 
    247  return u_save(top, bot);
    248 }
    249 
    250 /// Save the lines between "top" and "bot" for both the "u" and "U" command.
    251 /// "top" may be 0 and "bot" may be curbuf->b_ml.ml_line_count + 1.
    252 /// Careful: may trigger autocommands that reload the buffer.
    253 /// Returns FAIL when lines could not be saved, OK otherwise.
    254 int u_save(linenr_T top, linenr_T bot)
    255 {
    256  return u_save_buf(curbuf, top, bot);
    257 }
    258 
    259 int u_save_buf(buf_T *buf, linenr_T top, linenr_T bot)
    260 {
    261  if (top >= bot || bot > (buf->b_ml.ml_line_count + 1)) {
    262    return FAIL;        // rely on caller to do error messages
    263  }
    264 
    265  if (top + 2 == bot) {
    266    u_saveline(buf, top + 1);
    267  }
    268 
    269  return u_savecommon(buf, top, bot, 0, false);
    270 }
    271 
    272 /// Save the line "lnum" (used by ":s" and "~" command).
    273 /// The line is replaced, so the new bottom line is lnum + 1.
    274 /// Careful: may trigger autocommands that reload the buffer.
    275 /// Returns FAIL when lines could not be saved, OK otherwise.
    276 int u_savesub(linenr_T lnum)
    277 {
    278  return u_savecommon(curbuf, lnum - 1, lnum + 1, lnum + 1, false);
    279 }
    280 
    281 /// A new line is inserted before line "lnum" (used by :s command).
    282 /// The line is inserted, so the new bottom line is lnum + 1.
    283 /// Careful: may trigger autocommands that reload the buffer.
    284 /// Returns FAIL when lines could not be saved, OK otherwise.
    285 int u_inssub(linenr_T lnum)
    286 {
    287  return u_savecommon(curbuf, lnum - 1, lnum, lnum + 1, false);
    288 }
    289 
    290 /// Save the lines "lnum" - "lnum" + nlines (used by delete command).
    291 /// The lines are deleted, so the new bottom line is lnum, unless the buffer
    292 /// becomes empty.
    293 /// Careful: may trigger autocommands that reload the buffer.
    294 /// Returns FAIL when lines could not be saved, OK otherwise.
    295 int u_savedel(linenr_T lnum, linenr_T nlines)
    296 {
    297  return u_savecommon(curbuf, lnum - 1, lnum + nlines,
    298                      nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, false);
    299 }
    300 
    301 /// Return true when undo is allowed. Otherwise print an error message and
    302 /// return false.
    303 ///
    304 /// @return true if undo is allowed.
    305 bool undo_allowed(buf_T *buf)
    306 {
    307  // Don't allow changes when 'modifiable' is off.
    308  if (!MODIFIABLE(buf)) {
    309    emsg(_(e_modifiable));
    310    return false;
    311  }
    312 
    313  // In the sandbox it's not allowed to change the text.
    314  if (sandbox != 0) {
    315    emsg(_(e_sandbox));
    316    return false;
    317  }
    318 
    319  // Don't allow changes in the buffer while editing the cmdline.  The
    320  // caller of getcmdline() may get confused.
    321  if (textlock != 0 || expr_map_locked()) {
    322    emsg(_(e_textlock));
    323    return false;
    324  }
    325 
    326  return true;
    327 }
    328 
    329 /// Get the 'undolevels' value for the current buffer.
    330 static OptInt get_undolevel(buf_T *buf)
    331 {
    332  if (buf->b_p_ul == NO_LOCAL_UNDOLEVEL) {
    333    return p_ul;
    334  }
    335  return buf->b_p_ul;
    336 }
    337 
    338 static inline void zero_fmark_additional_data(fmark_T *fmarks)
    339 {
    340  for (size_t i = 0; i < NMARKS; i++) {
    341    XFREE_CLEAR(fmarks[i].additional_data);
    342  }
    343 }
    344 
    345 /// Common code for various ways to save text before a change.
    346 /// "top" is the line above the first changed line.
    347 /// "bot" is the line below the last changed line.
    348 /// "newbot" is the new bottom line.  Use zero when not known.
    349 /// "reload" is true when saving for a buffer reload.
    350 /// Careful: may trigger autocommands that reload the buffer.
    351 /// Returns FAIL when lines could not be saved, OK otherwise.
    352 int u_savecommon(buf_T *buf, linenr_T top, linenr_T bot, linenr_T newbot, bool reload)
    353 {
    354  if (!reload) {
    355    // When making changes is not allowed return FAIL.  It's a crude way
    356    // to make all change commands fail.
    357    if (!undo_allowed(buf)) {
    358      return FAIL;
    359    }
    360 
    361    // Saving text for undo means we are going to make a change.  Give a
    362    // warning for a read-only file before making the change, so that the
    363    // FileChangedRO event can replace the buffer with a read-write version
    364    // (e.g., obtained from a source control system).
    365    if (buf == curbuf) {
    366      change_warning(buf, 0);
    367    }
    368 
    369    if (bot > buf->b_ml.ml_line_count + 1) {
    370      //  This happens when the FileChangedRO autocommand changes the
    371      //  file in a way it becomes shorter.
    372      emsg(_("E881: Line count changed unexpectedly"));
    373      return FAIL;
    374    }
    375  }
    376 
    377 #ifdef U_DEBUG
    378  u_check(false);
    379 #endif
    380 
    381  u_entry_T *uep;
    382  u_entry_T *prev_uep;
    383  linenr_T size = bot - top - 1;
    384 
    385  // If buf->b_u_synced == true make a new header.
    386  if (buf->b_u_synced) {
    387    // Need to create new entry in b_changelist.
    388    buf->b_new_change = true;
    389 
    390    u_header_T *uhp;
    391    if (get_undolevel(buf) >= 0) {
    392      // Make a new header entry.  Do this first so that we don't mess
    393      // up the undo info when out of memory.
    394      uhp = xmalloc(sizeof(u_header_T));
    395      kv_init(uhp->uh_extmark);
    396 #ifdef U_DEBUG
    397      uhp->uh_magic = UH_MAGIC;
    398 #endif
    399    } else {
    400      uhp = NULL;
    401    }
    402 
    403    // If we undid more than we redid, move the entry lists before and
    404    // including buf->b_u_curhead to an alternate branch.
    405    u_header_T *old_curhead = buf->b_u_curhead;
    406    if (old_curhead != NULL) {
    407      buf->b_u_newhead = old_curhead->uh_next.ptr;
    408      buf->b_u_curhead = NULL;
    409    }
    410 
    411    // free headers to keep the size right
    412    while (buf->b_u_numhead > get_undolevel(buf)
    413           && buf->b_u_oldhead != NULL) {
    414      u_header_T *uhfree = buf->b_u_oldhead;
    415 
    416      if (uhfree == old_curhead) {
    417        // Can't reconnect the branch, delete all of it.
    418        u_freebranch(buf, uhfree, &old_curhead);
    419      } else if (uhfree->uh_alt_next.ptr == NULL) {
    420        // There is no branch, only free one header.
    421        u_freeheader(buf, uhfree, &old_curhead);
    422      } else {
    423        // Free the oldest alternate branch as a whole.
    424        while (uhfree->uh_alt_next.ptr != NULL) {
    425          uhfree = uhfree->uh_alt_next.ptr;
    426        }
    427        u_freebranch(buf, uhfree, &old_curhead);
    428      }
    429 #ifdef U_DEBUG
    430      u_check(true);
    431 #endif
    432    }
    433 
    434    if (uhp == NULL) {  // no undo at all
    435      if (old_curhead != NULL) {
    436        u_freebranch(buf, old_curhead, NULL);
    437      }
    438      buf->b_u_synced = false;
    439      return OK;
    440    }
    441 
    442    uhp->uh_prev.ptr = NULL;
    443    uhp->uh_next.ptr = buf->b_u_newhead;
    444    uhp->uh_alt_next.ptr = old_curhead;
    445    if (old_curhead != NULL) {
    446      uhp->uh_alt_prev.ptr = old_curhead->uh_alt_prev.ptr;
    447 
    448      if (uhp->uh_alt_prev.ptr != NULL) {
    449        uhp->uh_alt_prev.ptr->uh_alt_next.ptr = uhp;
    450      }
    451 
    452      old_curhead->uh_alt_prev.ptr = uhp;
    453 
    454      if (buf->b_u_oldhead == old_curhead) {
    455        buf->b_u_oldhead = uhp;
    456      }
    457    } else {
    458      uhp->uh_alt_prev.ptr = NULL;
    459    }
    460 
    461    if (buf->b_u_newhead != NULL) {
    462      buf->b_u_newhead->uh_prev.ptr = uhp;
    463    }
    464 
    465    uhp->uh_seq = ++buf->b_u_seq_last;
    466    buf->b_u_seq_cur = uhp->uh_seq;
    467    uhp->uh_time = time(NULL);
    468    uhp->uh_save_nr = 0;
    469    buf->b_u_time_cur = uhp->uh_time + 1;
    470 
    471    uhp->uh_walk = 0;
    472    uhp->uh_entry = NULL;
    473    uhp->uh_getbot_entry = NULL;
    474    uhp->uh_cursor = curwin->w_cursor;          // save cursor pos. for undo
    475    if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) {
    476      uhp->uh_cursor_vcol = getviscol();
    477    } else {
    478      uhp->uh_cursor_vcol = -1;
    479    }
    480 
    481    // save changed and buffer empty flag for undo
    482    uhp->uh_flags = (buf->b_changed ? UH_CHANGED : 0) +
    483                    ((buf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
    484 
    485    // save named marks and Visual marks for undo
    486    zero_fmark_additional_data(buf->b_namedm);
    487    memmove(uhp->uh_namedm, buf->b_namedm,
    488            sizeof(buf->b_namedm[0]) * NMARKS);
    489    uhp->uh_visual = buf->b_visual;
    490 
    491    buf->b_u_newhead = uhp;
    492 
    493    if (buf->b_u_oldhead == NULL) {
    494      buf->b_u_oldhead = uhp;
    495    }
    496    buf->b_u_numhead++;
    497  } else {
    498    if (get_undolevel(buf) < 0) {  // no undo at all
    499      return OK;
    500    }
    501 
    502    // When saving a single line, and it has been saved just before, it
    503    // doesn't make sense saving it again.  Saves a lot of memory when
    504    // making lots of changes inside the same line.
    505    // This is only possible if the previous change didn't increase or
    506    // decrease the number of lines.
    507    // Check the ten last changes.  More doesn't make sense and takes too
    508    // long.
    509    if (size == 1) {
    510      uep = u_get_headentry(buf);
    511      prev_uep = NULL;
    512      for (int i = 0; i < 10; i++) {
    513        if (uep == NULL) {
    514          break;
    515        }
    516 
    517        // If lines have been inserted/deleted we give up.
    518        // Also when the line was included in a multi-line save.
    519        if ((buf->b_u_newhead->uh_getbot_entry != uep
    520             ? (uep->ue_top + uep->ue_size + 1
    521                != (uep->ue_bot == 0
    522                    ? buf->b_ml.ml_line_count + 1
    523                    : uep->ue_bot))
    524             : uep->ue_lcount != buf->b_ml.ml_line_count)
    525            || (uep->ue_size > 1
    526                && top >= uep->ue_top
    527                && top + 2 <= uep->ue_top + uep->ue_size + 1)) {
    528          break;
    529        }
    530 
    531        // If it's the same line we can skip saving it again.
    532        if (uep->ue_size == 1 && uep->ue_top == top) {
    533          if (i > 0) {
    534            // It's not the last entry: get ue_bot for the last
    535            // entry now.  Following deleted/inserted lines go to
    536            // the re-used entry.
    537            u_getbot(buf);
    538            buf->b_u_synced = false;
    539 
    540            // Move the found entry to become the last entry.  The
    541            // order of undo/redo doesn't matter for the entries
    542            // we move it over, since they don't change the line
    543            // count and don't include this line.  It does matter
    544            // for the found entry if the line count is changed by
    545            // the executed command.
    546            prev_uep->ue_next = uep->ue_next;
    547            uep->ue_next = buf->b_u_newhead->uh_entry;
    548            buf->b_u_newhead->uh_entry = uep;
    549          }
    550 
    551          // The executed command may change the line count.
    552          if (newbot != 0) {
    553            uep->ue_bot = newbot;
    554          } else if (bot > buf->b_ml.ml_line_count) {
    555            uep->ue_bot = 0;
    556          } else {
    557            uep->ue_lcount = buf->b_ml.ml_line_count;
    558            buf->b_u_newhead->uh_getbot_entry = uep;
    559          }
    560          return OK;
    561        }
    562        prev_uep = uep;
    563        uep = uep->ue_next;
    564      }
    565    }
    566 
    567    // find line number for ue_bot for previous u_save()
    568    u_getbot(buf);
    569  }
    570 
    571  // add lines in front of entry list
    572  uep = xmalloc(sizeof(u_entry_T));
    573  CLEAR_POINTER(uep);
    574 #ifdef U_DEBUG
    575  uep->ue_magic = UE_MAGIC;
    576 #endif
    577 
    578  uep->ue_size = size;
    579  uep->ue_top = top;
    580  if (newbot != 0) {
    581    uep->ue_bot = newbot;
    582    // Use 0 for ue_bot if bot is below last line.
    583    // Otherwise we have to compute ue_bot later.
    584  } else if (bot > buf->b_ml.ml_line_count) {
    585    uep->ue_bot = 0;
    586  } else {
    587    uep->ue_lcount = buf->b_ml.ml_line_count;
    588    buf->b_u_newhead->uh_getbot_entry = uep;
    589  }
    590 
    591  if (size > 0) {
    592    uep->ue_array = xmalloc(sizeof(char *) * (size_t)size);
    593    linenr_T lnum;
    594    int i;
    595    for (i = 0, lnum = top + 1; i < size; i++) {
    596      fast_breakcheck();
    597      if (got_int) {
    598        u_freeentry(uep, i);
    599        return FAIL;
    600      }
    601      uep->ue_array[i] = u_save_line_buf(buf, lnum++);
    602    }
    603  } else {
    604    uep->ue_array = NULL;
    605  }
    606 
    607  uep->ue_next = buf->b_u_newhead->uh_entry;
    608  buf->b_u_newhead->uh_entry = uep;
    609  if (reload) {
    610    // buffer was reloaded, notify text change subscribers
    611    buf->b_u_newhead->uh_flags |= UH_RELOAD;
    612  }
    613  buf->b_u_synced = false;
    614  undo_undoes = false;
    615 
    616 #ifdef U_DEBUG
    617  u_check(false);
    618 #endif
    619  return OK;
    620 }
    621 
    622 // magic at start of undofile
    623 #define UF_START_MAGIC     "Vim\237UnDo\345"
    624 #define UF_START_MAGIC_LEN     9
    625 // magic at start of header
    626 #define UF_HEADER_MAGIC        0x5fd0
    627 // magic after last header
    628 #define UF_HEADER_END_MAGIC    0xe7aa
    629 // magic at start of entry
    630 #define UF_ENTRY_MAGIC         0xf518
    631 // magic after last entry
    632 #define UF_ENTRY_END_MAGIC     0x3581
    633 
    634 // 2-byte undofile version number
    635 #define UF_VERSION             3
    636 
    637 // extra fields for header
    638 #define UF_LAST_SAVE_NR        1
    639 
    640 // extra fields for uhp
    641 #define UHP_SAVE_NR            1
    642 
    643 static const char e_not_open[] = N_("E828: Cannot open undo file for writing: %s");
    644 
    645 /// Compute the hash for a buffer text into hash[UNDO_HASH_SIZE].
    646 ///
    647 /// @param[in] buf The buffer used to compute the hash
    648 /// @param[in] hash Array of size UNDO_HASH_SIZE in which to store the value of
    649 ///                 the hash
    650 void u_compute_hash(buf_T *buf, uint8_t *hash)
    651 {
    652  context_sha256_T ctx;
    653  sha256_start(&ctx);
    654  for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
    655    char *p = ml_get_buf(buf, lnum);
    656    sha256_update(&ctx, (uint8_t *)p, strlen(p) + 1);
    657  }
    658  sha256_finish(&ctx, hash);
    659 }
    660 
    661 /// Return an allocated string of the full path of the target undofile.
    662 ///
    663 /// @param[in]  buf_ffname  Full file name for which undo file location should
    664 ///                         be found.
    665 /// @param[in]  reading  If true, find the file to read by traversing all of the
    666 ///                      directories in &undodir. If false use the first
    667 ///                      existing directory. If none of the directories in
    668 ///                      &undodir option exist then last directory in the list
    669 ///                      will be automatically created.
    670 ///
    671 /// @return [allocated] File name to read from/write to or NULL.
    672 char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
    673  FUNC_ATTR_WARN_UNUSED_RESULT
    674 {
    675  const char *ffname = buf_ffname;
    676 
    677  if (ffname == NULL) {
    678    return NULL;
    679  }
    680 
    681 #ifdef HAVE_READLINK
    682  char fname_buf[MAXPATHL];
    683  // Expand symlink in the file name, so that we put the undo file with the
    684  // actual file instead of with the symlink.
    685  if (resolve_symlink(ffname, fname_buf) == OK) {
    686    ffname = fname_buf;
    687  }
    688 #endif
    689 
    690  char dir_name[MAXPATHL + 1];
    691  char *munged_name = NULL;
    692  char *undo_file_name = NULL;
    693 
    694  // Loop over 'undodir'.  When reading find the first file that exists.
    695  // When not reading use the first directory that exists or ".".
    696  char *dirp = p_udir;
    697  while (*dirp != NUL) {
    698    size_t dir_len = copy_option_part(&dirp, dir_name, MAXPATHL, ",");
    699    if (dir_len == 1 && dir_name[0] == '.') {
    700      // Use same directory as the ffname,
    701      // "dir/name" -> "dir/.name.un~"
    702      const size_t ffname_len = strlen(ffname);
    703      undo_file_name = xmalloc(ffname_len + 6);
    704      memmove(undo_file_name, ffname, ffname_len + 1);
    705      char *const tail = path_tail(undo_file_name);
    706      const size_t tail_len = strlen(tail);
    707      memmove(tail + 1, tail, tail_len + 1);
    708      *tail = '.';
    709      memmove(tail + tail_len + 1, ".un~", sizeof(".un~"));
    710    } else {
    711      dir_name[dir_len] = NUL;
    712 
    713      // Remove trailing pathseps from directory name
    714      char *p = &dir_name[dir_len - 1];
    715      while (vim_ispathsep(*p)) {
    716        *p-- = NUL;
    717      }
    718 
    719      bool has_directory = os_isdir(dir_name);
    720      if (!has_directory && *dirp == NUL && !reading) {
    721        // Last directory in the list does not exist, create it.
    722        int ret;
    723        char *failed_dir;
    724        if ((ret = os_mkdir_recurse(dir_name, 0755, &failed_dir, NULL)) != 0) {
    725          semsg(_("E5003: Unable to create directory \"%s\" for undo file: %s"),
    726                failed_dir, os_strerror(ret));
    727          xfree(failed_dir);
    728        } else {
    729          has_directory = true;
    730        }
    731      }
    732      if (has_directory) {
    733        if (munged_name == NULL) {
    734          munged_name = xstrdup(ffname);
    735          for (char *c = munged_name; *c != NUL; MB_PTR_ADV(c)) {
    736            if (vim_ispathsep(*c)) {
    737              *c = '%';
    738            }
    739          }
    740        }
    741        undo_file_name = concat_fnames(dir_name, munged_name, true);
    742      }
    743    }
    744 
    745    // When reading check if the file exists.
    746    if (undo_file_name != NULL
    747        && (!reading || os_path_exists(undo_file_name))) {
    748      break;
    749    }
    750    XFREE_CLEAR(undo_file_name);
    751  }
    752 
    753  xfree(munged_name);
    754  return undo_file_name;
    755 }
    756 
    757 /// Display an error for corrupted undo file
    758 ///
    759 /// @param[in]  mesg  Identifier of the corruption kind.
    760 /// @param[in]  file_name  File in which error occurred.
    761 static void corruption_error(const char *const mesg, const char *const file_name)
    762  FUNC_ATTR_NONNULL_ALL
    763 {
    764  semsg(_("E825: Corrupted undo file (%s): %s"), mesg, file_name);
    765 }
    766 
    767 static void u_free_uhp(u_header_T *uhp)
    768 {
    769  u_entry_T *uep = uhp->uh_entry;
    770  while (uep != NULL) {
    771    u_entry_T *nuep = uep->ue_next;
    772    u_freeentry(uep, uep->ue_size);
    773    uep = nuep;
    774  }
    775  xfree(uhp);
    776 }
    777 
    778 /// Writes the undofile header.
    779 ///
    780 /// @param bi   The buffer information
    781 /// @param hash The hash of the buffer contents
    782 //
    783 /// @returns false in case of an error.
    784 static bool serialize_header(bufinfo_T *bi, uint8_t *hash)
    785  FUNC_ATTR_NONNULL_ALL
    786 {
    787  buf_T *buf = bi->bi_buf;
    788  FILE *fp = bi->bi_fp;
    789 
    790  // Start writing, first the magic marker and undo info version.
    791  if (fwrite(UF_START_MAGIC, UF_START_MAGIC_LEN, 1, fp) != 1) {
    792    return false;
    793  }
    794 
    795  undo_write_bytes(bi, UF_VERSION, 2);
    796 
    797  // Write a hash of the buffer text, so that we can verify it is
    798  // still the same when reading the buffer text.
    799  if (!undo_write(bi, hash, UNDO_HASH_SIZE)) {
    800    return false;
    801  }
    802 
    803  // Write buffer-specific data.
    804  undo_write_bytes(bi, (uintmax_t)buf->b_ml.ml_line_count, 4);
    805  size_t len = buf->b_u_line_ptr ? strlen(buf->b_u_line_ptr) : 0;
    806  undo_write_bytes(bi, len, 4);
    807  if (len > 0 && !undo_write(bi, (uint8_t *)buf->b_u_line_ptr, len)) {
    808    return false;
    809  }
    810  undo_write_bytes(bi, (uintmax_t)buf->b_u_line_lnum, 4);
    811  undo_write_bytes(bi, (uintmax_t)buf->b_u_line_colnr, 4);
    812 
    813  // Write undo structures header data.
    814  put_header_ptr(bi, buf->b_u_oldhead);
    815  put_header_ptr(bi, buf->b_u_newhead);
    816  put_header_ptr(bi, buf->b_u_curhead);
    817 
    818  undo_write_bytes(bi, (uintmax_t)buf->b_u_numhead, 4);
    819  undo_write_bytes(bi, (uintmax_t)buf->b_u_seq_last, 4);
    820  undo_write_bytes(bi, (uintmax_t)buf->b_u_seq_cur, 4);
    821  uint8_t time_buf[8];
    822  time_to_bytes(buf->b_u_time_cur, time_buf);
    823  undo_write(bi, time_buf, sizeof(time_buf));
    824 
    825  // Write optional fields.
    826  undo_write_bytes(bi, 4, 1);
    827  undo_write_bytes(bi, UF_LAST_SAVE_NR, 1);
    828  undo_write_bytes(bi, (uintmax_t)buf->b_u_save_nr_last, 4);
    829 
    830  // Write end marker.
    831  undo_write_bytes(bi, 0, 1);
    832 
    833  return true;
    834 }
    835 
    836 /// Writes an undo header.
    837 ///
    838 /// @param bi  The buffer information
    839 /// @param uhp The undo header to write
    840 //
    841 /// @returns false in case of an error.
    842 static bool serialize_uhp(bufinfo_T *bi, u_header_T *uhp)
    843 {
    844  if (!undo_write_bytes(bi, (uintmax_t)UF_HEADER_MAGIC, 2)) {
    845    return false;
    846  }
    847 
    848  put_header_ptr(bi, uhp->uh_next.ptr);
    849  put_header_ptr(bi, uhp->uh_prev.ptr);
    850  put_header_ptr(bi, uhp->uh_alt_next.ptr);
    851  put_header_ptr(bi, uhp->uh_alt_prev.ptr);
    852  undo_write_bytes(bi, (uintmax_t)uhp->uh_seq, 4);
    853  serialize_pos(bi, uhp->uh_cursor);
    854  undo_write_bytes(bi, (uintmax_t)uhp->uh_cursor_vcol, 4);
    855  undo_write_bytes(bi, (uintmax_t)uhp->uh_flags, 2);
    856  // Assume NMARKS will stay the same.
    857  for (size_t i = 0; i < (size_t)NMARKS; i++) {
    858    serialize_pos(bi, uhp->uh_namedm[i].mark);
    859  }
    860  serialize_visualinfo(bi, &uhp->uh_visual);
    861  uint8_t time_buf[8];
    862  time_to_bytes(uhp->uh_time, time_buf);
    863  undo_write(bi, time_buf, sizeof(time_buf));
    864 
    865  // Write optional fields.
    866  undo_write_bytes(bi, 4, 1);
    867  undo_write_bytes(bi, UHP_SAVE_NR, 1);
    868  undo_write_bytes(bi, (uintmax_t)uhp->uh_save_nr, 4);
    869 
    870  // Write end marker.
    871  undo_write_bytes(bi, 0, 1);
    872 
    873  // Write all the entries.
    874  for (u_entry_T *uep = uhp->uh_entry; uep; uep = uep->ue_next) {
    875    undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
    876    if (!serialize_uep(bi, uep)) {
    877      return false;
    878    }
    879  }
    880  undo_write_bytes(bi, (uintmax_t)UF_ENTRY_END_MAGIC, 2);
    881 
    882  // Write all extmark undo objects
    883  for (size_t i = 0; i < kv_size(uhp->uh_extmark); i++) {
    884    if (!serialize_extmark(bi, kv_A(uhp->uh_extmark, i))) {
    885      return false;
    886    }
    887  }
    888  undo_write_bytes(bi, (uintmax_t)UF_ENTRY_END_MAGIC, 2);
    889 
    890  return true;
    891 }
    892 
    893 static u_header_T *unserialize_uhp(bufinfo_T *bi, const char *file_name)
    894 {
    895  u_header_T *uhp = xmalloc(sizeof(u_header_T));
    896  CLEAR_POINTER(uhp);
    897 #ifdef U_DEBUG
    898  uhp->uh_magic = UH_MAGIC;
    899 #endif
    900  uhp->uh_next.seq = undo_read_4c(bi);
    901  uhp->uh_prev.seq = undo_read_4c(bi);
    902  uhp->uh_alt_next.seq = undo_read_4c(bi);
    903  uhp->uh_alt_prev.seq = undo_read_4c(bi);
    904  uhp->uh_seq = undo_read_4c(bi);
    905  if (uhp->uh_seq <= 0) {
    906    corruption_error("uh_seq", file_name);
    907    xfree(uhp);
    908    return NULL;
    909  }
    910  unserialize_pos(bi, &uhp->uh_cursor);
    911  uhp->uh_cursor_vcol = undo_read_4c(bi);
    912  uhp->uh_flags = undo_read_2c(bi);
    913  const Timestamp cur_timestamp = os_time();
    914  for (size_t i = 0; i < (size_t)NMARKS; i++) {
    915    unserialize_pos(bi, &uhp->uh_namedm[i].mark);
    916    uhp->uh_namedm[i].timestamp = cur_timestamp;
    917    uhp->uh_namedm[i].fnum = 0;
    918  }
    919  unserialize_visualinfo(bi, &uhp->uh_visual);
    920  uhp->uh_time = undo_read_time(bi);
    921 
    922  // Unserialize optional fields.
    923  while (true) {
    924    int len = undo_read_byte(bi);
    925 
    926    if (len == EOF) {
    927      corruption_error("truncated", file_name);
    928      u_free_uhp(uhp);
    929      return NULL;
    930    }
    931    if (len == 0) {
    932      break;
    933    }
    934    int what = undo_read_byte(bi);
    935    switch (what) {
    936    case UHP_SAVE_NR:
    937      uhp->uh_save_nr = undo_read_4c(bi);
    938      break;
    939    default:
    940      // Field not supported, skip it.
    941      while (--len >= 0) {
    942        undo_read_byte(bi);
    943      }
    944    }
    945  }
    946 
    947  // Unserialize the uep list.
    948  u_entry_T *last_uep = NULL;
    949  int c;
    950  while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC) {
    951    bool error = false;
    952    u_entry_T *uep = unserialize_uep(bi, &error, file_name);
    953    if (last_uep == NULL) {
    954      uhp->uh_entry = uep;
    955    } else {
    956      last_uep->ue_next = uep;
    957    }
    958    last_uep = uep;
    959    if (uep == NULL || error) {
    960      u_free_uhp(uhp);
    961      return NULL;
    962    }
    963  }
    964  if (c != UF_ENTRY_END_MAGIC) {
    965    corruption_error("entry end", file_name);
    966    u_free_uhp(uhp);
    967    return NULL;
    968  }
    969 
    970  // Unserialize all extmark undo information
    971  kv_init(uhp->uh_extmark);
    972 
    973  while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC) {
    974    bool error = false;
    975    ExtmarkUndoObject *extup = unserialize_extmark(bi, &error, file_name);
    976    if (error) {
    977      kv_destroy(uhp->uh_extmark);
    978      xfree(extup);
    979      return NULL;
    980    }
    981    kv_push(uhp->uh_extmark, *extup);
    982    xfree(extup);
    983  }
    984  if (c != UF_ENTRY_END_MAGIC) {
    985    corruption_error("entry end", file_name);
    986    u_free_uhp(uhp);
    987    return NULL;
    988  }
    989 
    990  return uhp;
    991 }
    992 
    993 static bool serialize_extmark(bufinfo_T *bi, ExtmarkUndoObject extup)
    994 {
    995  if (extup.type == kExtmarkSplice) {
    996    undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
    997    undo_write_bytes(bi, (uintmax_t)extup.type, 4);
    998    if (!undo_write(bi, (uint8_t *)&(extup.data.splice),
    999                    sizeof(ExtmarkSplice))) {
   1000      return false;
   1001    }
   1002  } else if (extup.type == kExtmarkMove) {
   1003    undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
   1004    undo_write_bytes(bi, (uintmax_t)extup.type, 4);
   1005    if (!undo_write(bi, (uint8_t *)&(extup.data.move), sizeof(ExtmarkMove))) {
   1006      return false;
   1007    }
   1008  }
   1009  // Note: We do not serialize ExtmarkSavePos information, since
   1010  // buffer marktrees are not retained when closing/reopening a file
   1011  return true;
   1012 }
   1013 
   1014 static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error, const char *filename)
   1015 {
   1016  uint8_t *buf = NULL;
   1017 
   1018  ExtmarkUndoObject *extup = xmalloc(sizeof(ExtmarkUndoObject));
   1019 
   1020  UndoObjectType type = (UndoObjectType)undo_read_4c(bi);
   1021  extup->type = type;
   1022  if (type == kExtmarkSplice) {
   1023    size_t n_elems = (size_t)sizeof(ExtmarkSplice) / sizeof(uint8_t);
   1024    buf = xcalloc(n_elems, sizeof(uint8_t));
   1025    if (!undo_read(bi, buf, n_elems)) {
   1026      goto error;
   1027    }
   1028    extup->data.splice = *(ExtmarkSplice *)buf;
   1029  } else if (type == kExtmarkMove) {
   1030    size_t n_elems = (size_t)sizeof(ExtmarkMove) / sizeof(uint8_t);
   1031    buf = xcalloc(n_elems, sizeof(uint8_t));
   1032    if (!undo_read(bi, buf, n_elems)) {
   1033      goto error;
   1034    }
   1035    extup->data.move = *(ExtmarkMove *)buf;
   1036  } else {
   1037    goto error;
   1038  }
   1039 
   1040  xfree(buf);
   1041 
   1042  return extup;
   1043 
   1044 error:
   1045  xfree(extup);
   1046  if (buf) {
   1047    xfree(buf);
   1048  }
   1049  *error = true;
   1050  return NULL;
   1051 }
   1052 
   1053 /// Serializes "uep".
   1054 ///
   1055 /// @param bi  The buffer information
   1056 /// @param uep The undo entry to write
   1057 //
   1058 /// @returns false in case of an error.
   1059 static bool serialize_uep(bufinfo_T *bi, u_entry_T *uep)
   1060 {
   1061  undo_write_bytes(bi, (uintmax_t)uep->ue_top, 4);
   1062  undo_write_bytes(bi, (uintmax_t)uep->ue_bot, 4);
   1063  undo_write_bytes(bi, (uintmax_t)uep->ue_lcount, 4);
   1064  undo_write_bytes(bi, (uintmax_t)uep->ue_size, 4);
   1065 
   1066  for (size_t i = 0; i < (size_t)uep->ue_size; i++) {
   1067    size_t len = strlen(uep->ue_array[i]);
   1068    if (!undo_write_bytes(bi, len, 4)) {
   1069      return false;
   1070    }
   1071    if (len > 0 && !undo_write(bi, (uint8_t *)uep->ue_array[i], len)) {
   1072      return false;
   1073    }
   1074  }
   1075  return true;
   1076 }
   1077 
   1078 static u_entry_T *unserialize_uep(bufinfo_T *bi, bool *error, const char *file_name)
   1079 {
   1080  u_entry_T *uep = xmalloc(sizeof(u_entry_T));
   1081  CLEAR_POINTER(uep);
   1082 #ifdef U_DEBUG
   1083  uep->ue_magic = UE_MAGIC;
   1084 #endif
   1085  uep->ue_top = undo_read_4c(bi);
   1086  uep->ue_bot = undo_read_4c(bi);
   1087  uep->ue_lcount = undo_read_4c(bi);
   1088  uep->ue_size = undo_read_4c(bi);
   1089 
   1090  char **array = NULL;
   1091  if (uep->ue_size > 0) {
   1092    if ((size_t)uep->ue_size < SIZE_MAX / sizeof(char *)) {
   1093      array = xmalloc(sizeof(char *) * (size_t)uep->ue_size);
   1094      memset(array, 0, sizeof(char *) * (size_t)uep->ue_size);
   1095    }
   1096  }
   1097  uep->ue_array = array;
   1098 
   1099  for (size_t i = 0; i < (size_t)uep->ue_size; i++) {
   1100    int line_len = undo_read_4c(bi);
   1101    char *line;
   1102    if (line_len >= 0) {
   1103      line = undo_read_string(bi, (size_t)line_len);
   1104    } else {
   1105      line = NULL;
   1106      corruption_error("line length", file_name);
   1107    }
   1108    if (line == NULL) {
   1109      *error = true;
   1110      return uep;
   1111    }
   1112    array[i] = line;
   1113  }
   1114  return uep;
   1115 }
   1116 
   1117 /// Serializes "pos".
   1118 static void serialize_pos(bufinfo_T *bi, pos_T pos)
   1119 {
   1120  undo_write_bytes(bi, (uintmax_t)pos.lnum, 4);
   1121  undo_write_bytes(bi, (uintmax_t)pos.col, 4);
   1122  undo_write_bytes(bi, (uintmax_t)pos.coladd, 4);
   1123 }
   1124 
   1125 /// Unserializes the pos_T at the current position.
   1126 static void unserialize_pos(bufinfo_T *bi, pos_T *pos)
   1127 {
   1128  pos->lnum = undo_read_4c(bi);
   1129  pos->lnum = MAX(pos->lnum, 0);
   1130  pos->col = undo_read_4c(bi);
   1131  pos->col = MAX(pos->col, 0);
   1132  pos->coladd = undo_read_4c(bi);
   1133  pos->coladd = MAX(pos->coladd, 0);
   1134 }
   1135 
   1136 /// Serializes "info".
   1137 static void serialize_visualinfo(bufinfo_T *bi, visualinfo_T *info)
   1138 {
   1139  serialize_pos(bi, info->vi_start);
   1140  serialize_pos(bi, info->vi_end);
   1141  undo_write_bytes(bi, (uintmax_t)info->vi_mode, 4);
   1142  undo_write_bytes(bi, (uintmax_t)info->vi_curswant, 4);
   1143 }
   1144 
   1145 /// Unserializes the visualinfo_T at the current position.
   1146 static void unserialize_visualinfo(bufinfo_T *bi, visualinfo_T *info)
   1147 {
   1148  unserialize_pos(bi, &info->vi_start);
   1149  unserialize_pos(bi, &info->vi_end);
   1150  info->vi_mode = undo_read_4c(bi);
   1151  info->vi_curswant = undo_read_4c(bi);
   1152 }
   1153 
   1154 /// Write the undo tree in an undo file.
   1155 ///
   1156 /// @param[in]  name  Name of the undo file or NULL if this function needs to
   1157 ///                   generate the undo file name based on buf->b_ffname.
   1158 /// @param[in]  forceit  True for `:wundo!`, false otherwise.
   1159 /// @param[in]  buf  Buffer for which undo file is written.
   1160 /// @param[in]  hash  Hash value of the buffer text. Must have #UNDO_HASH_SIZE
   1161 ///                   size.
   1162 void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, uint8_t *const hash)
   1163  FUNC_ATTR_NONNULL_ARG(3, 4)
   1164 {
   1165  char *file_name;
   1166 #ifdef U_DEBUG
   1167  int headers_written = 0;
   1168 #endif
   1169  FILE *fp = NULL;
   1170  bool write_ok = false;
   1171 
   1172  if (name == NULL) {
   1173    file_name = u_get_undo_file_name(buf->b_ffname, false);
   1174    if (file_name == NULL) {
   1175      if (p_verbose > 0) {
   1176        verbose_enter();
   1177        smsg(0, "%s", _("Cannot write undo file in any directory in 'undodir'"));
   1178        verbose_leave();
   1179      }
   1180      return;
   1181    }
   1182  } else {
   1183    file_name = (char *)name;
   1184  }
   1185 
   1186  // Decide about the permission to use for the undo file.  If the buffer
   1187  // has a name use the permission of the original file.  Otherwise only
   1188  // allow the user to access the undo file.
   1189  int perm = 0600;
   1190  if (buf->b_ffname != NULL) {
   1191    perm = os_getperm(buf->b_ffname);
   1192    if (perm < 0) {
   1193      perm = 0600;
   1194    }
   1195  }
   1196 
   1197  // Strip any sticky and executable bits.
   1198  perm = perm & 0666;
   1199 
   1200  // If the undo file already exists, verify that it actually is an undo
   1201  // file, and delete it.
   1202  if (os_path_exists(file_name)) {
   1203    if (name == NULL || !forceit) {
   1204      // Check we can read it and it's an undo file.
   1205      int fd = os_open(file_name, O_RDONLY, 0);
   1206      if (fd < 0) {
   1207        if (name != NULL || p_verbose > 0) {
   1208          if (name == NULL) {
   1209            verbose_enter();
   1210          }
   1211          smsg(0, _("Will not overwrite with undo file, cannot read: %s"),
   1212               file_name);
   1213          if (name == NULL) {
   1214            verbose_leave();
   1215          }
   1216        }
   1217        goto theend;
   1218      } else {
   1219        char mbuf[UF_START_MAGIC_LEN];
   1220        ssize_t len = read_eintr(fd, mbuf, UF_START_MAGIC_LEN);
   1221        close(fd);
   1222        if (len < UF_START_MAGIC_LEN
   1223            || memcmp(mbuf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0) {
   1224          if (name != NULL || p_verbose > 0) {
   1225            if (name == NULL) {
   1226              verbose_enter();
   1227            }
   1228            smsg(0, _("Will not overwrite, this is not an undo file: %s"),
   1229                 file_name);
   1230            if (name == NULL) {
   1231              verbose_leave();
   1232            }
   1233          }
   1234          goto theend;
   1235        }
   1236      }
   1237    }
   1238    os_remove(file_name);
   1239  }
   1240 
   1241  // If there is no undo information at all, quit here after deleting any
   1242  // existing undo file.
   1243  if (buf->b_u_numhead == 0 && buf->b_u_line_ptr == NULL) {
   1244    if (p_verbose > 0) {
   1245      verb_msg(_("Skipping undo file write, nothing to undo"));
   1246    }
   1247    goto theend;
   1248  }
   1249 
   1250  int fd = os_open(file_name, O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
   1251  if (fd < 0) {
   1252    semsg(_(e_not_open), file_name);
   1253    goto theend;
   1254  }
   1255  os_setperm(file_name, perm);
   1256  if (p_verbose > 0) {
   1257    verbose_enter();
   1258    smsg(0, _("Writing undo file: %s"), file_name);
   1259    verbose_leave();
   1260  }
   1261 
   1262 #ifdef U_DEBUG
   1263  // Check there is no problem in undo info before writing.
   1264  u_check(false);
   1265 #endif
   1266 
   1267 #ifdef UNIX
   1268  // Try to set the group of the undo file same as the original file. If
   1269  // this fails, set the protection bits for the group same as the
   1270  // protection bits for others.
   1271  FileInfo file_info_old;
   1272  FileInfo file_info_new;
   1273  if (buf->b_ffname != NULL
   1274      && os_fileinfo(buf->b_ffname, &file_info_old)
   1275      && os_fileinfo(file_name, &file_info_new)
   1276      && file_info_old.stat.st_gid != file_info_new.stat.st_gid
   1277      && os_fchown(fd, (uv_uid_t)-1, (uv_gid_t)file_info_old.stat.st_gid)) {
   1278    os_setperm(file_name, (perm & 0707) | ((perm & 07) << 3));
   1279  }
   1280 #endif
   1281 
   1282  fp = fdopen(fd, "w");
   1283  if (fp == NULL) {
   1284    semsg(_(e_not_open), file_name);
   1285    close(fd);
   1286    os_remove(file_name);
   1287    goto theend;
   1288  }
   1289 
   1290  // Undo must be synced.
   1291  u_sync(true);
   1292 
   1293  // Write the header.
   1294  bufinfo_T bi = {
   1295    .bi_buf = buf,
   1296    .bi_fp = fp,
   1297  };
   1298  if (!serialize_header(&bi, hash)) {
   1299    goto write_error;
   1300  }
   1301 
   1302  // Iteratively serialize UHPs and their UEPs from the top down.
   1303  int mark = ++lastmark;
   1304  u_header_T *uhp = buf->b_u_oldhead;
   1305  while (uhp != NULL) {
   1306    // Serialize current UHP if we haven't seen it
   1307    if (uhp->uh_walk != mark) {
   1308      uhp->uh_walk = mark;
   1309 #ifdef U_DEBUG
   1310      headers_written++;
   1311 #endif
   1312      if (!serialize_uhp(&bi, uhp)) {
   1313        goto write_error;
   1314      }
   1315    }
   1316 
   1317    // Now walk through the tree - algorithm from undo_time().
   1318    if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark) {
   1319      uhp = uhp->uh_prev.ptr;
   1320    } else if (uhp->uh_alt_next.ptr != NULL
   1321               && uhp->uh_alt_next.ptr->uh_walk != mark) {
   1322      uhp = uhp->uh_alt_next.ptr;
   1323    } else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
   1324               && uhp->uh_next.ptr->uh_walk != mark) {
   1325      uhp = uhp->uh_next.ptr;
   1326    } else if (uhp->uh_alt_prev.ptr != NULL) {
   1327      uhp = uhp->uh_alt_prev.ptr;
   1328    } else {
   1329      uhp = uhp->uh_next.ptr;
   1330    }
   1331  }
   1332 
   1333  if (undo_write_bytes(&bi, (uintmax_t)UF_HEADER_END_MAGIC, 2)) {
   1334    write_ok = true;
   1335  }
   1336 #ifdef U_DEBUG
   1337  if (headers_written != buf->b_u_numhead) {
   1338    semsg("Written %" PRId64 " headers, ...", (int64_t)headers_written);
   1339    semsg("... but numhead is %" PRId64, (int64_t)buf->b_u_numhead);
   1340  }
   1341 #endif
   1342 
   1343  if ((buf->b_p_fs >= 0 ? buf->b_p_fs : p_fs) && fflush(fp) == 0
   1344      && os_fsync(fd) != 0) {
   1345    write_ok = false;
   1346  }
   1347 
   1348 write_error:
   1349  fclose(fp);
   1350  if (!write_ok) {
   1351    semsg(_(e_write_error_in_undo_file_str), file_name);
   1352  }
   1353 
   1354  if (buf->b_ffname != NULL) {
   1355    // For systems that support ACL: get the ACL from the original file.
   1356    vim_acl_T acl = os_get_acl(buf->b_ffname);
   1357    os_set_acl(file_name, acl);
   1358    os_free_acl(acl);
   1359  }
   1360 
   1361 theend:
   1362  if (file_name != name) {
   1363    xfree(file_name);
   1364  }
   1365 }
   1366 
   1367 /// Loads the undo tree from an undo file.
   1368 /// If "name" is not NULL use it as the undo file name. This also means being
   1369 /// a bit more verbose.
   1370 /// Otherwise use curbuf->b_ffname to generate the undo file name.
   1371 /// "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
   1372 void u_read_undo(char *name, const uint8_t *hash, const char *orig_name FUNC_ATTR_UNUSED)
   1373  FUNC_ATTR_NONNULL_ARG(2)
   1374 {
   1375  u_header_T **uhp_table = NULL;
   1376  char *line_ptr = NULL;
   1377 
   1378  char *file_name;
   1379  if (name == NULL) {
   1380    file_name = u_get_undo_file_name(curbuf->b_ffname, true);
   1381    if (file_name == NULL) {
   1382      return;
   1383    }
   1384 
   1385 #ifdef UNIX
   1386    // For safety we only read an undo file if the owner is equal to the
   1387    // owner of the text file or equal to the current user.
   1388    FileInfo file_info_orig;
   1389    FileInfo file_info_undo;
   1390    if (os_fileinfo(orig_name, &file_info_orig)
   1391        && os_fileinfo(file_name, &file_info_undo)
   1392        && file_info_orig.stat.st_uid != file_info_undo.stat.st_uid
   1393        && file_info_undo.stat.st_uid != getuid()) {
   1394      if (p_verbose > 0) {
   1395        verbose_enter();
   1396        smsg(0, _("Not reading undo file, owner differs: %s"),
   1397             file_name);
   1398        verbose_leave();
   1399      }
   1400      return;
   1401    }
   1402 #endif
   1403  } else {
   1404    file_name = name;
   1405  }
   1406 
   1407  if (p_verbose > 0) {
   1408    verbose_enter();
   1409    smsg(0, _("Reading undo file: %s"), file_name);
   1410    verbose_leave();
   1411  }
   1412 
   1413  FILE *fp = os_fopen(file_name, "r");
   1414  if (fp == NULL) {
   1415    if (name != NULL || p_verbose > 0) {
   1416      semsg(_("E822: Cannot open undo file for reading: %s"), file_name);
   1417    }
   1418    goto error;
   1419  }
   1420 
   1421  bufinfo_T bi = {
   1422    .bi_buf = curbuf,
   1423    .bi_fp = fp,
   1424  };
   1425 
   1426  // Read the undo file header.
   1427  char magic_buf[UF_START_MAGIC_LEN];
   1428  if (fread(magic_buf, UF_START_MAGIC_LEN, 1, fp) != 1
   1429      || memcmp(magic_buf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0) {
   1430    semsg(_("E823: Not an undo file: %s"), file_name);
   1431    goto error;
   1432  }
   1433  int version = get2c(fp);
   1434  if (version != UF_VERSION) {
   1435    semsg(_("E824: Incompatible undo file: %s"), file_name);
   1436    goto error;
   1437  }
   1438 
   1439  uint8_t read_hash[UNDO_HASH_SIZE];
   1440  if (!undo_read(&bi, read_hash, UNDO_HASH_SIZE)) {
   1441    corruption_error("hash", file_name);
   1442    goto error;
   1443  }
   1444  linenr_T line_count = (linenr_T)undo_read_4c(&bi);
   1445  if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
   1446      || line_count != curbuf->b_ml.ml_line_count) {
   1447    if (p_verbose > 0 || name != NULL) {
   1448      if (name == NULL) {
   1449        verbose_enter();
   1450      }
   1451      give_warning(_("File contents changed, cannot use undo info"), true, true);
   1452      if (name == NULL) {
   1453        verbose_leave();
   1454      }
   1455    }
   1456    goto error;
   1457  }
   1458 
   1459  // Read undo data for "U" command.
   1460  int str_len = undo_read_4c(&bi);
   1461  if (str_len < 0) {
   1462    goto error;
   1463  }
   1464 
   1465  if (str_len > 0) {
   1466    line_ptr = undo_read_string(&bi, (size_t)str_len);
   1467  }
   1468  linenr_T line_lnum = (linenr_T)undo_read_4c(&bi);
   1469  colnr_T line_colnr = (colnr_T)undo_read_4c(&bi);
   1470  if (line_lnum < 0 || line_colnr < 0) {
   1471    corruption_error("line lnum/col", file_name);
   1472    goto error;
   1473  }
   1474 
   1475  // Begin general undo data
   1476  int old_header_seq = undo_read_4c(&bi);
   1477  int new_header_seq = undo_read_4c(&bi);
   1478  int cur_header_seq = undo_read_4c(&bi);
   1479  int num_head = undo_read_4c(&bi);
   1480  int seq_last = undo_read_4c(&bi);
   1481  int seq_cur = undo_read_4c(&bi);
   1482  time_t seq_time = undo_read_time(&bi);
   1483 
   1484  // Optional header fields.
   1485  int last_save_nr = 0;
   1486  while (true) {
   1487    int len = undo_read_byte(&bi);
   1488 
   1489    if (len == 0 || len == EOF) {
   1490      break;
   1491    }
   1492    int what = undo_read_byte(&bi);
   1493    switch (what) {
   1494    case UF_LAST_SAVE_NR:
   1495      last_save_nr = undo_read_4c(&bi);
   1496      break;
   1497 
   1498    default:
   1499      // field not supported, skip
   1500      while (--len >= 0) {
   1501        undo_read_byte(&bi);
   1502      }
   1503    }
   1504  }
   1505 
   1506  // uhp_table will store the freshly created undo headers we allocate
   1507  // until we insert them into curbuf. The table remains sorted by the
   1508  // sequence numbers of the headers.
   1509  // When there are no headers uhp_table is NULL.
   1510  if (num_head > 0) {
   1511    if ((size_t)num_head < SIZE_MAX / sizeof(*uhp_table)) {
   1512      uhp_table = xmalloc((size_t)num_head * sizeof(*uhp_table));
   1513    }
   1514  }
   1515 
   1516  int num_read_uhps = 0;
   1517 
   1518  int c;
   1519  while ((c = undo_read_2c(&bi)) == UF_HEADER_MAGIC) {
   1520    if (num_read_uhps >= num_head) {
   1521      corruption_error("num_head too small", file_name);
   1522      goto error;
   1523    }
   1524 
   1525    u_header_T *uhp = unserialize_uhp(&bi, file_name);
   1526    if (uhp == NULL) {
   1527      goto error;
   1528    }
   1529    uhp_table[num_read_uhps++] = uhp;
   1530  }
   1531 
   1532  if (num_read_uhps != num_head) {
   1533    corruption_error("num_head", file_name);
   1534    goto error;
   1535  }
   1536  if (c != UF_HEADER_END_MAGIC) {
   1537    corruption_error("end marker", file_name);
   1538    goto error;
   1539  }
   1540 
   1541 #ifdef U_DEBUG
   1542  size_t amount = num_head * sizeof(int) + 1;
   1543  int *uhp_table_used = xmalloc(amount);
   1544  memset(uhp_table_used, 0, amount);
   1545 # define SET_FLAG(j) ++uhp_table_used[j]
   1546 #else
   1547 # define SET_FLAG(j)
   1548 #endif
   1549 
   1550  // We have put all of the headers into a table. Now we iterate through the
   1551  // table and swizzle each sequence number we have stored in uh_*_seq into
   1552  // a pointer corresponding to the header with that sequence number.
   1553  int16_t old_idx = -1;
   1554  int16_t new_idx = -1;
   1555  int16_t cur_idx = -1;
   1556  for (int i = 0; i < num_head; i++) {
   1557    u_header_T *uhp = uhp_table[i];
   1558    if (uhp == NULL) {
   1559      continue;
   1560    }
   1561    for (int j = 0; j < num_head; j++) {
   1562      if (uhp_table[j] != NULL && i != j
   1563          && uhp_table[i]->uh_seq == uhp_table[j]->uh_seq) {
   1564        corruption_error("duplicate uh_seq", file_name);
   1565        goto error;
   1566      }
   1567    }
   1568    for (int j = 0; j < num_head; j++) {
   1569      if (uhp_table[j] != NULL
   1570          && uhp_table[j]->uh_seq == uhp->uh_next.seq) {
   1571        uhp->uh_next.ptr = uhp_table[j];
   1572        SET_FLAG(j);
   1573        break;
   1574      }
   1575    }
   1576    for (int j = 0; j < num_head; j++) {
   1577      if (uhp_table[j] != NULL
   1578          && uhp_table[j]->uh_seq == uhp->uh_prev.seq) {
   1579        uhp->uh_prev.ptr = uhp_table[j];
   1580        SET_FLAG(j);
   1581        break;
   1582      }
   1583    }
   1584    for (int j = 0; j < num_head; j++) {
   1585      if (uhp_table[j] != NULL
   1586          && uhp_table[j]->uh_seq == uhp->uh_alt_next.seq) {
   1587        uhp->uh_alt_next.ptr = uhp_table[j];
   1588        SET_FLAG(j);
   1589        break;
   1590      }
   1591    }
   1592    for (int j = 0; j < num_head; j++) {
   1593      if (uhp_table[j] != NULL
   1594          && uhp_table[j]->uh_seq == uhp->uh_alt_prev.seq) {
   1595        uhp->uh_alt_prev.ptr = uhp_table[j];
   1596        SET_FLAG(j);
   1597        break;
   1598      }
   1599    }
   1600    if (old_header_seq > 0 && old_idx < 0 && uhp->uh_seq == old_header_seq) {
   1601      assert(i <= INT16_MAX);
   1602      old_idx = (int16_t)i;
   1603      SET_FLAG(i);
   1604    }
   1605    if (new_header_seq > 0 && new_idx < 0 && uhp->uh_seq == new_header_seq) {
   1606      assert(i <= INT16_MAX);
   1607      new_idx = (int16_t)i;
   1608      SET_FLAG(i);
   1609    }
   1610    if (cur_header_seq > 0 && cur_idx < 0 && uhp->uh_seq == cur_header_seq) {
   1611      assert(i <= INT16_MAX);
   1612      cur_idx = (int16_t)i;
   1613      SET_FLAG(i);
   1614    }
   1615  }
   1616 
   1617  // Now that we have read the undo info successfully, free the current undo
   1618  // info and use the info from the file.
   1619  u_blockfree(curbuf);
   1620  curbuf->b_u_oldhead = old_idx < 0 ? NULL : uhp_table[old_idx];
   1621  curbuf->b_u_newhead = new_idx < 0 ? NULL : uhp_table[new_idx];
   1622  curbuf->b_u_curhead = cur_idx < 0 ? NULL : uhp_table[cur_idx];
   1623  curbuf->b_u_line_ptr = line_ptr;
   1624  curbuf->b_u_line_lnum = line_lnum;
   1625  curbuf->b_u_line_colnr = line_colnr;
   1626  curbuf->b_u_numhead = num_head;
   1627  curbuf->b_u_seq_last = seq_last;
   1628  curbuf->b_u_seq_cur = seq_cur;
   1629  curbuf->b_u_time_cur = seq_time;
   1630  curbuf->b_u_save_nr_last = last_save_nr;
   1631  curbuf->b_u_save_nr_cur = last_save_nr;
   1632 
   1633  curbuf->b_u_synced = true;
   1634  xfree(uhp_table);
   1635 
   1636 #ifdef U_DEBUG
   1637  for (int i = 0; i < num_head; i++) {
   1638    if (uhp_table_used[i] == 0) {
   1639      semsg("uhp_table entry %" PRId64 " not used, leaking memory", (int64_t)i);
   1640    }
   1641  }
   1642  xfree(uhp_table_used);
   1643  u_check(true);
   1644 #endif
   1645 
   1646  if (name != NULL) {
   1647    smsg(0, _("Finished reading undo file %s"), file_name);
   1648  }
   1649  goto theend;
   1650 
   1651 error:
   1652  xfree(line_ptr);
   1653  if (uhp_table != NULL) {
   1654    for (int i = 0; i < num_read_uhps; i++) {
   1655      if (uhp_table[i] != NULL) {
   1656        u_free_uhp(uhp_table[i]);
   1657      }
   1658    }
   1659    xfree(uhp_table);
   1660  }
   1661 
   1662 theend:
   1663  if (fp != NULL) {
   1664    fclose(fp);
   1665  }
   1666  if (file_name != name) {
   1667    xfree(file_name);
   1668  }
   1669 }
   1670 
   1671 /// Writes a sequence of bytes to the undo file.
   1672 ///
   1673 /// @param bi  The buffer info
   1674 /// @param ptr The byte buffer to write
   1675 /// @param len The number of bytes to write
   1676 ///
   1677 /// @returns false in case of an error.
   1678 static bool undo_write(bufinfo_T *bi, uint8_t *ptr, size_t len)
   1679  FUNC_ATTR_NONNULL_ARG(1)
   1680 {
   1681  return fwrite(ptr, len, 1, bi->bi_fp) == 1;
   1682 }
   1683 
   1684 /// Writes a number, most significant bit first, in "len" bytes.
   1685 ///
   1686 /// Must match with undo_read_?c() functions.
   1687 ///
   1688 /// @param bi  The buffer info
   1689 /// @param nr  The number to write
   1690 /// @param len The number of bytes to use when writing the number.
   1691 ///
   1692 /// @returns false in case of an error.
   1693 static bool undo_write_bytes(bufinfo_T *bi, uintmax_t nr, size_t len)
   1694 {
   1695  assert(len > 0);
   1696  uint8_t buf[8];
   1697  for (size_t i = len - 1, bufi = 0; bufi < len; i--, bufi++) {
   1698    buf[bufi] = (uint8_t)(nr >> (i * 8));
   1699  }
   1700  return undo_write(bi, buf, len);
   1701 }
   1702 
   1703 /// Writes the pointer to an undo header.
   1704 ///
   1705 /// Instead of writing the pointer itself, we use the sequence
   1706 /// number of the header. This is converted back to pointers
   1707 /// when reading.
   1708 static void put_header_ptr(bufinfo_T *bi, u_header_T *uhp)
   1709 {
   1710  assert(uhp == NULL || uhp->uh_seq >= 0);
   1711  undo_write_bytes(bi, (uint64_t)(uhp != NULL ? uhp->uh_seq : 0), 4);
   1712 }
   1713 
   1714 static int undo_read_4c(bufinfo_T *bi)
   1715 {
   1716  return get4c(bi->bi_fp);
   1717 }
   1718 
   1719 static int undo_read_2c(bufinfo_T *bi)
   1720 {
   1721  return get2c(bi->bi_fp);
   1722 }
   1723 
   1724 static int undo_read_byte(bufinfo_T *bi)
   1725 {
   1726  return getc(bi->bi_fp);
   1727 }
   1728 
   1729 static time_t undo_read_time(bufinfo_T *bi)
   1730 {
   1731  return get8ctime(bi->bi_fp);
   1732 }
   1733 
   1734 /// Reads "buffer[size]" from the undo file.
   1735 ///
   1736 /// @param bi     The buffer info
   1737 /// @param buffer Character buffer to read data into
   1738 /// @param size   The size of the character buffer
   1739 ///
   1740 /// @returns false in case of an error.
   1741 static bool undo_read(bufinfo_T *bi, uint8_t *buffer, size_t size)
   1742  FUNC_ATTR_NONNULL_ARG(1)
   1743 {
   1744  const bool retval = fread(buffer, size, 1, bi->bi_fp) == 1;
   1745  if (!retval) {
   1746    // Error may be checked for only later.  Fill with zeros,
   1747    // so that the reader won't use garbage.
   1748    memset(buffer, 0, size);
   1749  }
   1750  return retval;
   1751 }
   1752 
   1753 /// Reads a string of length "len" from "bi->bi_fd" and appends a zero to it.
   1754 ///
   1755 /// @param len can be zero to allocate an empty line.
   1756 ///
   1757 /// @returns a pointer to allocated memory or NULL in case of an error.
   1758 static char *undo_read_string(bufinfo_T *bi, size_t len)
   1759 {
   1760  char *ptr = xmallocz(len);
   1761  if (len > 0 && !undo_read(bi, (uint8_t *)ptr, len)) {
   1762    xfree(ptr);
   1763    return NULL;
   1764  }
   1765  return ptr;
   1766 }
   1767 
   1768 /// If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible).
   1769 /// If 'cpoptions' does not contain 'u': Always undo.
   1770 void u_undo(int count)
   1771 {
   1772  // If we get an undo command while executing a macro, we behave like the
   1773  // original vi. If this happens twice in one macro the result will not
   1774  // be compatible.
   1775  if (curbuf->b_u_synced == false) {
   1776    u_sync(true);
   1777    count = 1;
   1778  }
   1779 
   1780  if (vim_strchr(p_cpo, CPO_UNDO) == NULL) {
   1781    undo_undoes = true;
   1782  } else {
   1783    undo_undoes = !undo_undoes;
   1784  }
   1785  u_doit(count, false, true);
   1786 }
   1787 
   1788 /// If 'cpoptions' contains 'u': Repeat the previous undo or redo.
   1789 /// If 'cpoptions' does not contain 'u': Always redo.
   1790 void u_redo(int count)
   1791 {
   1792  if (vim_strchr(p_cpo, CPO_UNDO) == NULL) {
   1793    undo_undoes = false;
   1794  }
   1795 
   1796  u_doit(count, false, true);
   1797 }
   1798 
   1799 /// Undo and remove the branch from the undo tree.
   1800 /// Also moves the cursor (as a "normal" undo would).
   1801 ///
   1802 /// @param do_buf_event If `true`, send the changedtick with the buffer updates
   1803 bool u_undo_and_forget(int count, bool do_buf_event)
   1804 {
   1805  if (curbuf->b_u_synced == false) {
   1806    u_sync(true);
   1807    count = 1;
   1808  }
   1809  undo_undoes = true;
   1810  u_doit(count, true, do_buf_event);
   1811 
   1812  if (curbuf->b_u_curhead == NULL) {
   1813    // nothing was undone.
   1814    return false;
   1815  }
   1816 
   1817  // Delete the current redo header
   1818  // set the redo header to the next alternative branch (if any)
   1819  // otherwise we will be in the leaf state
   1820  u_header_T *to_forget = curbuf->b_u_curhead;
   1821  curbuf->b_u_newhead = to_forget->uh_next.ptr;
   1822  curbuf->b_u_curhead = to_forget->uh_alt_next.ptr;
   1823  if (curbuf->b_u_curhead) {
   1824    to_forget->uh_alt_next.ptr = NULL;
   1825    curbuf->b_u_curhead->uh_alt_prev.ptr = to_forget->uh_alt_prev.ptr;
   1826    curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_next.ptr
   1827                          ? curbuf->b_u_curhead->uh_next.ptr->uh_seq : 0;
   1828  } else if (curbuf->b_u_newhead) {
   1829    curbuf->b_u_seq_cur = curbuf->b_u_newhead->uh_seq;
   1830  }
   1831  if (to_forget->uh_alt_prev.ptr) {
   1832    to_forget->uh_alt_prev.ptr->uh_alt_next.ptr = curbuf->b_u_curhead;
   1833  }
   1834  if (curbuf->b_u_newhead) {
   1835    curbuf->b_u_newhead->uh_prev.ptr = curbuf->b_u_curhead;
   1836  }
   1837  if (curbuf->b_u_seq_last == to_forget->uh_seq) {
   1838    curbuf->b_u_seq_last--;
   1839  }
   1840  u_freebranch(curbuf, to_forget, NULL);
   1841  return true;
   1842 }
   1843 
   1844 /// Undo or redo, depending on `undo_undoes`, `count` times.
   1845 ///
   1846 /// @param startcount How often to undo or redo
   1847 /// @param quiet If `true`, don't show messages
   1848 /// @param do_buf_event If `true`, send the changedtick with the buffer updates
   1849 static void u_doit(int startcount, bool quiet, bool do_buf_event)
   1850 {
   1851  if (!undo_allowed(curbuf)) {
   1852    return;
   1853  }
   1854 
   1855  u_newcount = 0;
   1856  u_oldcount = 0;
   1857  if (curbuf->b_ml.ml_flags & ML_EMPTY) {
   1858    u_oldcount = -1;
   1859  }
   1860 
   1861  msg_ext_set_kind("undo");
   1862  int count = startcount;
   1863  while (count--) {
   1864    // Do the change warning now, so that it triggers FileChangedRO when
   1865    // needed.  This may cause the file to be reloaded, that must happen
   1866    // before we do anything, because it may change curbuf->b_u_curhead
   1867    // and more.
   1868    change_warning(curbuf, 0);
   1869 
   1870    if (undo_undoes) {
   1871      if (curbuf->b_u_curhead == NULL) {  // first undo
   1872        curbuf->b_u_curhead = curbuf->b_u_newhead;
   1873      } else if (get_undolevel(curbuf) > 0) {  // multi level undo
   1874        // get next undo
   1875        curbuf->b_u_curhead = curbuf->b_u_curhead->uh_next.ptr;
   1876      }
   1877      // nothing to undo
   1878      if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL) {
   1879        // stick curbuf->b_u_curhead at end
   1880        curbuf->b_u_curhead = curbuf->b_u_oldhead;
   1881        beep_flush();
   1882        if (count == startcount - 1) {
   1883          msg(_("Already at oldest change"), 0);
   1884          return;
   1885        }
   1886        break;
   1887      }
   1888 
   1889      u_undoredo(true, do_buf_event);
   1890    } else {
   1891      if (curbuf->b_u_curhead == NULL || get_undolevel(curbuf) <= 0) {
   1892        beep_flush();  // nothing to redo
   1893        if (count == startcount - 1) {
   1894          msg(_("Already at newest change"), 0);
   1895          return;
   1896        }
   1897        break;
   1898      }
   1899 
   1900      u_undoredo(false, do_buf_event);
   1901 
   1902      // Advance for next redo.  Set "newhead" when at the end of the
   1903      // redoable changes.
   1904      if (curbuf->b_u_curhead->uh_prev.ptr == NULL) {
   1905        curbuf->b_u_newhead = curbuf->b_u_curhead;
   1906      }
   1907      curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev.ptr;
   1908    }
   1909  }
   1910  u_undo_end(undo_undoes, false, quiet);
   1911 }
   1912 
   1913 // Undo or redo over the timeline.
   1914 // When "step" is negative go back in time, otherwise goes forward in time.
   1915 // When "sec" is false make "step" steps, when "sec" is true use "step" as
   1916 // seconds.
   1917 // When "file" is true use "step" as a number of file writes.
   1918 // When "absolute" is true use "step" as the sequence number to jump to.
   1919 // "sec" must be false then.
   1920 void undo_time(int step, bool sec, bool file, bool absolute)
   1921 {
   1922  if (text_locked()) {
   1923    text_locked_msg();
   1924    return;
   1925  }
   1926 
   1927  // First make sure the current undoable change is synced.
   1928  if (curbuf->b_u_synced == false) {
   1929    u_sync(true);
   1930  }
   1931 
   1932  u_newcount = 0;
   1933  u_oldcount = 0;
   1934  if (curbuf->b_ml.ml_flags & ML_EMPTY) {
   1935    u_oldcount = -1;
   1936  }
   1937 
   1938  int target;
   1939  int closest;
   1940  u_header_T *uhp = NULL;
   1941  bool dosec = sec;
   1942  bool dofile = file;
   1943  bool above = false;
   1944  bool did_undo = true;
   1945 
   1946  // "target" is the node below which we want to be.
   1947  // Init "closest" to a value we can't reach.
   1948  if (absolute) {
   1949    target = step;
   1950    closest = -1;
   1951  } else {
   1952    if (dosec) {
   1953      target = (int)curbuf->b_u_time_cur + step;
   1954    } else if (dofile) {
   1955      if (step < 0) {
   1956        // Going back to a previous write. If there were changes after
   1957        // the last write, count that as moving one file-write, so
   1958        // that ":earlier 1f" undoes all changes since the last save.
   1959        uhp = curbuf->b_u_curhead;
   1960        if (uhp != NULL) {
   1961          uhp = uhp->uh_next.ptr;
   1962        } else {
   1963          uhp = curbuf->b_u_newhead;
   1964        }
   1965        if (uhp != NULL && uhp->uh_save_nr != 0) {
   1966          // "uh_save_nr" was set in the last block, that means
   1967          // there were no changes since the last write
   1968          target = curbuf->b_u_save_nr_cur + step;
   1969        } else {
   1970          // count the changes since the last write as one step
   1971          target = curbuf->b_u_save_nr_cur + step + 1;
   1972        }
   1973        if (target <= 0) {
   1974          // Go to before first write: before the oldest change. Use
   1975          // the sequence number for that.
   1976          dofile = false;
   1977        }
   1978      } else {
   1979        // Moving forward to a newer write.
   1980        target = curbuf->b_u_save_nr_cur + step;
   1981        if (target > curbuf->b_u_save_nr_last) {
   1982          // Go to after last write: after the latest change. Use
   1983          // the sequence number for that.
   1984          target = curbuf->b_u_seq_last + 1;
   1985          dofile = false;
   1986        }
   1987      }
   1988    } else {
   1989      target = curbuf->b_u_seq_cur + step;
   1990    }
   1991    if (step < 0) {
   1992      target = MAX(target, 0);
   1993      closest = -1;
   1994    } else {
   1995      if (dosec) {
   1996        closest = (int)(os_time() + 1);
   1997      } else if (dofile) {
   1998        closest = curbuf->b_u_save_nr_last + 2;
   1999      } else {
   2000        closest = curbuf->b_u_seq_last + 2;
   2001      }
   2002      if (target >= closest) {
   2003        target = closest - 1;
   2004      }
   2005    }
   2006  }
   2007  int closest_start = closest;
   2008  int closest_seq = curbuf->b_u_seq_cur;
   2009  int mark;
   2010  int nomark = 0;  // shut up compiler
   2011 
   2012  // When "target" is 0; Back to origin.
   2013  if (target == 0) {
   2014    mark = lastmark;  // avoid that GCC complains
   2015    goto target_zero;
   2016  }
   2017 
   2018  // May do this twice:
   2019  // 1. Search for "target", update "closest" to the best match found.
   2020  // 2. If "target" not found search for "closest".
   2021  //
   2022  // When using the closest time we use the sequence number in the second
   2023  // round, because there may be several entries with the same time.
   2024  for (int round = 1; round <= 2; round++) {
   2025    // Find the path from the current state to where we want to go.  The
   2026    // desired state can be anywhere in the undo tree, need to go all over
   2027    // it.  We put "nomark" in uh_walk where we have been without success,
   2028    // "mark" where it could possibly be.
   2029    mark = ++lastmark;
   2030    nomark = ++lastmark;
   2031 
   2032    if (curbuf->b_u_curhead == NULL) {          // at leaf of the tree
   2033      uhp = curbuf->b_u_newhead;
   2034    } else {
   2035      uhp = curbuf->b_u_curhead;
   2036    }
   2037 
   2038    while (uhp != NULL) {
   2039      uhp->uh_walk = mark;
   2040      int val = dosec ? (int)(uhp->uh_time)
   2041                      : dofile ? uhp->uh_save_nr
   2042                               : uhp->uh_seq;
   2043 
   2044      if (round == 1 && !(dofile && val == 0)) {
   2045        // Remember the header that is closest to the target.
   2046        // It must be at least in the right direction (checked with
   2047        // "b_u_seq_cur").  When the timestamp is equal find the
   2048        // highest/lowest sequence number.
   2049        if ((step < 0 ? uhp->uh_seq <= curbuf->b_u_seq_cur
   2050                      : uhp->uh_seq > curbuf->b_u_seq_cur)
   2051            && ((dosec && val == closest)
   2052                ? (step < 0
   2053                   ? uhp->uh_seq < closest_seq
   2054                   : uhp->uh_seq > closest_seq)
   2055                : closest == closest_start
   2056                || (val > target
   2057                    ? (closest > target
   2058                       ? val - target <= closest - target
   2059                       : val - target <= target - closest)
   2060                    : (closest > target
   2061                       ? target - val <= closest - target
   2062                       : target - val <= target - closest)))) {
   2063          closest = val;
   2064          closest_seq = uhp->uh_seq;
   2065        }
   2066      }
   2067 
   2068      // Quit searching when we found a match.  But when searching for a
   2069      // time we need to continue looking for the best uh_seq.
   2070      if (target == val && !dosec) {
   2071        target = uhp->uh_seq;
   2072        break;
   2073      }
   2074 
   2075      // go down in the tree if we haven't been there
   2076      if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark
   2077          && uhp->uh_prev.ptr->uh_walk != mark) {
   2078        uhp = uhp->uh_prev.ptr;
   2079      } else if (uhp->uh_alt_next.ptr != NULL
   2080                 && uhp->uh_alt_next.ptr->uh_walk != nomark
   2081                 && uhp->uh_alt_next.ptr->uh_walk != mark) {
   2082        // go to alternate branch if we haven't been there
   2083        uhp = uhp->uh_alt_next.ptr;
   2084      } else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
   2085                 // go up in the tree if we haven't been there and we are at the
   2086                 // start of alternate branches
   2087                 && uhp->uh_next.ptr->uh_walk != nomark
   2088                 && uhp->uh_next.ptr->uh_walk != mark) {
   2089        // If still at the start we don't go through this change.
   2090        if (uhp == curbuf->b_u_curhead) {
   2091          uhp->uh_walk = nomark;
   2092        }
   2093        uhp = uhp->uh_next.ptr;
   2094      } else {
   2095        // need to backtrack; mark this node as useless
   2096        uhp->uh_walk = nomark;
   2097        if (uhp->uh_alt_prev.ptr != NULL) {
   2098          uhp = uhp->uh_alt_prev.ptr;
   2099        } else {
   2100          uhp = uhp->uh_next.ptr;
   2101        }
   2102      }
   2103    }
   2104 
   2105    if (uhp != NULL) {      // found it
   2106      break;
   2107    }
   2108 
   2109    if (absolute) {
   2110      semsg(_("E830: Undo number %" PRId64 " not found"), (int64_t)step);
   2111      return;
   2112    }
   2113 
   2114    if (closest == closest_start) {
   2115      if (step < 0) {
   2116        msg(_("Already at oldest change"), 0);
   2117      } else {
   2118        msg(_("Already at newest change"), 0);
   2119      }
   2120      return;
   2121    }
   2122 
   2123    target = closest_seq;
   2124    dosec = false;
   2125    dofile = false;
   2126    if (step < 0) {
   2127      above = true;             // stop above the header
   2128    }
   2129  }
   2130 
   2131 target_zero:
   2132  // If we found it: Follow the path to go to where we want to be.
   2133  if (uhp != NULL || target == 0) {
   2134    // First go up the tree as much as needed.
   2135    while (!got_int) {
   2136      // Do the change warning now, for the same reason as above.
   2137      change_warning(curbuf, 0);
   2138 
   2139      uhp = curbuf->b_u_curhead;
   2140      if (uhp == NULL) {
   2141        uhp = curbuf->b_u_newhead;
   2142      } else {
   2143        uhp = uhp->uh_next.ptr;
   2144      }
   2145      if (uhp == NULL
   2146          || (target > 0 && uhp->uh_walk != mark)
   2147          || (uhp->uh_seq == target && !above)) {
   2148        break;
   2149      }
   2150      curbuf->b_u_curhead = uhp;
   2151      u_undoredo(true, true);
   2152      if (target > 0) {
   2153        uhp->uh_walk = nomark;          // don't go back down here
   2154      }
   2155    }
   2156 
   2157    // When back to origin, redo is not needed.
   2158    if (target > 0) {
   2159      // And now go down the tree (redo), branching off where needed.
   2160      while (!got_int) {
   2161        // Do the change warning now, for the same reason as above.
   2162        change_warning(curbuf, 0);
   2163 
   2164        uhp = curbuf->b_u_curhead;
   2165        if (uhp == NULL) {
   2166          break;
   2167        }
   2168 
   2169        // Go back to the first branch with a mark.
   2170        while (uhp->uh_alt_prev.ptr != NULL
   2171               && uhp->uh_alt_prev.ptr->uh_walk == mark) {
   2172          uhp = uhp->uh_alt_prev.ptr;
   2173        }
   2174 
   2175        // Find the last branch with a mark, that's the one.
   2176        u_header_T *last = uhp;
   2177        while (last->uh_alt_next.ptr != NULL
   2178               && last->uh_alt_next.ptr->uh_walk == mark) {
   2179          last = last->uh_alt_next.ptr;
   2180        }
   2181        if (last != uhp) {
   2182          // Make the used branch the first entry in the list of
   2183          // alternatives to make "u" and CTRL-R take this branch.
   2184          while (uhp->uh_alt_prev.ptr != NULL) {
   2185            uhp = uhp->uh_alt_prev.ptr;
   2186          }
   2187          if (last->uh_alt_next.ptr != NULL) {
   2188            last->uh_alt_next.ptr->uh_alt_prev.ptr = last->uh_alt_prev.ptr;
   2189          }
   2190          last->uh_alt_prev.ptr->uh_alt_next.ptr = last->uh_alt_next.ptr;
   2191          last->uh_alt_prev.ptr = NULL;
   2192          last->uh_alt_next.ptr = uhp;
   2193          uhp->uh_alt_prev.ptr = last;
   2194 
   2195          if (curbuf->b_u_oldhead == uhp) {
   2196            curbuf->b_u_oldhead = last;
   2197          }
   2198          uhp = last;
   2199          if (uhp->uh_next.ptr != NULL) {
   2200            uhp->uh_next.ptr->uh_prev.ptr = uhp;
   2201          }
   2202        }
   2203        curbuf->b_u_curhead = uhp;
   2204 
   2205        if (uhp->uh_walk != mark) {
   2206          break;            // must have reached the target
   2207        }
   2208 
   2209        // Stop when going backwards in time and didn't find the exact
   2210        // header we were looking for.
   2211        if (uhp->uh_seq == target && above) {
   2212          curbuf->b_u_seq_cur = target - 1;
   2213          break;
   2214        }
   2215 
   2216        u_undoredo(false, true);
   2217 
   2218        // Advance "curhead" to below the header we last used.  If it
   2219        // becomes NULL then we need to set "newhead" to this leaf.
   2220        if (uhp->uh_prev.ptr == NULL) {
   2221          curbuf->b_u_newhead = uhp;
   2222        }
   2223        curbuf->b_u_curhead = uhp->uh_prev.ptr;
   2224        did_undo = false;
   2225 
   2226        if (uhp->uh_seq == target) {    // found it!
   2227          break;
   2228        }
   2229 
   2230        uhp = uhp->uh_prev.ptr;
   2231        if (uhp == NULL || uhp->uh_walk != mark) {
   2232          // Need to redo more but can't find it...
   2233          internal_error("undo_time()");
   2234          break;
   2235        }
   2236      }
   2237    }
   2238  }
   2239  u_undo_end(did_undo, absolute, false);
   2240 }
   2241 
   2242 /// u_undoredo: common code for undo and redo
   2243 ///
   2244 /// The lines in the file are replaced by the lines in the entry list at
   2245 /// curbuf->b_u_curhead. The replaced lines in the file are saved in the entry
   2246 /// list for the next undo/redo.
   2247 ///
   2248 /// @param undo If `true`, go up the tree. Down if `false`.
   2249 /// @param do_buf_event If `true`, send buffer updates.
   2250 static void u_undoredo(bool undo, bool do_buf_event)
   2251 {
   2252  char **newarray = NULL;
   2253  linenr_T newlnum = MAXLNUM;
   2254  pos_T new_curpos = curwin->w_cursor;
   2255  u_entry_T *nuep;
   2256  u_entry_T *newlist = NULL;
   2257  fmark_T namedm[NMARKS];
   2258  u_header_T *curhead = curbuf->b_u_curhead;
   2259 
   2260  // Don't want autocommands using the undo structures here, they are
   2261  // invalid till the end.
   2262  block_autocmds();
   2263 
   2264 #ifdef U_DEBUG
   2265  u_check(false);
   2266 #endif
   2267  int old_flags = curhead->uh_flags;
   2268  int new_flags = (curbuf->b_changed ? UH_CHANGED : 0)
   2269                  | ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0)
   2270                  | (old_flags & UH_RELOAD);
   2271  setpcmark();
   2272 
   2273  // save marks before undo/redo
   2274  zero_fmark_additional_data(curbuf->b_namedm);
   2275  memmove(namedm, curbuf->b_namedm, sizeof(curbuf->b_namedm[0]) * NMARKS);
   2276  visualinfo_T visualinfo = curbuf->b_visual;
   2277  curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count;
   2278  curbuf->b_op_start.col = 0;
   2279  curbuf->b_op_end.lnum = 0;
   2280  curbuf->b_op_end.col = 0;
   2281 
   2282  for (u_entry_T *uep = curhead->uh_entry; uep != NULL; uep = nuep) {
   2283    linenr_T top = uep->ue_top;
   2284    linenr_T bot = uep->ue_bot;
   2285    if (bot == 0) {
   2286      bot = curbuf->b_ml.ml_line_count + 1;
   2287    }
   2288    if (top > curbuf->b_ml.ml_line_count || top >= bot
   2289        || bot > curbuf->b_ml.ml_line_count + 1) {
   2290      unblock_autocmds();
   2291      iemsg(_("E438: u_undo: line numbers wrong"));
   2292      changed(curbuf);                // don't want UNCHANGED now
   2293      return;
   2294    }
   2295 
   2296    linenr_T oldsize = bot - top - 1;        // number of lines before undo
   2297    linenr_T newsize = uep->ue_size;         // number of lines after undo
   2298 
   2299    // Decide about the cursor position, depending on what text changed.
   2300    // Don't set it yet, it may be invalid if lines are going to be added.
   2301    {
   2302      // If the saved cursor is somewhere in this undo block, move it to
   2303      // the remembered position.  Makes "gwap" put the cursor back
   2304      // where it was.
   2305      linenr_T lnum = curhead->uh_cursor.lnum;
   2306      if (lnum >= top && lnum <= top + newsize + 1) {
   2307        new_curpos = curhead->uh_cursor;
   2308        // We don't want other entries to override saved cursor
   2309        // position.
   2310        newlnum = -1;
   2311      } else if (top < newlnum) {
   2312        // Use the first line that actually changed.  Avoids that
   2313        // undoing auto-formatting puts the cursor in the previous
   2314        // line.
   2315        int i;
   2316        for (i = 0; i < newsize && i < oldsize; i++) {
   2317          if (strcmp(uep->ue_array[i], ml_get(top + 1 + (linenr_T)i)) != 0) {
   2318            break;
   2319          }
   2320        }
   2321        if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL) {
   2322          newlnum = top;
   2323          new_curpos.lnum = newlnum + 1;
   2324        } else if (i < newsize) {
   2325          newlnum = top + (linenr_T)i;
   2326          new_curpos.lnum = newlnum + 1;
   2327        }
   2328      }
   2329    }
   2330 
   2331    bool empty_buffer = false;
   2332 
   2333    // Delete the lines between top and bot and save them in newarray.
   2334    if (oldsize > 0) {
   2335      newarray = xmalloc(sizeof(char *) * (size_t)oldsize);
   2336      // delete backwards, it goes faster in most cases
   2337      int i;
   2338      linenr_T lnum;
   2339      for (lnum = bot - 1, i = oldsize; --i >= 0; lnum--) {
   2340        // what can we do when we run out of memory?
   2341        newarray[i] = u_save_line(lnum);
   2342        // remember we deleted the last line in the buffer, and a
   2343        // dummy empty line will be inserted
   2344        if (curbuf->b_ml.ml_line_count == 1) {
   2345          empty_buffer = true;
   2346        }
   2347        ml_delete(lnum);  // ML_DEL_UNDO
   2348      }
   2349    } else {
   2350      newarray = NULL;
   2351    }
   2352 
   2353    // make sure the cursor is on a valid line after the deletions
   2354    check_cursor_lnum(curwin);
   2355 
   2356    // Insert the lines in u_array between top and bot.
   2357    if (newsize) {
   2358      int i;
   2359      linenr_T lnum;
   2360      for (lnum = top, i = 0; i < newsize; i++, lnum++) {
   2361        // If the file is empty, there is an empty line 1 that we
   2362        // should get rid of, by replacing it with the new line
   2363        if (empty_buffer && lnum == 0) {
   2364          ml_replace(1, uep->ue_array[i], true);
   2365        } else {
   2366          ml_append_flags(lnum, uep->ue_array[i], 0, 0);  // ML_APPEND_UNDO
   2367        }
   2368        xfree(uep->ue_array[i]);
   2369      }
   2370      xfree(uep->ue_array);
   2371    }
   2372 
   2373    // Adjust marks
   2374    if (oldsize != newsize) {
   2375      mark_adjust(top + 1, top + oldsize, MAXLNUM, newsize - oldsize, kExtmarkNOOP);
   2376      if (curbuf->b_op_start.lnum > top + oldsize) {
   2377        curbuf->b_op_start.lnum += newsize - oldsize;
   2378      }
   2379      if (curbuf->b_op_end.lnum > top + oldsize) {
   2380        curbuf->b_op_end.lnum += newsize - oldsize;
   2381      }
   2382    }
   2383 
   2384    if (oldsize > 0 || newsize > 0) {
   2385      changed_lines(curbuf, top + 1, 0, bot, newsize - oldsize, do_buf_event);
   2386      // When text has been changed, possibly the start of the next line
   2387      // may have SpellCap that should be removed or it needs to be
   2388      // displayed.  Schedule the next line for redrawing just in case.
   2389      if (spell_check_window(curwin) && bot <= curbuf->b_ml.ml_line_count) {
   2390        redrawWinline(curwin, bot);
   2391      }
   2392    }
   2393 
   2394    // Set the '[ mark.
   2395    curbuf->b_op_start.lnum = MIN(curbuf->b_op_start.lnum, top + 1);
   2396    // Set the '] mark.
   2397    if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) {
   2398      curbuf->b_op_end.lnum = top + 1;
   2399    } else if (top + newsize > curbuf->b_op_end.lnum) {
   2400      curbuf->b_op_end.lnum = top + newsize;
   2401    }
   2402 
   2403    u_newcount += newsize;
   2404    u_oldcount += oldsize;
   2405    uep->ue_size = oldsize;
   2406    uep->ue_array = newarray;
   2407    uep->ue_bot = top + newsize + 1;
   2408 
   2409    // insert this entry in front of the new entry list
   2410    nuep = uep->ue_next;
   2411    uep->ue_next = newlist;
   2412    newlist = uep;
   2413  }
   2414 
   2415  // Ensure the '[ and '] marks are within bounds.
   2416  curbuf->b_op_start.lnum = MIN(curbuf->b_op_start.lnum, curbuf->b_ml.ml_line_count);
   2417  curbuf->b_op_end.lnum = MIN(curbuf->b_op_end.lnum, curbuf->b_ml.ml_line_count);
   2418 
   2419  // Adjust Extmarks
   2420  if (undo) {
   2421    for (int i = (int)kv_size(curhead->uh_extmark) - 1; i > -1; i--) {
   2422      extmark_apply_undo(kv_A(curhead->uh_extmark, i), undo);
   2423    }
   2424    // redo
   2425  } else {
   2426    for (int i = 0; i < (int)kv_size(curhead->uh_extmark); i++) {
   2427      extmark_apply_undo(kv_A(curhead->uh_extmark, i), undo);
   2428    }
   2429  }
   2430  if (curhead->uh_flags & UH_RELOAD) {
   2431    // TODO(bfredl): this is a bit crude. When 'undoreload' is used we
   2432    // should have all info to send a buffer-reloaing on_lines/on_bytes event
   2433    buf_updates_unload(curbuf, true);
   2434  }
   2435  // Finish adjusting extmarks
   2436 
   2437  // Set the cursor to the desired position.  Check that the line is valid.
   2438  curwin->w_cursor = new_curpos;
   2439  check_cursor_lnum(curwin);
   2440 
   2441  curhead->uh_entry = newlist;
   2442  curhead->uh_flags = new_flags;
   2443  if ((old_flags & UH_EMPTYBUF) && buf_is_empty(curbuf)) {
   2444    curbuf->b_ml.ml_flags |= ML_EMPTY;
   2445  }
   2446  if (old_flags & UH_CHANGED) {
   2447    changed(curbuf);
   2448  } else {
   2449    unchanged(curbuf, false, true);
   2450  }
   2451 
   2452  // because the calls to changed()/unchanged() above will bump changedtick
   2453  // again, we need to send a nvim_buf_lines_event with just the new value of
   2454  // b:changedtick
   2455  if (do_buf_event) {
   2456    buf_updates_changedtick(curbuf);
   2457  }
   2458 
   2459  // restore marks from before undo/redo
   2460  for (int i = 0; i < NMARKS; i++) {
   2461    if (curhead->uh_namedm[i].mark.lnum != 0) {
   2462      free_fmark(curbuf->b_namedm[i]);
   2463      curbuf->b_namedm[i] = curhead->uh_namedm[i];
   2464    }
   2465    if (namedm[i].mark.lnum != 0) {
   2466      curhead->uh_namedm[i] = namedm[i];
   2467    } else {
   2468      curhead->uh_namedm[i].mark.lnum = 0;
   2469    }
   2470  }
   2471  if (curhead->uh_visual.vi_start.lnum != 0) {
   2472    curbuf->b_visual = curhead->uh_visual;
   2473    curhead->uh_visual = visualinfo;
   2474  }
   2475 
   2476  // If the cursor is only off by one line, put it at the same position as
   2477  // before starting the change (for the "o" command).
   2478  // Otherwise the cursor should go to the first undone line.
   2479  if (curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum
   2480      && curwin->w_cursor.lnum > 1) {
   2481    curwin->w_cursor.lnum--;
   2482  }
   2483  if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count) {
   2484    if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum) {
   2485      curwin->w_cursor.col = curhead->uh_cursor.col;
   2486      if (virtual_active(curwin) && curhead->uh_cursor_vcol >= 0) {
   2487        coladvance(curwin, curhead->uh_cursor_vcol);
   2488      } else {
   2489        curwin->w_cursor.coladd = 0;
   2490      }
   2491    } else {
   2492      beginline(BL_SOL | BL_FIX);
   2493    }
   2494  } else {
   2495    // We get here with the current cursor line being past the end (eg
   2496    // after adding lines at the end of the file, and then undoing it).
   2497    // check_cursor() will move the cursor to the last line.  Move it to
   2498    // the first column here.
   2499    curwin->w_cursor.col = 0;
   2500    curwin->w_cursor.coladd = 0;
   2501  }
   2502 
   2503  // Make sure the cursor is on an existing line and column.
   2504  check_cursor(curwin);
   2505 
   2506  // Remember where we are for "g-" and ":earlier 10s".
   2507  curbuf->b_u_seq_cur = curhead->uh_seq;
   2508  if (undo) {
   2509    // We are below the previous undo.  However, to make ":earlier 1s"
   2510    // work we compute this as being just above the just undone change.
   2511    curbuf->b_u_seq_cur = curhead->uh_next.ptr
   2512                          ? curhead->uh_next.ptr->uh_seq : 0;
   2513  }
   2514 
   2515  // Remember where we are for ":earlier 1f" and ":later 1f".
   2516  if (curhead->uh_save_nr != 0) {
   2517    if (undo) {
   2518      curbuf->b_u_save_nr_cur = curhead->uh_save_nr - 1;
   2519    } else {
   2520      curbuf->b_u_save_nr_cur = curhead->uh_save_nr;
   2521    }
   2522  }
   2523 
   2524  // The timestamp can be the same for multiple changes, just use the one of
   2525  // the undone/redone change.
   2526  curbuf->b_u_time_cur = curhead->uh_time;
   2527 
   2528  unblock_autocmds();
   2529 #ifdef U_DEBUG
   2530  u_check(false);
   2531 #endif
   2532 }
   2533 
   2534 /// If we deleted or added lines, report the number of less/more lines.
   2535 /// Otherwise, report the number of changes (this may be incorrect
   2536 /// in some cases, but it's better than nothing).
   2537 ///
   2538 /// @param did_undo  just did an undo
   2539 /// @param absolute  used ":undo N"
   2540 static void u_undo_end(bool did_undo, bool absolute, bool quiet)
   2541 {
   2542  if ((fdo_flags & kOptFdoFlagUndo) && KeyTyped) {
   2543    foldOpenCursor();
   2544  }
   2545 
   2546  if (quiet
   2547      || global_busy        // no messages until global is finished
   2548      || !messaging()) {    // 'lazyredraw' set, don't do messages now
   2549    return;
   2550  }
   2551 
   2552  if (curbuf->b_ml.ml_flags & ML_EMPTY) {
   2553    u_newcount--;
   2554  }
   2555 
   2556  u_oldcount -= u_newcount;
   2557  char *msgstr;
   2558  if (u_oldcount == -1) {
   2559    msgstr = N_("more line");
   2560  } else if (u_oldcount < 0) {
   2561    msgstr = N_("more lines");
   2562  } else if (u_oldcount == 1) {
   2563    msgstr = N_("line less");
   2564  } else if (u_oldcount > 1) {
   2565    msgstr = N_("fewer lines");
   2566  } else {
   2567    u_oldcount = u_newcount;
   2568    if (u_newcount == 1) {
   2569      msgstr = N_("change");
   2570    } else {
   2571      msgstr = N_("changes");
   2572    }
   2573  }
   2574 
   2575  u_header_T *uhp;
   2576  if (curbuf->b_u_curhead != NULL) {
   2577    // For ":undo N" we prefer a "after #N" message.
   2578    if (absolute && curbuf->b_u_curhead->uh_next.ptr != NULL) {
   2579      uhp = curbuf->b_u_curhead->uh_next.ptr;
   2580      did_undo = false;
   2581    } else if (did_undo) {
   2582      uhp = curbuf->b_u_curhead;
   2583    } else {
   2584      uhp = curbuf->b_u_curhead->uh_next.ptr;
   2585    }
   2586  } else {
   2587    uhp = curbuf->b_u_newhead;
   2588  }
   2589 
   2590  char msgbuf[80];
   2591  if (uhp == NULL) {
   2592    *msgbuf = NUL;
   2593  } else {
   2594    undo_fmt_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
   2595  }
   2596 
   2597  {
   2598    FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
   2599      if (wp->w_buffer == curbuf && wp->w_p_cole > 0) {
   2600        redraw_later(wp, UPD_NOT_VALID);
   2601      }
   2602    }
   2603  }
   2604 
   2605  if (VIsual_active) {
   2606    check_pos(curbuf, &VIsual);
   2607  }
   2608 
   2609  smsg_keep(0, _("%" PRId64 " %s; %s #%" PRId64 "  %s"),
   2610            u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount,
   2611            _(msgstr),
   2612            did_undo ? _("before") : _("after"),
   2613            uhp == NULL ? 0 : (int64_t)uhp->uh_seq,
   2614            msgbuf);
   2615 }
   2616 
   2617 /// Put the timestamp of an undo header in "buf[buflen]" in a nice format.
   2618 void undo_fmt_time(char *buf, size_t buflen, time_t tt)
   2619 {
   2620  if (time(NULL) - tt >= 100) {
   2621    struct tm curtime;
   2622    os_localtime_r(&tt, &curtime);
   2623    size_t n;
   2624    if (time(NULL) - tt < (60 * 60 * 12)) {
   2625      // within 12 hours
   2626      n = strftime(buf, buflen, "%H:%M:%S", &curtime);
   2627    } else {
   2628      // longer ago
   2629      n = strftime(buf, buflen, "%Y/%m/%d %H:%M:%S", &curtime);
   2630    }
   2631    if (n == 0) {
   2632      buf[0] = NUL;
   2633    }
   2634  } else {
   2635    int64_t seconds = time(NULL) - tt;
   2636    vim_snprintf(buf, buflen,
   2637                 NGETTEXT("%" PRId64 " second ago",
   2638                          "%" PRId64 " seconds ago", (uint32_t)seconds),
   2639                 seconds);
   2640  }
   2641 }
   2642 
   2643 /// u_sync: stop adding to the current entry list
   2644 ///
   2645 /// @param force  if true, also sync when no_u_sync is set.
   2646 void u_sync(bool force)
   2647 {
   2648  // Skip it when already synced or syncing is disabled.
   2649  if (curbuf->b_u_synced || (!force && no_u_sync > 0)) {
   2650    return;
   2651  }
   2652 
   2653  if (get_undolevel(curbuf) < 0) {
   2654    curbuf->b_u_synced = true;  // no entries, nothing to do
   2655  } else {
   2656    u_getbot(curbuf);  // compute ue_bot of previous u_save
   2657    curbuf->b_u_curhead = NULL;
   2658  }
   2659 }
   2660 
   2661 /// ":undolist": List the leafs of the undo tree
   2662 void ex_undolist(exarg_T *eap)
   2663 {
   2664  int changes = 1;
   2665 
   2666  // 1: walk the tree to find all leafs, put the info in "ga".
   2667  // 2: sort the lines
   2668  // 3: display the list
   2669  int mark = ++lastmark;
   2670  int nomark = ++lastmark;
   2671  garray_T ga;
   2672  ga_init(&ga, (int)sizeof(char *), 20);
   2673 
   2674  u_header_T *uhp = curbuf->b_u_oldhead;
   2675  while (uhp != NULL) {
   2676    if (uhp->uh_prev.ptr == NULL && uhp->uh_walk != nomark
   2677        && uhp->uh_walk != mark) {
   2678      vim_snprintf(IObuff, IOSIZE, "%6d %7d  ", uhp->uh_seq, changes);
   2679      undo_fmt_time(IObuff + strlen(IObuff), IOSIZE - strlen(IObuff), uhp->uh_time);
   2680      if (uhp->uh_save_nr > 0) {
   2681        while (strlen(IObuff) < 33) {
   2682          xstrlcat(IObuff, " ", IOSIZE);
   2683        }
   2684        vim_snprintf_add(IObuff, IOSIZE, "  %3d", uhp->uh_save_nr);
   2685      }
   2686      GA_APPEND(char *, &ga, xstrdup(IObuff));
   2687    }
   2688 
   2689    uhp->uh_walk = mark;
   2690 
   2691    // go down in the tree if we haven't been there
   2692    if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark
   2693        && uhp->uh_prev.ptr->uh_walk != mark) {
   2694      uhp = uhp->uh_prev.ptr;
   2695      changes++;
   2696    } else if (uhp->uh_alt_next.ptr != NULL
   2697               && uhp->uh_alt_next.ptr->uh_walk != nomark
   2698               && uhp->uh_alt_next.ptr->uh_walk != mark) {
   2699      // go to alternate branch if we haven't been there
   2700      uhp = uhp->uh_alt_next.ptr;
   2701    } else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
   2702               // go up in the tree if we haven't been there and we are at the
   2703               // start of alternate branches
   2704               && uhp->uh_next.ptr->uh_walk != nomark
   2705               && uhp->uh_next.ptr->uh_walk != mark) {
   2706      uhp = uhp->uh_next.ptr;
   2707      changes--;
   2708    } else {
   2709      // need to backtrack; mark this node as done
   2710      uhp->uh_walk = nomark;
   2711      if (uhp->uh_alt_prev.ptr != NULL) {
   2712        uhp = uhp->uh_alt_prev.ptr;
   2713      } else {
   2714        uhp = uhp->uh_next.ptr;
   2715        changes--;
   2716      }
   2717    }
   2718  }
   2719 
   2720  msg_ext_set_kind("list_cmd");
   2721  if (GA_EMPTY(&ga)) {
   2722    msg(_("Nothing to undo"), 0);
   2723  } else {
   2724    sort_strings(ga.ga_data, ga.ga_len);
   2725 
   2726    msg_start();
   2727    msg_puts_hl(_("number changes  when               saved"), HLF_T, false);
   2728    for (int i = 0; i < ga.ga_len && !got_int; i++) {
   2729      msg_putchar('\n');
   2730      if (got_int) {
   2731        break;
   2732      }
   2733      msg_puts(((const char **)ga.ga_data)[i]);
   2734    }
   2735    msg_end();
   2736 
   2737    ga_clear_strings(&ga);
   2738  }
   2739 }
   2740 
   2741 /// ":undojoin": continue adding to the last entry list
   2742 void ex_undojoin(exarg_T *eap)
   2743 {
   2744  if (curbuf->b_u_newhead == NULL) {
   2745    return;                 // nothing changed before
   2746  }
   2747  if (curbuf->b_u_curhead != NULL) {
   2748    emsg(_("E790: undojoin is not allowed after undo"));
   2749    return;
   2750  }
   2751  if (!curbuf->b_u_synced) {
   2752    return;                 // already unsynced
   2753  }
   2754  if (get_undolevel(curbuf) < 0) {
   2755    return;                 // no entries, nothing to do
   2756  }
   2757  curbuf->b_u_synced = false;  // Append next change to last entry
   2758 }
   2759 
   2760 /// Called after writing or reloading the file and setting b_changed to false.
   2761 /// Now an undo means that the buffer is modified.
   2762 void u_unchanged(buf_T *buf)
   2763 {
   2764  u_unch_branch(buf->b_u_oldhead);
   2765  buf->b_did_warn = false;
   2766 }
   2767 
   2768 /// After reloading a buffer which was saved for 'undoreload': Find the first
   2769 /// line that was changed and set the cursor there.
   2770 void u_find_first_changed(void)
   2771 {
   2772  u_header_T *uhp = curbuf->b_u_newhead;
   2773 
   2774  if (curbuf->b_u_curhead != NULL || uhp == NULL) {
   2775    return;      // undid something in an autocmd?
   2776  }
   2777  // Check that the last undo block was for the whole file.
   2778  u_entry_T *uep = uhp->uh_entry;
   2779  if (uep->ue_top != 0 || uep->ue_bot != 0) {
   2780    return;
   2781  }
   2782 
   2783  linenr_T lnum;
   2784  for (lnum = 1; lnum < curbuf->b_ml.ml_line_count
   2785       && lnum <= uep->ue_size; lnum++) {
   2786    if (strcmp(ml_get_buf(curbuf, lnum), uep->ue_array[lnum - 1]) != 0) {
   2787      clearpos(&(uhp->uh_cursor));
   2788      uhp->uh_cursor.lnum = lnum;
   2789      return;
   2790    }
   2791  }
   2792  if (curbuf->b_ml.ml_line_count != uep->ue_size) {
   2793    // lines added or deleted at the end, put the cursor there
   2794    clearpos(&(uhp->uh_cursor));
   2795    uhp->uh_cursor.lnum = lnum;
   2796  }
   2797 }
   2798 
   2799 /// Increase the write count, store it in the last undo header, what would be
   2800 /// used for "u".
   2801 void u_update_save_nr(buf_T *buf)
   2802 {
   2803  buf->b_u_save_nr_last++;
   2804  buf->b_u_save_nr_cur = buf->b_u_save_nr_last;
   2805  u_header_T *uhp = buf->b_u_curhead;
   2806  if (uhp != NULL) {
   2807    uhp = uhp->uh_next.ptr;
   2808  } else {
   2809    uhp = buf->b_u_newhead;
   2810  }
   2811  if (uhp != NULL) {
   2812    uhp->uh_save_nr = buf->b_u_save_nr_last;
   2813  }
   2814 }
   2815 
   2816 static void u_unch_branch(u_header_T *uhp)
   2817 {
   2818  for (u_header_T *uh = uhp; uh != NULL; uh = uh->uh_prev.ptr) {
   2819    uh->uh_flags |= UH_CHANGED;
   2820    if (uh->uh_alt_next.ptr != NULL) {
   2821      u_unch_branch(uh->uh_alt_next.ptr);           // recursive
   2822    }
   2823  }
   2824 }
   2825 
   2826 /// Get pointer to last added entry.
   2827 /// If it's not valid, give an error message and return NULL.
   2828 static u_entry_T *u_get_headentry(buf_T *buf)
   2829 {
   2830  if (buf->b_u_newhead == NULL || buf->b_u_newhead->uh_entry == NULL) {
   2831    iemsg(_(e_undo_list_corrupt));
   2832    return NULL;
   2833  }
   2834  return buf->b_u_newhead->uh_entry;
   2835 }
   2836 
   2837 /// u_getbot(): compute the line number of the previous u_save
   2838 ///              It is called only when b_u_synced is false.
   2839 static void u_getbot(buf_T *buf)
   2840 {
   2841  u_entry_T *uep = u_get_headentry(buf);  // check for corrupt undo list
   2842  if (uep == NULL) {
   2843    return;
   2844  }
   2845 
   2846  uep = buf->b_u_newhead->uh_getbot_entry;
   2847  if (uep != NULL) {
   2848    // the new ue_bot is computed from the number of lines that has been
   2849    // inserted (0 - deleted) since calling u_save. This is equal to the
   2850    // old line count subtracted from the current line count.
   2851    linenr_T extra = buf->b_ml.ml_line_count - uep->ue_lcount;
   2852    uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra;
   2853    if (uep->ue_bot < 1 || uep->ue_bot > buf->b_ml.ml_line_count) {
   2854      iemsg(_(e_undo_line_missing));
   2855      uep->ue_bot = uep->ue_top + 1;        // assume all lines deleted, will
   2856                                            // get all the old lines back
   2857                                            // without deleting the current
   2858                                            // ones
   2859    }
   2860 
   2861    buf->b_u_newhead->uh_getbot_entry = NULL;
   2862  }
   2863 
   2864  buf->b_u_synced = true;
   2865 }
   2866 
   2867 /// Free one header "uhp" and its entry list and adjust the pointers.
   2868 ///
   2869 /// @param uhpp  if not NULL reset when freeing this header
   2870 static void u_freeheader(buf_T *buf, u_header_T *uhp, u_header_T **uhpp)
   2871 {
   2872  // When there is an alternate redo list free that branch completely,
   2873  // because we can never go there.
   2874  if (uhp->uh_alt_next.ptr != NULL) {
   2875    u_freebranch(buf, uhp->uh_alt_next.ptr, uhpp);
   2876  }
   2877 
   2878  if (uhp->uh_alt_prev.ptr != NULL) {
   2879    uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL;
   2880  }
   2881 
   2882  // Update the links in the list to remove the header.
   2883  if (uhp->uh_next.ptr == NULL) {
   2884    buf->b_u_oldhead = uhp->uh_prev.ptr;
   2885  } else {
   2886    uhp->uh_next.ptr->uh_prev.ptr = uhp->uh_prev.ptr;
   2887  }
   2888 
   2889  if (uhp->uh_prev.ptr == NULL) {
   2890    buf->b_u_newhead = uhp->uh_next.ptr;
   2891  } else {
   2892    for (u_header_T *uhap = uhp->uh_prev.ptr; uhap != NULL;
   2893         uhap = uhap->uh_alt_next.ptr) {
   2894      uhap->uh_next.ptr = uhp->uh_next.ptr;
   2895    }
   2896  }
   2897 
   2898  u_freeentries(buf, uhp, uhpp);
   2899 }
   2900 
   2901 /// Free an alternate branch and any following alternate branches.
   2902 ///
   2903 /// @param uhpp  if not NULL reset when freeing this header
   2904 static void u_freebranch(buf_T *buf, u_header_T *uhp, u_header_T **uhpp)
   2905 {
   2906  // If this is the top branch we may need to use u_freeheader() to update
   2907  // all the pointers.
   2908  if (uhp == buf->b_u_oldhead) {
   2909    while (buf->b_u_oldhead != NULL) {
   2910      u_freeheader(buf, buf->b_u_oldhead, uhpp);
   2911    }
   2912    return;
   2913  }
   2914 
   2915  if (uhp->uh_alt_prev.ptr != NULL) {
   2916    uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL;
   2917  }
   2918 
   2919  u_header_T *next = uhp;
   2920  while (next != NULL) {
   2921    u_header_T *tofree = next;
   2922    if (tofree->uh_alt_next.ptr != NULL) {
   2923      u_freebranch(buf, tofree->uh_alt_next.ptr, uhpp);         // recursive
   2924    }
   2925    next = tofree->uh_prev.ptr;
   2926    u_freeentries(buf, tofree, uhpp);
   2927  }
   2928 }
   2929 
   2930 /// Free all the undo entries for one header and the header itself.
   2931 /// This means that "uhp" is invalid when returning.
   2932 ///
   2933 /// @param uhpp  if not NULL reset when freeing this header
   2934 static void u_freeentries(buf_T *buf, u_header_T *uhp, u_header_T **uhpp)
   2935 {
   2936  // Check for pointers to the header that become invalid now.
   2937  if (buf->b_u_curhead == uhp) {
   2938    buf->b_u_curhead = NULL;
   2939  }
   2940  if (buf->b_u_newhead == uhp) {
   2941    buf->b_u_newhead = NULL;      // freeing the newest entry
   2942  }
   2943  if (uhpp != NULL && uhp == *uhpp) {
   2944    *uhpp = NULL;
   2945  }
   2946 
   2947  u_entry_T *nuep;
   2948  for (u_entry_T *uep = uhp->uh_entry; uep != NULL; uep = nuep) {
   2949    nuep = uep->ue_next;
   2950    u_freeentry(uep, uep->ue_size);
   2951  }
   2952 
   2953  kv_destroy(uhp->uh_extmark);
   2954 
   2955 #ifdef U_DEBUG
   2956  uhp->uh_magic = 0;
   2957 #endif
   2958  xfree(uhp);
   2959  buf->b_u_numhead--;
   2960 }
   2961 
   2962 /// free entry 'uep' and 'n' lines in uep->ue_array[]
   2963 static void u_freeentry(u_entry_T *uep, int n)
   2964 {
   2965  while (n > 0) {
   2966    xfree(uep->ue_array[--n]);
   2967  }
   2968  xfree(uep->ue_array);
   2969 #ifdef U_DEBUG
   2970  uep->ue_magic = 0;
   2971 #endif
   2972  xfree(uep);
   2973 }
   2974 
   2975 /// invalidate the undo buffer; called when storage has already been released
   2976 void u_clearall(buf_T *buf)
   2977 {
   2978  buf->b_u_newhead = buf->b_u_oldhead = buf->b_u_curhead = NULL;
   2979  buf->b_u_synced = true;
   2980  buf->b_u_numhead = 0;
   2981  buf->b_u_line_ptr = NULL;
   2982  buf->b_u_line_lnum = 0;
   2983 }
   2984 
   2985 /// Free all allocated memory blocks for the buffer 'buf'.
   2986 void u_blockfree(buf_T *buf)
   2987 {
   2988  while (buf->b_u_oldhead != NULL) {
   2989 #ifndef NDEBUG
   2990    u_header_T *previous_oldhead = buf->b_u_oldhead;
   2991 #endif
   2992 
   2993    u_freeheader(buf, buf->b_u_oldhead, NULL);
   2994    assert(buf->b_u_oldhead != previous_oldhead);
   2995  }
   2996  xfree(buf->b_u_line_ptr);
   2997 }
   2998 
   2999 /// Free all allocated memory blocks for the buffer 'buf'.
   3000 /// and invalidate the undo buffer
   3001 void u_clearallandblockfree(buf_T *buf)
   3002 {
   3003  u_blockfree(buf);
   3004  u_clearall(buf);
   3005 }
   3006 
   3007 /// Save the line "lnum" for the "U" command.
   3008 static void u_saveline(buf_T *buf, linenr_T lnum)
   3009 {
   3010  if (lnum == buf->b_u_line_lnum) {      // line is already saved
   3011    return;
   3012  }
   3013  if (lnum < 1 || lnum > buf->b_ml.ml_line_count) {  // should never happen
   3014    return;
   3015  }
   3016  u_clearline(buf);
   3017  buf->b_u_line_lnum = lnum;
   3018  if (curwin->w_buffer == buf && curwin->w_cursor.lnum == lnum) {
   3019    buf->b_u_line_colnr = curwin->w_cursor.col;
   3020  } else {
   3021    buf->b_u_line_colnr = 0;
   3022  }
   3023  buf->b_u_line_ptr = u_save_line_buf(buf, lnum);
   3024 }
   3025 
   3026 /// clear the line saved for the "U" command
   3027 /// (this is used externally for crossing a line while in insert mode)
   3028 void u_clearline(buf_T *buf)
   3029 {
   3030  if (buf->b_u_line_ptr == NULL) {
   3031    return;
   3032  }
   3033 
   3034  XFREE_CLEAR(buf->b_u_line_ptr);
   3035  buf->b_u_line_lnum = 0;
   3036 }
   3037 
   3038 /// Implementation of the "U" command.
   3039 /// Differentiation from vi: "U" can be undone with the next "U".
   3040 /// We also allow the cursor to be in another line.
   3041 /// Careful: may trigger autocommands that reload the buffer.
   3042 void u_undoline(void)
   3043 {
   3044  if (curbuf->b_u_line_ptr == NULL
   3045      || curbuf->b_u_line_lnum > curbuf->b_ml.ml_line_count) {
   3046    beep_flush();
   3047    return;
   3048  }
   3049 
   3050  // first save the line for the 'u' command
   3051  if (u_savecommon(curbuf, curbuf->b_u_line_lnum - 1,
   3052                   curbuf->b_u_line_lnum + 1, 0, false) == FAIL) {
   3053    return;
   3054  }
   3055 
   3056  char *oldp = u_save_line(curbuf->b_u_line_lnum);
   3057  ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, true);
   3058  extmark_splice_cols(curbuf, (int)curbuf->b_u_line_lnum - 1, 0, (colnr_T)strlen(oldp),
   3059                      (colnr_T)strlen(curbuf->b_u_line_ptr), kExtmarkUndo);
   3060  changed_bytes(curbuf->b_u_line_lnum, 0);
   3061  xfree(curbuf->b_u_line_ptr);
   3062  curbuf->b_u_line_ptr = oldp;
   3063 
   3064  colnr_T t = curbuf->b_u_line_colnr;
   3065  if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum) {
   3066    curbuf->b_u_line_colnr = curwin->w_cursor.col;
   3067  }
   3068  curwin->w_cursor.col = t;
   3069  curwin->w_cursor.lnum = curbuf->b_u_line_lnum;
   3070  check_cursor_col(curwin);
   3071 }
   3072 
   3073 /// Allocate memory and copy curbuf line into it.
   3074 ///
   3075 /// @param lnum the line to copy
   3076 static char *u_save_line(linenr_T lnum)
   3077 {
   3078  return u_save_line_buf(curbuf, lnum);
   3079 }
   3080 
   3081 /// Allocate memory and copy line into it
   3082 ///
   3083 /// @param lnum line to copy
   3084 /// @param buf buffer to copy from
   3085 static char *u_save_line_buf(buf_T *buf, linenr_T lnum)
   3086 {
   3087  return xstrdup(ml_get_buf(buf, lnum));
   3088 }
   3089 
   3090 /// Check if the 'modified' flag is set, or 'ff' has changed (only need to
   3091 /// check the first character, because it can only be "dos", "unix" or "mac").
   3092 /// "nofile" and "scratch" type buffers are considered to always be unchanged.
   3093 ///
   3094 /// @param buf The buffer to check
   3095 ///
   3096 /// @return true if the buffer has changed
   3097 bool bufIsChanged(buf_T *buf)
   3098  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
   3099 {
   3100  // In a "prompt" buffer we do respect 'modified', so that we can control
   3101  // closing the window by setting or resetting that option.
   3102  return (!bt_dontwrite(buf) || bt_prompt(buf))
   3103         && (buf->b_changed || file_ff_differs(buf, true));
   3104 }
   3105 
   3106 // Return true if any buffer has changes.  Also buffers that are not written.
   3107 bool anyBufIsChanged(void)
   3108  FUNC_ATTR_WARN_UNUSED_RESULT
   3109 {
   3110  FOR_ALL_BUFFERS(buf) {
   3111    if (bufIsChanged(buf)) {
   3112      return true;
   3113    }
   3114  }
   3115  return false;
   3116 }
   3117 
   3118 /// @see bufIsChanged
   3119 /// @return true if the current buffer has changed
   3120 bool curbufIsChanged(void)
   3121  FUNC_ATTR_WARN_UNUSED_RESULT
   3122 {
   3123  return bufIsChanged(curbuf);
   3124 }
   3125 
   3126 /// Append the list of undo blocks to a newly allocated list
   3127 ///
   3128 /// For use in undotree(). Recursive.
   3129 ///
   3130 /// @param[in]  first_uhp  Undo blocks list to start with.
   3131 ///
   3132 /// @return [allocated] List with a representation of undo blocks.
   3133 static list_T *u_eval_tree(buf_T *const buf, const u_header_T *const first_uhp)
   3134  FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
   3135 {
   3136  list_T *const list = tv_list_alloc(kListLenMayKnow);
   3137 
   3138  for (const u_header_T *uhp = first_uhp; uhp != NULL; uhp = uhp->uh_prev.ptr) {
   3139    dict_T *const dict = tv_dict_alloc();
   3140    tv_dict_add_nr(dict, S_LEN("seq"), (varnumber_T)uhp->uh_seq);
   3141    tv_dict_add_nr(dict, S_LEN("time"), (varnumber_T)uhp->uh_time);
   3142    if (uhp == buf->b_u_newhead) {
   3143      tv_dict_add_nr(dict, S_LEN("newhead"), 1);
   3144    }
   3145    if (uhp == buf->b_u_curhead) {
   3146      tv_dict_add_nr(dict, S_LEN("curhead"), 1);
   3147    }
   3148    if (uhp->uh_save_nr > 0) {
   3149      tv_dict_add_nr(dict, S_LEN("save"), (varnumber_T)uhp->uh_save_nr);
   3150    }
   3151 
   3152    if (uhp->uh_alt_next.ptr != NULL) {
   3153      // Recursive call to add alternate undo tree.
   3154      tv_dict_add_list(dict, S_LEN("alt"), u_eval_tree(buf, uhp->uh_alt_next.ptr));
   3155    }
   3156 
   3157    tv_list_append_dict(list, dict);
   3158  }
   3159 
   3160  return list;
   3161 }
   3162 
   3163 /// "undofile(name)" function
   3164 void f_undofile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3165 {
   3166  rettv->v_type = VAR_STRING;
   3167  const char *const fname = tv_get_string(&argvars[0]);
   3168 
   3169  if (*fname == NUL) {
   3170    // If there is no file name there will be no undo file.
   3171    rettv->vval.v_string = NULL;
   3172  } else {
   3173    char *ffname = FullName_save(fname, true);
   3174 
   3175    if (ffname != NULL) {
   3176      rettv->vval.v_string = u_get_undo_file_name(ffname, false);
   3177    }
   3178    xfree(ffname);
   3179  }
   3180 }
   3181 
   3182 /// "undotree(expr)" function
   3183 void f_undotree(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3184 {
   3185  tv_dict_alloc_ret(rettv);
   3186 
   3187  typval_T *const tv = &argvars[0];
   3188  buf_T *const buf = tv->v_type == VAR_UNKNOWN ? curbuf : get_buf_arg(tv);
   3189  if (buf == NULL) {
   3190    return;
   3191  }
   3192 
   3193  dict_T *dict = rettv->vval.v_dict;
   3194 
   3195  tv_dict_add_nr(dict, S_LEN("synced"), (varnumber_T)buf->b_u_synced);
   3196  tv_dict_add_nr(dict, S_LEN("seq_last"), (varnumber_T)buf->b_u_seq_last);
   3197  tv_dict_add_nr(dict, S_LEN("save_last"), (varnumber_T)buf->b_u_save_nr_last);
   3198  tv_dict_add_nr(dict, S_LEN("seq_cur"), (varnumber_T)buf->b_u_seq_cur);
   3199  tv_dict_add_nr(dict, S_LEN("time_cur"), (varnumber_T)buf->b_u_time_cur);
   3200  tv_dict_add_nr(dict, S_LEN("save_cur"), (varnumber_T)buf->b_u_save_nr_cur);
   3201 
   3202  tv_dict_add_list(dict, S_LEN("entries"), u_eval_tree(buf, buf->b_u_oldhead));
   3203 }
   3204 
   3205 // Given the buffer, Return the undo header. If none is set, set one first.
   3206 // NULL will be returned if e.g undolevels = -1 (undo disabled)
   3207 u_header_T *u_force_get_undo_header(buf_T *buf)
   3208 {
   3209  u_header_T *uhp = NULL;
   3210  if (buf->b_u_curhead != NULL) {
   3211    uhp = buf->b_u_curhead;
   3212  } else if (buf->b_u_newhead) {
   3213    uhp = buf->b_u_newhead;
   3214  }
   3215  // Create the first undo header for the buffer
   3216  if (!uhp) {
   3217    // Args are tricky: this means replace empty range by empty range..
   3218    u_savecommon(buf, 0, 1, 1, true);
   3219 
   3220    uhp = buf->b_u_curhead;
   3221    if (!uhp) {
   3222      uhp = buf->b_u_newhead;
   3223      if (get_undolevel(buf) > 0 && !uhp) {
   3224        abort();
   3225      }
   3226    }
   3227  }
   3228  return uhp;
   3229 }