Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
8.3 KiB

  1. /* $Header: /nw/tony/src/stevie/src/RCS/undo.c,v 1.7 89/08/06 09:51:06 tony Exp $
  2. *
  3. * Undo facility
  4. *
  5. * The routines in this file comprise a general undo facility for use
  6. * throughout the rest of the editor. The routine u_save() is called
  7. * before each edit operation to save the current contents of the lines
  8. * to be editted. Later, u_undo() can be called to return those lines
  9. * to their original state. The routine u_clear() should be called
  10. * whenever a new file is going to be editted to clear the undo buffer.
  11. */
  12. #include "stevie.h"
  13. /*
  14. * The next two variables mark the boundaries of the changed section
  15. * of the file. Lines BETWEEN the lower and upper bounds are changed
  16. * and originally contained the lines pointed to by u_lines. To undo
  17. * the last change, insert the lines in u_lines between the lower and
  18. * upper bounds.
  19. */
  20. static LINE *u_lbound = NULL; /* line just prior to first changed line */
  21. static LINE *u_ubound = NULL; /* line just after the last changed line */
  22. static LINE *u_lline = NULL; /* bounds of the saved lines */
  23. static LINE *u_uline = NULL;
  24. static int u_col;
  25. static bool_t u_valid = FALSE; /* is the undo buffer valid */
  26. /*
  27. * Local forward declarations
  28. */
  29. static LINE *copyline();
  30. static void u_lsave();
  31. static void u_lfree();
  32. /*
  33. * u_save(l, u) - save the current contents of part of the file
  34. *
  35. * The lines between 'l' and 'u' are about to be changed. This routine
  36. * saves their current contents into the undo buffer. The range l to u
  37. * is not inclusive because when we do an open, for example, there aren't
  38. * any lines in between. If no lines are to be saved, then l->next == u.
  39. */
  40. void
  41. u_save(l, u)
  42. LINE *l, *u;
  43. {
  44. LINE *nl; /* copy of the current line */
  45. /*
  46. * If l or u is null, there's an error. We don't return an
  47. * indication to the caller. They should find the problem
  48. * while trying to perform whatever edit is being requested
  49. * (e.g. a join on the last line).
  50. */
  51. if (l == NULL || u == NULL)
  52. return;
  53. u_clear(); /* clear the buffer, first */
  54. u_lsave(l, u); /* save to the "line undo" buffer, if needed */
  55. u_lbound = l;
  56. u_ubound = u;
  57. if (l->next != u) { /* there are lines in the middle */
  58. l = l->next;
  59. u = u->prev;
  60. u_lline = nl = copyline(l); /* copy the first line */
  61. while (l != u) {
  62. nl->next = copyline(l->next);
  63. nl->next->prev = nl;
  64. l = l->next;
  65. nl = nl->next;
  66. }
  67. u_uline = nl;
  68. } else
  69. u_lline = u_uline = NULL;
  70. u_valid = TRUE;
  71. u_col = Cursvcol;
  72. }
  73. /*
  74. * u_saveline() - save the current line in the undo buffer
  75. */
  76. void
  77. u_saveline()
  78. {
  79. u_save(Curschar->linep->prev, Curschar->linep->next);
  80. }
  81. /*
  82. * u_undo() - effect an 'undo' operation
  83. *
  84. * The last edit is undone by restoring the modified section of the file
  85. * to its original state. The lines we're going to trash are copied to
  86. * the undo buffer so that even an 'undo' can be undone. Rings the bell
  87. * if the undo buffer is empty.
  88. */
  89. void
  90. u_undo()
  91. {
  92. LINE *tl, *tu;
  93. if (!u_valid) {
  94. beep();
  95. return;
  96. }
  97. /*
  98. * Get the first line of the thing we're undoing on the screen.
  99. */
  100. Curschar->linep = u_lbound->next;
  101. Curschar->index = 0; /* for now */
  102. if (Curschar->linep == Fileend->linep)
  103. Curschar->linep = Curschar->linep->prev;
  104. cursupdate();
  105. /*
  106. * Save pointers to what's in the file now.
  107. */
  108. if (u_lbound->next != u_ubound) { /* there are lines to get */
  109. tl = u_lbound->next;
  110. tu = u_ubound->prev;
  111. tl->prev = NULL;
  112. tu->next = NULL;
  113. } else
  114. tl = tu = NULL; /* no lines between bounds */
  115. /*
  116. * Link the undo buffer into the right place in the file.
  117. */
  118. if (u_lline != NULL) { /* there are lines in the undo buf */
  119. /*
  120. * If the top line of the screen is being undone, we need to
  121. * fix up Topchar to point to the new line that will be there.
  122. */
  123. if (u_lbound->next == Topchar->linep)
  124. Topchar->linep = u_lline;
  125. u_lbound->next = u_lline;
  126. u_lline->prev = u_lbound;
  127. u_ubound->prev = u_uline;
  128. u_uline->next = u_ubound;
  129. } else { /* no lines... link the bounds */
  130. if (u_lbound->next == Topchar->linep)
  131. Topchar->linep = u_ubound;
  132. if (u_lbound == Filetop->linep)
  133. Topchar->linep = u_ubound;
  134. u_lbound->next = u_ubound;
  135. u_ubound->prev = u_lbound;
  136. }
  137. /*
  138. * If we swapped the top line, patch up Filemem appropriately.
  139. */
  140. if (u_lbound == Filetop->linep)
  141. Filemem->linep = Filetop->linep->next;
  142. /*
  143. * Now save the old stuff in the undo buffer.
  144. */
  145. u_lline = tl;
  146. u_uline = tu;
  147. renum(); /* have to renumber everything */
  148. /*
  149. * Put the cursor on the first line of the 'undo' region.
  150. */
  151. Curschar->linep = u_lbound->next;
  152. Curschar->index = 0;
  153. if (Curschar->linep == Fileend->linep)
  154. Curschar->linep = Curschar->linep->prev;
  155. *Curschar = *coladvance(Curschar, u_col);
  156. cursupdate();
  157. updatescreen(); /* now show the change */
  158. u_lfree(); /* clear the "line undo" buffer */
  159. }
  160. /*
  161. * u_clear() - clear the undo buffer
  162. *
  163. * This routine is called to clear the undo buffer at times when the
  164. * pointers are about to become invalid, such as when a new file is
  165. * about to be editted.
  166. */
  167. void
  168. u_clear()
  169. {
  170. LINE *l, *nextl;
  171. if (!u_valid) /* nothing to do */
  172. return;
  173. for (l = u_lline; l != NULL ;l = nextl) {
  174. nextl = l->next;
  175. free(l->s);
  176. free((char *)l);
  177. }
  178. u_lbound = u_ubound = u_lline = u_uline = NULL;
  179. u_valid = FALSE;
  180. }
  181. /*
  182. * The following functions and data implement the "line undo" feature
  183. * performed by the 'U' command.
  184. */
  185. static LINE *u_line; /* pointer to the line we last saved */
  186. static LINE *u_lcopy = NULL; /* local copy of the original line */
  187. /*
  188. * u_lfree() - free the line save buffer
  189. */
  190. static void
  191. u_lfree()
  192. {
  193. if (u_lcopy != NULL) {
  194. free(u_lcopy->s);
  195. free((char *)u_lcopy);
  196. u_lcopy = NULL;
  197. }
  198. u_line = NULL;
  199. }
  200. /*
  201. * u_lsave() - save the current line if necessary
  202. */
  203. static void
  204. u_lsave(l, u)
  205. LINE *l, *u;
  206. {
  207. if (l->next != u->prev) { /* not changing exactly one line */
  208. u_lfree();
  209. return;
  210. }
  211. if (l->next == u_line) /* more edits on the same line */
  212. return;
  213. u_lfree();
  214. u_line = l->next;
  215. u_lcopy = copyline(l->next);
  216. }
  217. /*
  218. * u_lundo() - undo the current line (the 'U' command)
  219. */
  220. void
  221. u_lundo()
  222. {
  223. if (u_lcopy != NULL) {
  224. free(Curschar->linep->s);
  225. Curschar->linep->s = u_lcopy->s;
  226. Curschar->linep->size = u_lcopy->size;
  227. free((char *)u_lcopy);
  228. } else
  229. beep();
  230. Curschar->index = 0;
  231. cursupdate();
  232. updatescreen(); /* now show the change */
  233. u_lcopy = NULL; /* can't undo this kind of undo */
  234. u_line = NULL;
  235. }
  236. /*
  237. * u_lcheck() - clear the "line undo" buffer if we've moved to a new line
  238. */
  239. void
  240. u_lcheck()
  241. {
  242. if (Curschar->linep != u_line)
  243. u_lfree();
  244. }
  245. /*
  246. * copyline(l) - copy the given line, and return a pointer to the copy
  247. */
  248. static LINE *
  249. copyline(l)
  250. LINE *l;
  251. {
  252. LINE *nl; /* the new line */
  253. nl = newline(strlen(l->s));
  254. strcpy(nl->s, l->s);
  255. return nl;
  256. }