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 } 311