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 <libsec.h>
12 #include "dat.h"
13 #include "fns.h"
15 /*
16 * Structure of Undo list:
17 * The Undo structure follows any associated data, so the list
18 * can be read backwards: read the structure, then read whatever
19 * data is associated (insert string, file name) and precedes it.
20 * The structure includes the previous value of the modify bit
21 * and a sequence number; successive Undo structures with the
22 * same sequence number represent simultaneous changes.
23 */
25 typedef struct Undo Undo;
26 struct Undo
27 {
28 short type; /* Delete, Insert, Filename */
29 short mod; /* modify bit */
30 uint seq; /* sequence number */
31 uint p0; /* location of change (unused in f) */
32 uint n; /* # runes in string or file name */
33 };
35 enum
36 {
37 Undosize = sizeof(Undo)/sizeof(Rune)
38 };
40 File*
41 fileaddtext(File *f, Text *t)
42 {
43 if(f == nil){
44 f = emalloc(sizeof(File));
45 f->unread = TRUE;
46 }
47 f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
48 f->text[f->ntext++] = t;
49 f->curtext = t;
50 return f;
51 }
53 void
54 filedeltext(File *f, Text *t)
55 {
56 int i;
58 for(i=0; i<f->ntext; i++)
59 if(f->text[i] == t)
60 goto Found;
61 error("can't find text in filedeltext");
63 Found:
64 f->ntext--;
65 if(f->ntext == 0){
66 fileclose(f);
67 return;
68 }
69 memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
70 if(f->curtext == t)
71 f->curtext = f->text[0];
72 }
74 void
75 fileinsert(File *f, uint p0, Rune *s, uint ns)
76 {
77 if(p0 > f->b.nc)
78 error("internal error: fileinsert");
79 if(f->seq > 0)
80 fileuninsert(f, &f->delta, p0, ns);
81 bufinsert(&f->b, p0, s, ns);
82 if(ns)
83 f->mod = TRUE;
84 }
86 void
87 fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
88 {
89 Undo u;
91 /* undo an insertion by deleting */
92 u.type = Delete;
93 u.mod = f->mod;
94 u.seq = f->seq;
95 u.p0 = p0;
96 u.n = ns;
97 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
98 }
100 void
101 filedelete(File *f, uint p0, uint p1)
103 if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
104 error("internal error: filedelete");
105 if(f->seq > 0)
106 fileundelete(f, &f->delta, p0, p1);
107 bufdelete(&f->b, p0, p1);
108 if(p1 > p0)
109 f->mod = TRUE;
112 void
113 fileundelete(File *f, Buffer *delta, uint p0, uint p1)
115 Undo u;
116 Rune *buf;
117 uint i, n;
119 /* undo a deletion by inserting */
120 u.type = Insert;
121 u.mod = f->mod;
122 u.seq = f->seq;
123 u.p0 = p0;
124 u.n = p1-p0;
125 buf = fbufalloc();
126 for(i=p0; i<p1; i+=n){
127 n = p1 - i;
128 if(n > RBUFSIZE)
129 n = RBUFSIZE;
130 bufread(&f->b, i, buf, n);
131 bufinsert(delta, delta->nc, buf, n);
133 fbuffree(buf);
134 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
138 void
139 filesetname(File *f, Rune *name, int n)
141 if(f->seq > 0)
142 fileunsetname(f, &f->delta);
143 free(f->name);
144 f->name = runemalloc(n);
145 runemove(f->name, name, n);
146 f->nname = n;
147 f->unread = TRUE;
150 void
151 fileunsetname(File *f, Buffer *delta)
153 Undo u;
155 /* undo a file name change by restoring old name */
156 u.type = Filename;
157 u.mod = f->mod;
158 u.seq = f->seq;
159 u.p0 = 0; /* unused */
160 u.n = f->nname;
161 if(f->nname)
162 bufinsert(delta, delta->nc, f->name, f->nname);
163 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
166 uint
167 fileload(File *f, uint p0, int fd, int *nulls, DigestState *h)
169 if(f->seq > 0)
170 error("undo in file.load unimplemented");
171 return bufload(&f->b, p0, fd, nulls, h);
174 /* return sequence number of pending redo */
175 uint
176 fileredoseq(File *f)
178 Undo u;
179 Buffer *delta;
181 delta = &f->epsilon;
182 if(delta->nc == 0)
183 return 0;
184 bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize);
185 return u.seq;
188 void
189 fileundo(File *f, int isundo, uint *q0p, uint *q1p)
191 Undo u;
192 Rune *buf;
193 uint i, j, n, up;
194 uint stop;
195 Buffer *delta, *epsilon;
197 if(isundo){
198 /* undo; reverse delta onto epsilon, seq decreases */
199 delta = &f->delta;
200 epsilon = &f->epsilon;
201 stop = f->seq;
202 }else{
203 /* redo; reverse epsilon onto delta, seq increases */
204 delta = &f->epsilon;
205 epsilon = &f->delta;
206 stop = 0; /* don't know yet */
209 buf = fbufalloc();
210 while(delta->nc > 0){
211 up = delta->nc-Undosize;
212 bufread(delta, up, (Rune*)&u, Undosize);
213 if(isundo){
214 if(u.seq < stop){
215 f->seq = u.seq;
216 goto Return;
218 }else{
219 if(stop == 0)
220 stop = u.seq;
221 if(u.seq > stop)
222 goto Return;
224 switch(u.type){
225 default:
226 fprint(2, "undo: 0x%ux\n", u.type);
227 abort();
228 break;
230 case Delete:
231 f->seq = u.seq;
232 fileundelete(f, epsilon, u.p0, u.p0+u.n);
233 f->mod = u.mod;
234 bufdelete(&f->b, u.p0, u.p0+u.n);
235 for(j=0; j<f->ntext; j++)
236 textdelete(f->text[j], u.p0, u.p0+u.n, FALSE);
237 *q0p = u.p0;
238 *q1p = u.p0;
239 break;
241 case Insert:
242 f->seq = u.seq;
243 fileuninsert(f, epsilon, u.p0, u.n);
244 f->mod = u.mod;
245 up -= u.n;
246 for(i=0; i<u.n; i+=n){
247 n = u.n - i;
248 if(n > RBUFSIZE)
249 n = RBUFSIZE;
250 bufread(delta, up+i, buf, n);
251 bufinsert(&f->b, u.p0+i, buf, n);
252 for(j=0; j<f->ntext; j++)
253 textinsert(f->text[j], u.p0+i, buf, n, FALSE);
255 *q0p = u.p0;
256 *q1p = u.p0+u.n;
257 break;
259 case Filename:
260 f->seq = u.seq;
261 fileunsetname(f, epsilon);
262 f->mod = u.mod;
263 up -= u.n;
264 free(f->name);
265 if(u.n == 0)
266 f->name = nil;
267 else
268 f->name = runemalloc(u.n);
269 bufread(delta, up, f->name, u.n);
270 f->nname = u.n;
271 break;
273 bufdelete(delta, up, delta->nc);
275 if(isundo)
276 f->seq = 0;
277 Return:
278 fbuffree(buf);
281 void
282 filereset(File *f)
284 bufreset(&f->delta);
285 bufreset(&f->epsilon);
286 f->seq = 0;
289 void
290 fileclose(File *f)
292 free(f->name);
293 f->nname = 0;
294 f->name = nil;
295 free(f->text);
296 f->ntext = 0;
297 f->text = nil;
298 bufclose(&f->b);
299 bufclose(&f->delta);
300 bufclose(&f->epsilon);
301 elogclose(f);
302 free(f);
305 void
306 filemark(File *f)
308 if(f->epsilon.nc)
309 bufdelete(&f->epsilon, 0, f->epsilon.nc);
310 f->seq = seq;