Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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*
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
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
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
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
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
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
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
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
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
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
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
281
filereset(File *f)
282
{
283
	bufreset(&f->delta);
284
	bufreset(&f->epsilon);
285
	f->seq = 0;
286
}
287
 
288
void
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
305
filemark(File *f)
306
{
307
	if(f->epsilon.nc)
308
		bufdelete(&f->epsilon, 0, f->epsilon.nc);
309
	f->seq = seq;
310
}