To: vim-dev@vim.org Subject: Patch 6.1.165 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ------------ Patch 6.1.165 Problem: Making changes in several lines and then a change in one of these lines that splits it in two or more lines, undo information was corrupted. May cause a crash. (Dave Fishburn) Solution: When skipping to save a line for undo because it was already saved, move it to become the last saved line, so that when the command changes the line count other saved lines are not involved. Files: src/undo.c *** ../vim61.164/src/undo.c Tue Apr 9 23:19:52 2002 --- src/undo.c Sat Aug 24 23:11:19 2002 *************** *** 155,160 **** --- 155,161 ---- long i; struct u_header *uhp; u_entry_T *uep; + u_entry_T *prev_uep; long size; /* *************** *** 258,310 **** if (size == 1) { uep = u_get_headentry(); for (i = 0; i < 10; ++i) { if (uep == NULL) break; ! /* If lines have been inserted/deleted we give up. */ ! if (curbuf->b_u_newhead->uh_getbot_entry != uep ! ? (uep->ue_top + uep->ue_size + 1 ! != (uep->ue_bot == 0 ! ? curbuf->b_ml.ml_line_count + 1 ! : uep->ue_bot)) ! : uep->ue_lcount != curbuf->b_ml.ml_line_count) break; /* If it's the same line we can skip saving it again. */ if (uep->ue_size == 1 && uep->ue_top == top) { - /* If it's not the last entry, get ue_bot for the last - * entry now. Following deleted/inserted lines go to the - * re-used entry. */ if (i > 0) { u_getbot(); curbuf->b_u_synced = FALSE; } ! /* The line count might change afterwards. */ if (newbot != 0) - { - /* When changing the line count and it's not the - * newest entry, must adjust the line numbers of older - * entries. */ - if (uep != curbuf->b_u_newhead->uh_entry - && uep->ue_bot != newbot) - { - u_entry_T *p; - - for (p = curbuf->b_u_newhead->uh_entry; - p != uep; p = p->ue_next) - { - if (p->ue_bot != 0) - p->ue_bot -= uep->ue_bot - newbot; - p->ue_top -= uep->ue_bot - newbot; - } - } uep->ue_bot = newbot; - } else if (bot > curbuf->b_ml.ml_line_count) uep->ue_bot = 0; else --- 259,308 ---- if (size == 1) { uep = u_get_headentry(); + prev_uep = NULL; for (i = 0; i < 10; ++i) { if (uep == NULL) break; ! /* If lines have been inserted/deleted we give up. ! * Also when the line was included in a multi-line save. */ ! if ((curbuf->b_u_newhead->uh_getbot_entry != uep ! ? (uep->ue_top + uep->ue_size + 1 ! != (uep->ue_bot == 0 ! ? curbuf->b_ml.ml_line_count + 1 ! : uep->ue_bot)) ! : uep->ue_lcount != curbuf->b_ml.ml_line_count) ! || (uep->ue_size > 1 ! && top >= uep->ue_top ! && top + 2 <= uep->ue_top + uep->ue_size + 1)) break; /* If it's the same line we can skip saving it again. */ if (uep->ue_size == 1 && uep->ue_top == top) { if (i > 0) { + /* It's not the last entry: get ue_bot for the last + * entry now. Following deleted/inserted lines go to + * the re-used entry. */ u_getbot(); curbuf->b_u_synced = FALSE; + + /* Move the found entry to become the last entry. The + * order of undo/redo doesn't matter for the entries + * we move it over, since they don't change the line + * count and don't include this line. It does matter + * for the found entry if the line count is changed by + * the executed command. */ + prev_uep->ue_next = uep->ue_next; + uep->ue_next = curbuf->b_u_newhead->uh_entry; + curbuf->b_u_newhead->uh_entry = uep; } ! /* The executed command may change the line count. */ if (newbot != 0) uep->ue_bot = newbot; else if (bot > curbuf->b_ml.ml_line_count) uep->ue_bot = 0; else *************** *** 314,319 **** --- 312,318 ---- } return OK; } + prev_uep = uep; uep = uep->ue_next; } } *************** *** 775,782 **** { /* * the new ue_bot is computed from the number of lines that has been ! * inserted (0 - deleted) since calling u_save. This is equal to the old ! * line count subtracted from the current line count. */ extra = curbuf->b_ml.ml_line_count - uep->ue_lcount; uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra; --- 774,781 ---- { /* * the new ue_bot is computed from the number of lines that has been ! * inserted (0 - deleted) since calling u_save. This is equal to the ! * old line count subtracted from the current line count. */ extra = curbuf->b_ml.ml_line_count - uep->ue_lcount; uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra; *************** *** 788,804 **** * without deleting the current * ones */ } - - /* If not the newest entry and lines have been inserted or deleted, - * newer entries must have their line numbers adjusted. */ - if (extra != 0) - for (uep = curbuf->b_u_newhead->uh_entry; - uep != curbuf->b_u_newhead->uh_getbot_entry; - uep = uep->ue_next) - { - uep->ue_bot -= extra; - uep->ue_top -= extra; - } curbuf->b_u_newhead->uh_getbot_entry = NULL; } --- 787,792 ---- *** ../vim61.164/src/version.c Sat Aug 24 23:19:56 2002 --- src/version.c Sat Aug 24 23:21:09 2002 *************** *** 608,609 **** --- 608,611 ---- { /* Add new patch number below this line */ + /**/ + 165, /**/ -- His head smashed in, and his heart cut out, And his liver removed, and his bowels unplugged, And his nostrils raped, and his bottom burned off, And his penis split ... and his ... "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@moolenaar.net -- http://www.moolenaar.net \\\ /// Creator of Vim -- http://vim.sf.net -- ftp://ftp.vim.org/pub/vim \\\ \\\ Project leader for A-A-P -- http://www.a-a-p.org /// \\\ Lord Of The Rings helps Uganda - http://iccf-holland.org/lotr.html ///