9fans.net/go@v0.0.7/cmd/sam/file.go (about) 1 // #include "sam.h" 2 3 /* 4 * Structure of Undo list: 5 * The Undo structure follows any associated data, so the list 6 * can be read backwards: read the structure, then read whatever 7 * data is associated (insert string, file name) and precedes it. 8 * The structure includes the previous value of the modify bit 9 * and a sequence number; successive Undo structures with the 10 * same sequence number represent simultaneous changes. 11 */ 12 13 package main 14 15 import ( 16 "os" 17 "reflect" 18 "unsafe" 19 ) 20 21 type Undo struct { 22 type_ int 23 mod bool 24 seq int 25 p0 int 26 n int 27 } 28 29 type Merge struct { 30 f *File 31 seq int 32 p0 int 33 n int 34 nbuf int 35 buf [RBUFSIZE]rune 36 } 37 38 const ( 39 Maxmerge = 50 40 Undosize = int(unsafe.Sizeof(Undo{}) / unsafe.Sizeof(rune(0))) 41 ) 42 43 func undorunes(u *Undo) []rune { 44 var r []rune 45 h := (*reflect.SliceHeader)(unsafe.Pointer(&r)) 46 h.Data = uintptr(unsafe.Pointer(u)) 47 h.Len = Undosize 48 h.Cap = Undosize 49 return r 50 } 51 52 var merge Merge 53 54 func fileopen() *File { 55 f := new(File) 56 f.dot.f = f 57 f.ndot.f = f 58 f.seq = 0 59 f.mod = false 60 f.unread = true 61 Strinit0(&f.name) 62 return f 63 } 64 65 func fileisdirty(f *File) bool { 66 return f.seq != f.cleanseq 67 } 68 69 func wrinsert(delta *Buffer, seq int, mod bool, p0 int, s []rune) { 70 var u Undo 71 u.type_ = Insert 72 u.mod = mod 73 u.seq = seq 74 u.p0 = p0 75 u.n = len(s) 76 bufinsert(delta, delta.nc, s) 77 bufinsert(delta, delta.nc, undorunes(&u)) 78 } 79 80 func wrdelete(delta *Buffer, seq int, mod bool, p0 int, p1 int) { 81 var u Undo 82 u.type_ = Delete 83 u.mod = mod 84 u.seq = seq 85 u.p0 = p0 86 u.n = p1 - p0 87 bufinsert(delta, delta.nc, undorunes(&u)) 88 } 89 90 func flushmerge() { 91 f := merge.f 92 if f == nil { 93 return 94 } 95 if merge.seq != f.seq { 96 panic_("flushmerge seq mismatch") 97 } 98 if merge.n != 0 { 99 wrdelete(&f.epsilon, f.seq, true, merge.p0, merge.p0+merge.n) 100 } 101 if merge.nbuf != 0 { 102 wrinsert(&f.epsilon, f.seq, true, merge.p0+merge.n, merge.buf[:merge.nbuf]) 103 } 104 merge.f = nil 105 merge.n = 0 106 merge.nbuf = 0 107 } 108 109 func mergeextend(f *File, p0 int) { 110 mp0n := merge.p0 + merge.n 111 if mp0n != p0 { 112 bufread(&f.b, mp0n, merge.buf[merge.nbuf:merge.nbuf+p0-mp0n]) 113 merge.nbuf += p0 - mp0n 114 merge.n = p0 - merge.p0 115 } 116 } 117 118 /* 119 * like fileundelete, but get the data from arguments 120 */ 121 func loginsert(f *File, p0 int, s []rune) { 122 ns := len(s) 123 if f.rescuing != 0 { 124 return 125 } 126 if ns == 0 { 127 return 128 } 129 if ns > STRSIZE { 130 panic_("loginsert") 131 } 132 if f.seq < seq { 133 filemark(f) 134 } 135 if p0 < f.hiposn { 136 error_(Esequence) 137 } 138 139 if merge.f != f || p0-(merge.p0+merge.n) > Maxmerge || merge.nbuf+((p0+ns)-(merge.p0+merge.n)) >= RBUFSIZE { /* too far */ /* too long */ 140 flushmerge() 141 } 142 143 if ns >= RBUFSIZE { 144 if !(merge.n == 0 && merge.nbuf == 0) || !(merge.f == nil) { 145 panic_("loginsert bad merge state") 146 } 147 wrinsert(&f.epsilon, f.seq, true, p0, s) 148 } else { 149 if merge.f != f { 150 merge.f = f 151 merge.p0 = p0 152 merge.seq = f.seq 153 } 154 mergeextend(f, p0) 155 156 /* append string to merge */ 157 copy(merge.buf[merge.nbuf:], s) 158 merge.nbuf += ns 159 } 160 161 f.hiposn = p0 162 if !f.unread && !f.mod { 163 state(f, Dirty) 164 } 165 } 166 167 func logdelete(f *File, p0 int, p1 int) { 168 if f.rescuing != 0 { 169 return 170 } 171 if p0 == p1 { 172 return 173 } 174 if f.seq < seq { 175 filemark(f) 176 } 177 if p0 < f.hiposn { 178 error_(Esequence) 179 } 180 181 if merge.f != f || p0-(merge.p0+merge.n) > Maxmerge || merge.nbuf+(p0-(merge.p0+merge.n)) >= RBUFSIZE { /* too far */ /* too long */ 182 flushmerge() 183 merge.f = f 184 merge.p0 = p0 185 merge.seq = f.seq 186 } 187 188 mergeextend(f, p0) 189 190 /* add to deletion */ 191 merge.n = p1 - merge.p0 192 193 f.hiposn = p1 194 if !f.unread && !f.mod { 195 state(f, Dirty) 196 } 197 } 198 199 /* 200 * like fileunsetname, but get the data from arguments 201 */ 202 func logsetname(f *File, s *String) { 203 if f.rescuing != 0 { 204 return 205 } 206 207 if f.unread { /* This is setting initial file name */ 208 filesetname(f, s) 209 return 210 } 211 212 if f.seq < seq { 213 filemark(f) 214 } 215 216 /* undo a file name change by restoring old name */ 217 delta := &f.epsilon 218 var u Undo 219 u.type_ = Filename 220 u.mod = true 221 u.seq = f.seq 222 u.p0 = 0 /* unused */ 223 u.n = len(s.s) 224 if len(s.s) != 0 { 225 bufinsert(delta, delta.nc, s.s) 226 } 227 bufinsert(delta, delta.nc, undorunes(&u)) 228 if !f.unread && !f.mod { 229 state(f, Dirty) 230 } 231 } 232 233 func fileuninsert(f *File, delta *Buffer, p0 int, ns int) { 234 var u Undo 235 /* undo an insertion by deleting */ 236 u.type_ = Delete 237 u.mod = f.mod 238 u.seq = f.seq 239 u.p0 = p0 240 u.n = ns 241 bufinsert(delta, delta.nc, undorunes(&u)) 242 } 243 244 func fileundelete(f *File, delta *Buffer, p0 int, p1 int) { 245 var u Undo 246 /* undo a deletion by inserting */ 247 u.type_ = Insert 248 u.mod = f.mod 249 u.seq = f.seq 250 u.p0 = p0 251 u.n = p1 - p0 252 buf := fbufalloc() 253 var n int 254 for i := p0; i < p1; i += n { 255 n = p1 - i 256 if n > RBUFSIZE { 257 n = RBUFSIZE 258 } 259 bufread(&f.b, i, buf[:n]) 260 bufinsert(delta, delta.nc, buf[:n]) 261 } 262 fbuffree(buf) 263 bufinsert(delta, delta.nc, undorunes(&u)) 264 265 } 266 267 func filereadc(f *File, q int) rune { 268 if q < 0 || q >= f.b.nc { 269 return -1 270 } 271 var r [1]rune 272 bufread(&f.b, q, r[:]) 273 return r[0] 274 } 275 276 func filesetname(f *File, s *String) { 277 if !f.unread { 278 fileunsetname(f, &f.delta) 279 } 280 Strduplstr(&f.name, s) 281 sortname(f) 282 f.unread = true 283 } 284 285 func fileunsetname(f *File, delta *Buffer) { 286 var u Undo 287 /* undo a file name change by restoring old name */ 288 u.type_ = Filename 289 u.mod = f.mod 290 u.seq = f.seq 291 u.p0 = 0 /* unused */ 292 var s String 293 Strinit(&s) 294 Strduplstr(&s, &f.name) 295 fullname(&s) 296 u.n = len(s.s) 297 if len(s.s) != 0 { 298 bufinsert(delta, delta.nc, s.s) 299 } 300 bufinsert(delta, delta.nc, undorunes(&u)) 301 Strclose(&s) 302 } 303 304 func fileunsetdot(f *File, delta *Buffer, dot Range) { 305 var u Undo 306 u.type_ = Dot 307 u.mod = f.mod 308 u.seq = f.seq 309 u.p0 = dot.p1 310 u.n = dot.p2 - dot.p1 311 bufinsert(delta, delta.nc, undorunes(&u)) 312 } 313 314 func fileunsetmark(f *File, delta *Buffer, mark Range) { 315 var u Undo 316 u.type_ = Mark 317 u.mod = f.mod 318 u.seq = f.seq 319 u.p0 = mark.p1 320 u.n = mark.p2 - mark.p1 321 bufinsert(delta, delta.nc, undorunes(&u)) 322 } 323 324 func fileload(f *File, p0 int, fd *os.File, nulls *bool) int { 325 if f.seq > 0 { 326 panic_("undo in file.load unimplemented") 327 } 328 return bufload(&f.b, p0, fd, nulls) 329 } 330 331 func fileupdate(f *File, notrans, toterm bool) bool { 332 if f.rescuing != 0 { 333 return false 334 } 335 336 flushmerge() 337 338 /* 339 * fix the modification bit 340 * subtle point: don't save it away in the log. 341 * 342 * if another change is made, the correct f->mod 343 * state is saved in the undo log by filemark 344 * when setting the dot and mark. 345 * 346 * if the change is undone, the correct state is 347 * saved from f in the fileun... routines. 348 */ 349 mod := f.mod 350 f.mod = f.prevmod 351 if f == cmd { 352 notrans = true 353 } else { 354 fileunsetdot(f, &f.delta, f.prevdot) 355 fileunsetmark(f, &f.delta, f.prevmark) 356 } 357 f.dot = f.ndot 358 var p1 int 359 var p2 int 360 fileundo(f, false, !notrans, &p1, &p2, toterm) 361 f.mod = mod 362 363 if f.delta.nc == 0 { 364 f.seq = 0 365 } 366 367 if f == cmd { 368 return false 369 } 370 371 if f.mod { 372 f.closeok = false 373 quitok = false 374 } else { 375 f.closeok = true 376 } 377 return true 378 } 379 380 func prevseq(b *Buffer) int { 381 up := b.nc 382 if up == 0 { 383 return 0 384 } 385 up -= Undosize 386 var u Undo 387 bufread(b, up, undorunes(&u)) 388 return u.seq 389 } 390 391 func undoseq(f *File, isundo bool) int { 392 if isundo { 393 return f.seq 394 } 395 396 return prevseq(&f.epsilon) 397 } 398 399 func fileundo(f *File, isundo, canredo bool, q0p *int, q1p *int, flag bool) { 400 var stop int 401 var delta *Buffer 402 var epsilon *Buffer 403 if isundo { 404 /* undo; reverse delta onto epsilon, seq decreases */ 405 delta = &f.delta 406 epsilon = &f.epsilon 407 stop = f.seq 408 } else { 409 /* redo; reverse epsilon onto delta, seq increases */ 410 delta = &f.epsilon 411 epsilon = &f.delta 412 stop = 0 /* don't know yet */ 413 } 414 415 raspstart(f) 416 for delta.nc > 0 { 417 /* rasp and buffer are in sync; sync with wire if needed */ 418 if needoutflush() { 419 raspflush(f) 420 } 421 up := delta.nc - Undosize 422 var u Undo 423 bufread(delta, up, undorunes(&u)) 424 if isundo { 425 if u.seq < stop { 426 f.seq = u.seq 427 raspdone(f, flag) 428 return 429 } 430 } else { 431 if stop == 0 { 432 stop = u.seq 433 } 434 if u.seq > stop { 435 raspdone(f, flag) 436 return 437 } 438 } 439 switch u.type_ { 440 default: 441 panic_("undo unknown u.type") 442 443 case Delete: 444 f.seq = u.seq 445 if canredo { 446 fileundelete(f, epsilon, u.p0, u.p0+u.n) 447 } 448 f.mod = u.mod 449 bufdelete(&f.b, u.p0, u.p0+u.n) 450 raspdelete(f, u.p0, u.p0+u.n, flag) 451 *q0p = u.p0 452 *q1p = u.p0 453 454 case Insert: 455 f.seq = u.seq 456 if canredo { 457 fileuninsert(f, epsilon, u.p0, u.n) 458 } 459 f.mod = u.mod 460 up -= u.n 461 buf := fbufalloc() 462 var n int 463 for i := 0; i < u.n; i += n { 464 n = u.n - i 465 if n > RBUFSIZE { 466 n = RBUFSIZE 467 } 468 bufread(delta, up+i, buf[:n]) 469 bufinsert(&f.b, u.p0+i, buf[:n]) 470 raspinsert(f, u.p0+i, buf[:n], flag) 471 } 472 fbuffree(buf) 473 *q0p = u.p0 474 *q1p = u.p0 + u.n 475 476 case Filename: 477 f.seq = u.seq 478 if canredo { 479 fileunsetname(f, epsilon) 480 } 481 f.mod = u.mod 482 up -= u.n 483 484 Strinsure(&f.name, u.n) 485 bufread(delta, up, f.name.s) 486 fixname(&f.name) 487 sortname(f) 488 case Dot: 489 f.seq = u.seq 490 if canredo { 491 fileunsetdot(f, epsilon, f.dot.r) 492 } 493 f.mod = u.mod 494 f.dot.r.p1 = u.p0 495 f.dot.r.p2 = u.p0 + u.n 496 case Mark: 497 f.seq = u.seq 498 if canredo { 499 fileunsetmark(f, epsilon, f.mark) 500 } 501 f.mod = u.mod 502 f.mark.p1 = u.p0 503 f.mark.p2 = u.p0 + u.n 504 } 505 bufdelete(delta, up, delta.nc) 506 } 507 if isundo { 508 f.seq = 0 509 } 510 raspdone(f, flag) 511 } 512 513 func filereset(f *File) { 514 bufreset(&f.delta) 515 bufreset(&f.epsilon) 516 f.seq = 0 517 } 518 519 func fileclose(f *File) { 520 Strclose(&f.name) 521 bufclose(&f.b) 522 bufclose(&f.delta) 523 bufclose(&f.epsilon) 524 if f.rasp != nil { 525 // listfree(f.rasp) 526 } 527 // free(f) 528 } 529 530 func filemark(f *File) { 531 532 if f.unread { 533 return 534 } 535 if f.epsilon.nc != 0 { 536 bufdelete(&f.epsilon, 0, f.epsilon.nc) 537 } 538 539 if f != cmd { 540 f.prevdot = f.dot.r 541 f.prevmark = f.mark 542 f.prevseq = f.seq 543 f.prevmod = f.mod 544 } 545 546 f.ndot = f.dot 547 f.seq = seq 548 f.hiposn = 0 549 }