Mercurial > vim
comparison src/undo.c @ 1415:20b52d44daaf v7.1.130
updated for version 7.1-130
author | vimboss |
---|---|
date | Mon, 01 Oct 2007 20:54:15 +0000 |
parents | 302520c08584 |
children | 93ffa40b5320 |
comparison
equal
deleted
inserted
replaced
1414:1f099ff4f6fb | 1415:20b52d44daaf |
---|---|
74 * | 74 * |
75 * All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the | 75 * All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the |
76 * buffer is unloaded. | 76 * buffer is unloaded. |
77 */ | 77 */ |
78 | 78 |
79 /* Uncomment the next line for including the u_check() function. This warns | |
80 * for errors in the debug information. */ | |
81 /* #define U_DEBUG 1 */ | |
82 #define UH_MAGIC 0x18dade /* value for uh_magic when in use */ | |
83 #define UE_MAGIC 0xabc123 /* value for ue_magic when in use */ | |
84 | |
79 #include "vim.h" | 85 #include "vim.h" |
80 | 86 |
81 /* See below: use malloc()/free() for memory management. */ | 87 /* See below: use malloc()/free() for memory management. */ |
82 #define U_USE_MALLOC 1 | 88 #define U_USE_MALLOC 1 |
83 | 89 |
111 * When 'u' flag included in 'cpoptions', we behave like vi. Need to remember | 117 * When 'u' flag included in 'cpoptions', we behave like vi. Need to remember |
112 * the action that "u" should do. | 118 * the action that "u" should do. |
113 */ | 119 */ |
114 static int undo_undoes = FALSE; | 120 static int undo_undoes = FALSE; |
115 | 121 |
122 #ifdef U_DEBUG | |
123 /* | |
124 * Check the undo structures for being valid. Print a warning when something | |
125 * looks wrong. | |
126 */ | |
127 static int seen_b_u_curhead; | |
128 static int seen_b_u_newhead; | |
129 static int header_count; | |
130 | |
131 static void | |
132 u_check_tree(u_header_T *uhp, | |
133 u_header_T *exp_uh_next, | |
134 u_header_T *exp_uh_alt_prev) | |
135 { | |
136 u_entry_T *uep; | |
137 | |
138 if (uhp == NULL) | |
139 return; | |
140 ++header_count; | |
141 if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1) | |
142 { | |
143 EMSG("b_u_curhead found twice (looping?)"); | |
144 return; | |
145 } | |
146 if (uhp == curbuf->b_u_newhead && ++seen_b_u_newhead > 1) | |
147 { | |
148 EMSG("b_u_newhead found twice (looping?)"); | |
149 return; | |
150 } | |
151 | |
152 if (uhp->uh_magic != UH_MAGIC) | |
153 EMSG("uh_magic wrong (may be using freed memory)"); | |
154 else | |
155 { | |
156 /* Check pointers back are correct. */ | |
157 if (uhp->uh_next != exp_uh_next) | |
158 { | |
159 EMSG("uh_next wrong"); | |
160 smsg((char_u *)"expected: 0x%x, actual: 0x%x", | |
161 exp_uh_next, uhp->uh_next); | |
162 } | |
163 if (uhp->uh_alt_prev != exp_uh_alt_prev) | |
164 { | |
165 EMSG("uh_alt_prev wrong"); | |
166 smsg((char_u *)"expected: 0x%x, actual: 0x%x", | |
167 exp_uh_alt_prev, uhp->uh_alt_prev); | |
168 } | |
169 | |
170 /* Check the undo tree at this header. */ | |
171 for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) | |
172 { | |
173 if (uep->ue_magic != UE_MAGIC) | |
174 { | |
175 EMSG("ue_magic wrong (may be using freed memory)"); | |
176 break; | |
177 } | |
178 } | |
179 | |
180 /* Check the next alt tree. */ | |
181 u_check_tree(uhp->uh_alt_next, uhp->uh_next, uhp); | |
182 | |
183 /* Check the next header in this branch. */ | |
184 u_check_tree(uhp->uh_prev, uhp, NULL); | |
185 } | |
186 } | |
187 | |
188 void | |
189 u_check(int newhead_may_be_NULL) | |
190 { | |
191 seen_b_u_newhead = 0; | |
192 seen_b_u_curhead = 0; | |
193 header_count = 0; | |
194 | |
195 u_check_tree(curbuf->b_u_oldhead, NULL, NULL); | |
196 | |
197 if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL | |
198 && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL)) | |
199 EMSGN("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead); | |
200 if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0) | |
201 EMSGN("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead); | |
202 if (header_count != curbuf->b_u_numhead) | |
203 { | |
204 EMSG("b_u_numhead invalid"); | |
205 smsg((char_u *)"expected: %ld, actual: %ld", | |
206 (long)header_count, (long)curbuf->b_u_numhead); | |
207 } | |
208 } | |
209 #endif | |
210 | |
116 /* | 211 /* |
117 * Save the current line for both the "u" and "U" command. | 212 * Save the current line for both the "u" and "U" command. |
118 * Returns OK or FAIL. | 213 * Returns OK or FAIL. |
119 */ | 214 */ |
120 int | 215 int |
241 /* When making changes is not allowed return FAIL. It's a crude way to | 336 /* When making changes is not allowed return FAIL. It's a crude way to |
242 * make all change commands fail. */ | 337 * make all change commands fail. */ |
243 if (!undo_allowed()) | 338 if (!undo_allowed()) |
244 return FAIL; | 339 return FAIL; |
245 | 340 |
341 #ifdef U_DEBUG | |
342 u_check(FALSE); | |
343 #endif | |
246 #ifdef FEAT_NETBEANS_INTG | 344 #ifdef FEAT_NETBEANS_INTG |
247 /* | 345 /* |
248 * Netbeans defines areas that cannot be modified. Bail out here when | 346 * Netbeans defines areas that cannot be modified. Bail out here when |
249 * trying to change text in a guarded area. | 347 * trying to change text in a guarded area. |
250 */ | 348 */ |
292 * up the undo info when out of memory. | 390 * up the undo info when out of memory. |
293 */ | 391 */ |
294 uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T)); | 392 uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T)); |
295 if (uhp == NULL) | 393 if (uhp == NULL) |
296 goto nomem; | 394 goto nomem; |
395 #ifdef U_DEBUG | |
396 uhp->uh_magic = UH_MAGIC; | |
397 #endif | |
297 } | 398 } |
298 else | 399 else |
299 uhp = NULL; | 400 uhp = NULL; |
300 | 401 |
301 /* | 402 /* |
314 */ | 415 */ |
315 while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL) | 416 while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL) |
316 { | 417 { |
317 u_header_T *uhfree = curbuf->b_u_oldhead; | 418 u_header_T *uhfree = curbuf->b_u_oldhead; |
318 | 419 |
319 /* If there is no branch only free one header. */ | 420 if (uhfree == old_curhead) |
320 if (uhfree->uh_alt_next == NULL) | 421 /* Can't reconnect the branch, delete all of it. */ |
422 u_freebranch(curbuf, uhfree, &old_curhead); | |
423 else if (uhfree->uh_alt_next == NULL) | |
424 /* There is no branch, only free one header. */ | |
321 u_freeheader(curbuf, uhfree, &old_curhead); | 425 u_freeheader(curbuf, uhfree, &old_curhead); |
322 else | 426 else |
323 { | 427 { |
324 /* Free the oldest alternate branch as a whole. */ | 428 /* Free the oldest alternate branch as a whole. */ |
325 while (uhfree->uh_alt_next != NULL) | 429 while (uhfree->uh_alt_next != NULL) |
326 uhfree = uhfree->uh_alt_next; | 430 uhfree = uhfree->uh_alt_next; |
327 u_freebranch(curbuf, uhfree, &old_curhead); | 431 u_freebranch(curbuf, uhfree, &old_curhead); |
328 } | 432 } |
433 #ifdef U_DEBUG | |
434 u_check(TRUE); | |
435 #endif | |
329 } | 436 } |
330 | 437 |
331 if (uhp == NULL) /* no undo at all */ | 438 if (uhp == NULL) /* no undo at all */ |
332 { | 439 { |
333 if (old_curhead != NULL) | 440 if (old_curhead != NULL) |
476 * add lines in front of entry list | 583 * add lines in front of entry list |
477 */ | 584 */ |
478 uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T)); | 585 uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T)); |
479 if (uep == NULL) | 586 if (uep == NULL) |
480 goto nomem; | 587 goto nomem; |
588 #ifdef U_DEBUG | |
589 uep->ue_magic = UE_MAGIC; | |
590 #endif | |
481 | 591 |
482 uep->ue_size = size; | 592 uep->ue_size = size; |
483 uep->ue_top = top; | 593 uep->ue_top = top; |
484 if (newbot != 0) | 594 if (newbot != 0) |
485 uep->ue_bot = newbot; | 595 uep->ue_bot = newbot; |
523 uep->ue_next = curbuf->b_u_newhead->uh_entry; | 633 uep->ue_next = curbuf->b_u_newhead->uh_entry; |
524 curbuf->b_u_newhead->uh_entry = uep; | 634 curbuf->b_u_newhead->uh_entry = uep; |
525 curbuf->b_u_synced = FALSE; | 635 curbuf->b_u_synced = FALSE; |
526 undo_undoes = FALSE; | 636 undo_undoes = FALSE; |
527 | 637 |
638 #ifdef U_DEBUG | |
639 u_check(FALSE); | |
640 #endif | |
528 return OK; | 641 return OK; |
529 | 642 |
530 nomem: | 643 nomem: |
531 msg_silent = 0; /* must display the prompt */ | 644 msg_silent = 0; /* must display the prompt */ |
532 if (ask_yesno((char_u *)_("No undo possible; continue anyway"), TRUE) | 645 if (ask_yesno((char_u *)_("No undo possible; continue anyway"), TRUE) |
953 visualinfo_T visualinfo; | 1066 visualinfo_T visualinfo; |
954 #endif | 1067 #endif |
955 int empty_buffer; /* buffer became empty */ | 1068 int empty_buffer; /* buffer became empty */ |
956 u_header_T *curhead = curbuf->b_u_curhead; | 1069 u_header_T *curhead = curbuf->b_u_curhead; |
957 | 1070 |
1071 #ifdef U_DEBUG | |
1072 u_check(FALSE); | |
1073 #endif | |
958 old_flags = curhead->uh_flags; | 1074 old_flags = curhead->uh_flags; |
959 new_flags = (curbuf->b_changed ? UH_CHANGED : 0) + | 1075 new_flags = (curbuf->b_changed ? UH_CHANGED : 0) + |
960 ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); | 1076 ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); |
961 setpcmark(); | 1077 setpcmark(); |
962 | 1078 |
1184 --curbuf->b_u_seq_cur; | 1300 --curbuf->b_u_seq_cur; |
1185 | 1301 |
1186 /* The timestamp can be the same for multiple changes, just use the one of | 1302 /* The timestamp can be the same for multiple changes, just use the one of |
1187 * the undone/redone change. */ | 1303 * the undone/redone change. */ |
1188 curbuf->b_u_seq_time = curhead->uh_time; | 1304 curbuf->b_u_seq_time = curhead->uh_time; |
1305 #ifdef U_DEBUG | |
1306 u_check(FALSE); | |
1307 #endif | |
1189 } | 1308 } |
1190 | 1309 |
1191 /* | 1310 /* |
1192 * If we deleted or added lines, report the number of less/more lines. | 1311 * If we deleted or added lines, report the number of less/more lines. |
1193 * Otherwise, report the number of changes (this may be incorrect | 1312 * Otherwise, report the number of changes (this may be incorrect |
1513 | 1632 |
1514 curbuf->b_u_synced = TRUE; | 1633 curbuf->b_u_synced = TRUE; |
1515 } | 1634 } |
1516 | 1635 |
1517 /* | 1636 /* |
1518 * Free one header and its entry list and adjust the pointers. | 1637 * Free one header "uhp" and its entry list and adjust the pointers. |
1519 */ | 1638 */ |
1520 static void | 1639 static void |
1521 u_freeheader(buf, uhp, uhpp) | 1640 u_freeheader(buf, uhp, uhpp) |
1522 buf_T *buf; | 1641 buf_T *buf; |
1523 u_header_T *uhp; | 1642 u_header_T *uhp; |
1524 u_header_T **uhpp; /* if not NULL reset when freeing this header */ | 1643 u_header_T **uhpp; /* if not NULL reset when freeing this header */ |
1525 { | 1644 { |
1645 u_header_T *uhap; | |
1646 | |
1526 /* When there is an alternate redo list free that branch completely, | 1647 /* When there is an alternate redo list free that branch completely, |
1527 * because we can never go there. */ | 1648 * because we can never go there. */ |
1528 if (uhp->uh_alt_next != NULL) | 1649 if (uhp->uh_alt_next != NULL) |
1529 u_freebranch(buf, uhp->uh_alt_next, uhpp); | 1650 u_freebranch(buf, uhp->uh_alt_next, uhpp); |
1530 | 1651 |
1538 uhp->uh_next->uh_prev = uhp->uh_prev; | 1659 uhp->uh_next->uh_prev = uhp->uh_prev; |
1539 | 1660 |
1540 if (uhp->uh_prev == NULL) | 1661 if (uhp->uh_prev == NULL) |
1541 buf->b_u_newhead = uhp->uh_next; | 1662 buf->b_u_newhead = uhp->uh_next; |
1542 else | 1663 else |
1543 uhp->uh_prev->uh_next = uhp->uh_next; | 1664 for (uhap = uhp->uh_prev; uhap != NULL; uhap = uhap->uh_alt_next) |
1665 uhap->uh_next = uhp->uh_next; | |
1544 | 1666 |
1545 u_freeentries(buf, uhp, uhpp); | 1667 u_freeentries(buf, uhp, uhpp); |
1546 } | 1668 } |
1547 | 1669 |
1548 /* | 1670 /* |
1583 u_entry_T *uep, *nuep; | 1705 u_entry_T *uep, *nuep; |
1584 | 1706 |
1585 /* Check for pointers to the header that become invalid now. */ | 1707 /* Check for pointers to the header that become invalid now. */ |
1586 if (buf->b_u_curhead == uhp) | 1708 if (buf->b_u_curhead == uhp) |
1587 buf->b_u_curhead = NULL; | 1709 buf->b_u_curhead = NULL; |
1710 if (buf->b_u_newhead == uhp) | |
1711 buf->b_u_newhead = NULL; /* freeing the newest entry */ | |
1588 if (uhpp != NULL && uhp == *uhpp) | 1712 if (uhpp != NULL && uhp == *uhpp) |
1589 *uhpp = NULL; | 1713 *uhpp = NULL; |
1590 | 1714 |
1591 for (uep = uhp->uh_entry; uep != NULL; uep = nuep) | 1715 for (uep = uhp->uh_entry; uep != NULL; uep = nuep) |
1592 { | 1716 { |
1593 nuep = uep->ue_next; | 1717 nuep = uep->ue_next; |
1594 u_freeentry(uep, uep->ue_size); | 1718 u_freeentry(uep, uep->ue_size); |
1595 } | 1719 } |
1596 | 1720 |
1721 #ifdef U_DEBUG | |
1722 uhp->uh_magic = 0; | |
1723 #endif | |
1597 U_FREE_LINE((char_u *)uhp); | 1724 U_FREE_LINE((char_u *)uhp); |
1598 --buf->b_u_numhead; | 1725 --buf->b_u_numhead; |
1599 } | 1726 } |
1600 | 1727 |
1601 /* | 1728 /* |
1607 long n; | 1734 long n; |
1608 { | 1735 { |
1609 while (n > 0) | 1736 while (n > 0) |
1610 U_FREE_LINE(uep->ue_array[--n]); | 1737 U_FREE_LINE(uep->ue_array[--n]); |
1611 U_FREE_LINE((char_u *)uep->ue_array); | 1738 U_FREE_LINE((char_u *)uep->ue_array); |
1739 #ifdef U_DEBUG | |
1740 uep->ue_magic = 0; | |
1741 #endif | |
1612 U_FREE_LINE((char_u *)uep); | 1742 U_FREE_LINE((char_u *)uep); |
1613 } | 1743 } |
1614 | 1744 |
1615 /* | 1745 /* |
1616 * invalidate the undo buffer; called when storage has already been released | 1746 * invalidate the undo buffer; called when storage has already been released |