xref: /plan9/sys/src/cmd/acme/file.c (revision ef9eff0badb330e9dfd6ba476ea333c24db47db4)
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"
13 
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  */
23 
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 };
33 
34 enum
35 {
36 	Undosize = sizeof(Undo)/sizeof(Rune),
37 };
38 
39 File*
fileaddtext(File * f,Text * t)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 }
51 
52 void
filedeltext(File * f,Text * t)53 filedeltext(File *f, Text *t)
54 {
55 	int i;
56 
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");
61 
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 }
72 
73 void
fileinsert(File * f,uint p0,Rune * s,uint ns)74 fileinsert(File *f, uint p0, Rune *s, uint ns)
75 {
76 	if(p0 > f->nc)
77 		error("internal error: fileinsert");
78 	if(f->seq > 0)
79 		fileuninsert(f, &f->delta, p0, ns);
80 	bufinsert(f, p0, s, ns);
81 	if(ns)
82 		f->mod = TRUE;
83 }
84 
85 void
fileuninsert(File * f,Buffer * delta,uint p0,uint ns)86 fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
87 {
88 	Undo u;
89 
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 }
98 
99 void
filedelete(File * f,uint p0,uint p1)100 filedelete(File *f, uint p0, uint p1)
101 {
102 	if(!(p0<=p1 && p0<=f->nc && p1<=f->nc))
103 		error("internal error: filedelete");
104 	if(f->seq > 0)
105 		fileundelete(f, &f->delta, p0, p1);
106 	bufdelete(f, p0, p1);
107 	if(p1 > p0)
108 		f->mod = TRUE;
109 }
110 
111 void
fileundelete(File * f,Buffer * delta,uint p0,uint p1)112 fileundelete(File *f, Buffer *delta, uint p0, uint p1)
113 {
114 	Undo u;
115 	Rune *buf;
116 	uint i, n;
117 
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, i, buf, n);
130 		bufinsert(delta, delta->nc, buf, n);
131 	}
132 	fbuffree(buf);
133 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
134 
135 }
136 
137 void
filesetname(File * f,Rune * name,int n)138 filesetname(File *f, Rune *name, int n)
139 {
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;
147 }
148 
149 void
fileunsetname(File * f,Buffer * delta)150 fileunsetname(File *f, Buffer *delta)
151 {
152 	Undo u;
153 
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);
163 }
164 
165 uint
fileload(File * f,uint p0,int fd,int * nulls)166 fileload(File *f, uint p0, int fd, int *nulls)
167 {
168 	if(f->seq > 0)
169 		error("undo in file.load unimplemented");
170 	return bufload(f, p0, fd, nulls);
171 }
172 
173 /* return sequence number of pending redo */
174 uint
fileredoseq(File * f)175 fileredoseq(File *f)
176 {
177 	Undo u;
178 	Buffer *delta;
179 
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;
185 }
186 
187 void
fileundo(File * f,int isundo,uint * q0p,uint * q1p)188 fileundo(File *f, int isundo, uint *q0p, uint *q1p)
189 {
190 	Undo u;
191 	Rune *buf;
192 	uint i, j, n, up;
193 	uint stop;
194 	Buffer *delta, *epsilon;
195 
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 */
206 	}
207 
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;
216 			}
217 		}else{
218 			if(stop == 0)
219 				stop = u.seq;
220 			if(u.seq > stop)
221 				goto Return;
222 		}
223 		switch(u.type){
224 		default:
225 			fprint(2, "undo: 0x%ux\n", u.type);
226 			abort();
227 			break;
228 
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, 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;
239 
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, u.p0+i, buf, n);
251 				for(j=0; j<f->ntext; j++)
252 					textinsert(f->text[j], u.p0+i, buf, n, FALSE);
253 			}
254 			*q0p = u.p0;
255 			*q1p = u.p0+u.n;
256 			break;
257 
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;
271 		}
272 		bufdelete(delta, up, delta->nc);
273 	}
274 	if(isundo)
275 		f->seq = 0;
276     Return:
277 	fbuffree(buf);
278 }
279 
280 void
filereset(File * f)281 filereset(File *f)
282 {
283 	bufreset(&f->delta);
284 	bufreset(&f->epsilon);
285 	f->seq = 0;
286 }
287 
288 void
fileclose(File * f)289 fileclose(File *f)
290 {
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);
298 	bufclose(&f->delta);
299 	bufclose(&f->epsilon);
300 	elogclose(f);
301 	free(f);
302 }
303 
304 void
filemark(File * f)305 filemark(File *f)
306 {
307 	if(f->epsilon.nc)
308 		bufdelete(&f->epsilon, 0, f->epsilon.nc);
309 	f->seq = seq;
310 }
311