]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/acme/file.c
stats: show amount of reclaimable pages (add -r flag)
[plan9front.git] / sys / src / cmd / acme / file.c
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 }