Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <cursor.h>
6 #include <mouse.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include <fcall.h>
10 #include <plumb.h>
11 #include "dat.h"
12 #include "fns.h"
14 /*
15 * Structure of Undo list:
16 * The Undo structure follows any associated data, so the list
17 * can be read backwards: read the structure, then read whatever
18 * data is associated (insert string, file name) and precedes it.
19 * The structure includes the previous value of the modify bit
20 * and a sequence number; successive Undo structures with the
21 * same sequence number represent simultaneous changes.
22 */
24 typedef struct Undo Undo;
25 struct Undo
26 {
27 short type; /* Delete, Insert, Filename */
28 short mod; /* modify bit */
29 uint seq; /* sequence number */
30 uint p0; /* location of change (unused in f) */
31 uint n; /* # runes in string or file name */
32 };
34 enum
35 {
36 Undosize = sizeof(Undo)/sizeof(Rune),
37 };
39 File*
40 fileaddtext(File *f, Text *t)
41 {
42 if(f == nil){
43 f = emalloc(sizeof(File));
44 f->unread = TRUE;
45 }
46 f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
47 f->text[f->ntext++] = t;
48 f->curtext = t;
49 return f;
50 }
52 void
53 filedeltext(File *f, Text *t)
54 {
55 int i;
57 for(i=0; i<f->ntext; i++)
58 if(f->text[i] == t)
59 goto Found;
60 error("can't find text in filedeltext");
62 Found:
63 f->ntext--;
64 if(f->ntext == 0){
65 fileclose(f);
66 return;
67 }
68 memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
69 if(f->curtext == t)
70 f->curtext = f->text[0];
71 }
73 void
74 fileinsert(File *f, uint p0, Rune *s, uint ns)
75 {
76 if(p0 > f->b.nc)
77 error("internal error: fileinsert");
78 if(f->seq > 0)
79 fileuninsert(f, &f->delta, p0, ns);
80 bufinsert(&f->b, p0, s, ns);
81 if(ns)
82 f->mod = TRUE;
83 }
85 void
86 fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
87 {
88 Undo u;
90 /* undo an insertion by deleting */
91 u.type = Delete;
92 u.mod = f->mod;
93 u.seq = f->seq;
94 u.p0 = p0;
95 u.n = ns;
96 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
97 }
99 void
100 filedelete(File *f, uint p0, uint p1)
102 if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
103 error("internal error: filedelete");
104 if(f->seq > 0)
105 fileundelete(f, &f->delta, p0, p1);
106 bufdelete(&f->b, p0, p1);
107 if(p1 > p0)
108 f->mod = TRUE;
111 void
112 fileundelete(File *f, Buffer *delta, uint p0, uint p1)
114 Undo u;
115 Rune *buf;
116 uint i, n;
118 /* undo a deletion by inserting */
119 u.type = Insert;
120 u.mod = f->mod;
121 u.seq = f->seq;
122 u.p0 = p0;
123 u.n = p1-p0;
124 buf = fbufalloc();
125 for(i=p0; i<p1; i+=n){
126 n = p1 - i;
127 if(n > RBUFSIZE)
128 n = RBUFSIZE;
129 bufread(&f->b, i, buf, n);
130 bufinsert(delta, delta->nc, buf, n);
132 fbuffree(buf);
133 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
137 void
138 filesetname(File *f, Rune *name, int n)
140 if(f->seq > 0)
141 fileunsetname(f, &f->delta);
142 free(f->name);
143 f->name = runemalloc(n);
144 runemove(f->name, name, n);
145 f->nname = n;
146 f->unread = TRUE;
149 void
150 fileunsetname(File *f, Buffer *delta)
152 Undo u;
154 /* undo a file name change by restoring old name */
155 u.type = Filename;
156 u.mod = f->mod;
157 u.seq = f->seq;
158 u.p0 = 0; /* unused */
159 u.n = f->nname;
160 if(f->nname)
161 bufinsert(delta, delta->nc, f->name, f->nname);
162 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
165 uint
166 fileload(File *f, uint p0, int fd, int *nulls)
168 if(f->seq > 0)
169 error("undo in file.load unimplemented");
170 return bufload(&f->b, p0, fd, nulls);
173 /* return sequence number of pending redo */
174 uint
175 fileredoseq(File *f)
177 Undo u;
178 Buffer *delta;
180 delta = &f->epsilon;
181 if(delta->nc == 0)
182 return 0;
183 bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize);
184 return u.seq;
187 void
188 fileundo(File *f, int isundo, uint *q0p, uint *q1p)
190 Undo u;
191 Rune *buf;
192 uint i, j, n, up;
193 uint stop;
194 Buffer *delta, *epsilon;
196 if(isundo){
197 /* undo; reverse delta onto epsilon, seq decreases */
198 delta = &f->delta;
199 epsilon = &f->epsilon;
200 stop = f->seq;
201 }else{
202 /* redo; reverse epsilon onto delta, seq increases */
203 delta = &f->epsilon;
204 epsilon = &f->delta;
205 stop = 0; /* don't know yet */
208 buf = fbufalloc();
209 while(delta->nc > 0){
210 up = delta->nc-Undosize;
211 bufread(delta, up, (Rune*)&u, Undosize);
212 if(isundo){
213 if(u.seq < stop){
214 f->seq = u.seq;
215 goto Return;
217 }else{
218 if(stop == 0)
219 stop = u.seq;
220 if(u.seq > stop)
221 goto Return;
223 switch(u.type){
224 default:
225 fprint(2, "undo: 0x%ux\n", u.type);
226 abort();
227 break;
229 case Delete:
230 f->seq = u.seq;
231 fileundelete(f, epsilon, u.p0, u.p0+u.n);
232 f->mod = u.mod;
233 bufdelete(&f->b, u.p0, u.p0+u.n);
234 for(j=0; j<f->ntext; j++)
235 textdelete(f->text[j], u.p0, u.p0+u.n, FALSE);
236 *q0p = u.p0;
237 *q1p = u.p0;
238 break;
240 case Insert:
241 f->seq = u.seq;
242 fileuninsert(f, epsilon, u.p0, u.n);
243 f->mod = u.mod;
244 up -= u.n;
245 for(i=0; i<u.n; i+=n){
246 n = u.n - i;
247 if(n > RBUFSIZE)
248 n = RBUFSIZE;
249 bufread(delta, up+i, buf, n);
250 bufinsert(&f->b, u.p0+i, buf, n);
251 for(j=0; j<f->ntext; j++)
252 textinsert(f->text[j], u.p0+i, buf, n, FALSE);
254 *q0p = u.p0;
255 *q1p = u.p0+u.n;
256 break;
258 case Filename:
259 f->seq = u.seq;
260 fileunsetname(f, epsilon);
261 f->mod = u.mod;
262 up -= u.n;
263 free(f->name);
264 if(u.n == 0)
265 f->name = nil;
266 else
267 f->name = runemalloc(u.n);
268 bufread(delta, up, f->name, u.n);
269 f->nname = u.n;
270 break;
272 bufdelete(delta, up, delta->nc);
274 if(isundo)
275 f->seq = 0;
276 Return:
277 fbuffree(buf);
280 void
281 filereset(File *f)
283 bufreset(&f->delta);
284 bufreset(&f->epsilon);
285 f->seq = 0;
288 void
289 fileclose(File *f)
291 free(f->name);
292 f->nname = 0;
293 f->name = nil;
294 free(f->text);
295 f->ntext = 0;
296 f->text = nil;
297 bufclose(&f->b);
298 bufclose(&f->delta);
299 bufclose(&f->epsilon);
300 elogclose(f);
301 free(f);
304 void
305 filemark(File *f)
307 if(f->epsilon.nc)
308 bufdelete(&f->epsilon, 0, f->epsilon.nc);
309 f->seq = seq;