9fans.net/go@v0.0.7/cmd/samterm/mesg.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "os" 8 "unicode/utf8" 9 10 "9fans.net/go/plumb" 11 ) 12 13 const HSIZE = 3 /* Type + short count */ 14 var h Header 15 var indata = make([]byte, 0, DATASIZE) 16 var outdata [DATASIZE]byte 17 var outcount int 18 var hversion int 19 var hostfd [2]*os.File 20 var exiting int 21 22 var rcv_state int = 0 23 var rcv_count int = 0 24 var rcv_errs int = 0 25 26 func rcv() { 27 if protodebug { 28 print("rcv in\n") 29 } 30 for c := rcvchar(); c >= 0; c = rcvchar() { 31 if protodebug { 32 print(".") 33 } 34 switch rcv_state { 35 case 0: 36 h.typ = Hmesg(c) 37 rcv_state++ 38 39 case 1: 40 h.count0 = byte(c) 41 rcv_state++ 42 43 case 2: 44 h.count1 = byte(c) 45 rcv_count = int(h.count0) | int(h.count1)<<8 46 if rcv_count > DATASIZE { 47 rcv_errs++ 48 if rcv_errs < 5 { 49 dumperrmsg(rcv_count, h.typ, int(h.count0), c) 50 rcv_state = 0 51 continue 52 } 53 fmt.Fprintf(os.Stderr, "type %d count %d\n", h.typ, rcv_count) 54 panic("count>DATASIZE") 55 } 56 indata = indata[:0] 57 if rcv_count == 0 { 58 inmesg(h.typ, 0) 59 rcv_count = 0 60 rcv_state = 0 61 continue 62 } 63 rcv_state++ 64 65 case 3: 66 indata = append(indata, byte(c)) 67 if len(indata) == rcv_count { 68 inmesg(h.typ, rcv_count) 69 rcv_count = 0 70 rcv_state = 0 71 continue 72 } 73 } 74 if protodebug { 75 print(":") 76 } 77 } 78 79 if protodebug { 80 print("rcv out\n") 81 } 82 } 83 84 func whichtext(tg int) *Text { 85 for i := range tag { 86 if tag[i] == tg { 87 return text[i] 88 } 89 } 90 println("TEXT") 91 for i := range tag { 92 println(tag[i], text[i], string(name[i])) 93 } 94 panic("whichtext") 95 // return nil 96 } 97 98 func inmesg(typ Hmesg, count int) { 99 m := inshort(0) 100 l := inlong(2) 101 switch typ { 102 case -1: 103 panic("rcv error") 104 // fallthrough 105 default: 106 fmt.Fprintf(os.Stderr, "type %d\n", typ) 107 panic("rcv unknown") 108 // fallthrough 109 110 case Hversion: 111 hversion = m 112 113 case Hbindname: 114 l := invlong(2) /* for 64-bit pointers */ 115 i := whichmenu(m) 116 if i < 0 { 117 break 118 } 119 /* in case of a race, a bindname may already have occurred */ 120 old := textByID[l] 121 t := whichtext(m) 122 if t == nil { 123 t = old 124 } else { /* let the old one win; clean up the new one */ 125 for old.nwin > 0 { 126 closeup(&old.l[old.front]) 127 } 128 } 129 text[i] = t 130 text[i].tag = m 131 132 case Hcurrent: 133 if whichmenu(m) < 0 { 134 break 135 } 136 t := whichtext(m) 137 isCmd := which != nil && which.text == &cmd && m != cmd.tag 138 if t == nil { 139 t = sweeptext(false, m) 140 if t == nil { 141 break 142 } 143 } 144 if t.l[t.front].textfn == nil { 145 panic("Hcurrent") 146 } 147 lp := &t.l[t.front] 148 if isCmd { 149 flupfront(lp) 150 flborder(lp, false) 151 work = lp 152 } else { 153 current(lp) 154 } 155 156 case Hmovname: 157 m := whichmenu(m) 158 if m < 0 { 159 break 160 } 161 t := text[m] 162 l := tag[m] 163 i := name[m][0] 164 text[m] = nil /* suppress panic in menudel */ 165 menudel(m) 166 if t == &cmd { 167 m = 0 168 } else { 169 if len(text) > 0 && text[0] == &cmd { 170 m = 1 171 } else { 172 m = 0 173 } 174 for ; m < len(name); m++ { 175 if bytes.Compare(indata[2:], name[m][1:]) < 0 { 176 break 177 } 178 } 179 } 180 menuins(m, indata[2:], t, i, int(l)) 181 182 case Hgrow: 183 if whichmenu(m) >= 0 { 184 hgrow(m, l, inlong(6), 1) 185 } 186 187 case Hnewname: 188 menuins(0, nil, nil, ' ', m) 189 190 case Hcheck0: 191 i := whichmenu(m) 192 if i >= 0 { 193 t := text[i] 194 if t != nil { 195 t.lock++ 196 } 197 outTs(Tcheck, m) 198 } 199 200 case Hcheck: 201 i := whichmenu(m) 202 if i >= 0 { 203 t := text[i] 204 if t != nil && t.lock != 0 { 205 t.lock-- 206 } 207 hcheck(m) 208 } 209 210 case Hunlock: 211 clrlock() 212 213 case Hdata: 214 if whichmenu(m) >= 0 { 215 l += hdata(m, l, indata[6:]) 216 } 217 goto Checkscroll 218 219 case Horigin: 220 if whichmenu(m) >= 0 { 221 horigin(m, l) 222 } 223 224 case Hunlockfile: 225 if whichmenu(m) >= 0 { 226 t := whichtext(m) 227 if t.lock != 0 { 228 t.lock-- 229 l = -1 230 goto Checkscroll 231 } 232 } 233 234 case Hsetdot: 235 if whichmenu(m) >= 0 { 236 hsetdot(m, l, inlong(6)) 237 } 238 239 case Hgrowdata: 240 if whichmenu(m) < 0 { 241 break 242 } 243 hgrow(m, l, inlong(6), 0) 244 whichtext(m).lock++ /* fake the request */ 245 l += hdata(m, l, indata[10:]) 246 goto Checkscroll 247 248 case Hmoveto: 249 if whichmenu(m) >= 0 { 250 hmoveto(m, l) 251 } 252 253 case Hclean: 254 m := whichmenu(m) 255 if m >= 0 { 256 name[m][0] = ' ' 257 } 258 259 case Hdirty: 260 m := whichmenu(m) 261 if m >= 0 { 262 name[m][0] = '\'' 263 } 264 265 case Hdelname: 266 m := whichmenu(m) 267 if m >= 0 { 268 menudel(m) 269 } 270 271 case Hcut: 272 if whichmenu(m) >= 0 { 273 hcut(m, l, inlong(6)) 274 } 275 276 case Hclose: 277 if whichmenu(m) < 0 { 278 break 279 } 280 t := whichtext(m) 281 if t == nil { 282 break 283 } 284 l := t.nwin 285 for i := 0; l > 0 && i < NL; i++ { 286 lp := &t.l[i] 287 if lp.textfn != nil { 288 closeup(lp) 289 l-- 290 } 291 } 292 293 case Hsetpat: 294 setpat(indata) 295 296 case Hsetsnarf: 297 hsetsnarf(m) 298 299 case Hsnarflen: 300 snarflen = inlong(0) 301 302 case Hack: 303 outT0(Tack) 304 305 case Hexit: 306 exiting = 1 307 outT0(Texit) 308 os.Exit(0) 309 310 case Hplumb: 311 hplumb(m) 312 } 313 return 314 315 Checkscroll: 316 if m == cmd.tag { 317 for i := 0; i < NL; i++ { 318 lp := &cmd.l[i] 319 if lp.textfn != nil { 320 p := int(l) 321 if p < 0 { 322 p = lp.p1 323 } 324 center(lp, p) 325 } 326 } 327 } 328 } 329 330 func setlock() { 331 hostlock++ 332 cursor = &lockarrow 333 display.SwitchCursor(cursor) 334 } 335 336 func clrlock() { 337 hasunlocked = true 338 if hostlock > 0 { 339 hostlock-- 340 } 341 if hostlock == 0 { 342 cursor = nil 343 display.SwitchCursor(cursor) 344 } 345 } 346 347 func startfile(t *Text) { 348 outTsv(Tstartfile, t.tag, t.id) /* for 64-bit pointers */ 349 setlock() 350 } 351 352 func startnewfile(typ Tmesg, t *Text) { 353 t.tag = Untagged 354 outTv(typ, t.id) /* for 64-bit pointers */ 355 } 356 357 func inshort(n int) int { 358 return int(binary.LittleEndian.Uint16(indata[n : n+2])) 359 } 360 361 func inlong(n int) int { 362 return int(binary.LittleEndian.Uint32(indata[n : n+4])) 363 } 364 365 func invlong(n int) int64 { 366 return int64(binary.LittleEndian.Uint64(indata[n : n+8])) 367 } 368 369 func outT0(typ Tmesg) { 370 outstart(typ) 371 outsend() 372 } 373 374 func outTl(typ Tmesg, l int) { 375 outstart(typ) 376 outlong(l) 377 outsend() 378 } 379 380 func outTs(typ Tmesg, s int) { 381 outstart(typ) 382 outshort(s) 383 outsend() 384 } 385 386 func outTss(typ Tmesg, s1 int, s2 int) { 387 outstart(typ) 388 outshort(s1) 389 outshort(s2) 390 outsend() 391 } 392 393 func outTsll(typ Tmesg, s1 int, l1 int, l2 int) { 394 outstart(typ) 395 outshort(s1) 396 outlong(l1) 397 outlong(l2) 398 outsend() 399 } 400 401 func outTsl(typ Tmesg, s1 int, l1 int) { 402 outstart(typ) 403 outshort(s1) 404 outlong(l1) 405 outsend() 406 } 407 408 func outTsv(typ Tmesg, s1 int, v1 int64) { 409 outstart(typ) 410 outshort(s1) 411 outvlong(v1) 412 outsend() 413 } 414 415 func outTv(typ Tmesg, v1 int64) { 416 outstart(typ) 417 outvlong(v1) 418 outsend() 419 } 420 421 func outTslS(typ Tmesg, s1 int, l1 int, s []rune) { 422 outstart(typ) 423 outshort(s1) 424 outlong(l1) 425 outrunes(s) 426 outsend() 427 } 428 429 func outTsls(typ Tmesg, s1 int, l1 int, s2 int) { 430 outstart(typ) 431 outshort(s1) 432 outlong(l1) 433 outshort(s2) 434 outsend() 435 } 436 437 func outstart(typ Tmesg) { 438 outdata[0] = byte(typ) 439 outcount = 0 440 } 441 442 func outrunes(s []rune) { 443 for _, r := range s { 444 outcount += utf8.EncodeRune(outdata[HSIZE+outcount:HSIZE+outcount+utf8.UTFMax], r) 445 } 446 } 447 448 func outshort(s int) { 449 binary.LittleEndian.PutUint16(outdata[HSIZE+outcount:HSIZE+outcount+2], uint16(s)) 450 outcount += 2 451 } 452 453 func outlong(l int) { 454 binary.LittleEndian.PutUint32(outdata[HSIZE+outcount:HSIZE+outcount+4], uint32(l)) 455 outcount += 4 456 } 457 458 func outvlong(v int64) { 459 binary.LittleEndian.PutUint64(outdata[HSIZE+outcount:HSIZE+outcount+8], uint64(v)) 460 outcount += 8 461 } 462 463 func outsend() { 464 if outcount > DATASIZE-HSIZE { 465 panic("outcount>sizeof outdata") 466 } 467 outdata[1] = uint8(outcount) 468 outdata[2] = uint8(outcount >> 8) 469 if n, err := hostfd[1].Write(outdata[:outcount+HSIZE]); n != int(outcount+HSIZE) { 470 panic("write error: " + err.Error()) 471 } 472 } 473 474 func hsetdot(m int, p0 int, p1 int) { 475 t := whichtext(m) 476 l := &t.l[t.front] 477 478 flushtyping(true) 479 flsetselect(l, p0, p1) 480 } 481 482 func horigin(m int, p0 int) { 483 t := whichtext(m) 484 l := &t.l[t.front] 485 if !flprepare(l) { 486 l.origin = p0 487 return 488 } 489 a := p0 - l.origin 490 if a >= 0 && a < l.f.NumChars { 491 l.f.Delete(0, a) 492 } else if a < 0 && -a < l.f.NumChars { 493 rp := rload(&t.rasp, p0, l.origin) 494 l.f.Insert(rp, 0) 495 } else { 496 l.f.Delete(0, l.f.NumChars) 497 } 498 l.origin = p0 499 scrdraw(l, t.rasp.nrunes) 500 if l.visible == Some { 501 flrefresh(l, l.entire, 0) 502 } 503 hcheck(m) 504 } 505 506 func hmoveto(m int, p0 int) { 507 t := whichtext(m) 508 l := &t.l[t.front] 509 510 if p0 < l.origin || p0-l.origin > l.f.NumChars*9/10 { 511 outTsll(Torigin, m, p0, 2) 512 } 513 } 514 515 func hcheck(m int) { 516 reqd := false 517 if m == Untagged { 518 return 519 } 520 t := whichtext(m) 521 if t == nil { /* possible in a half-built window */ 522 return 523 } 524 for i := 0; i < NL; i++ { 525 l := &t.l[i] 526 if l.textfn == nil || !flprepare(l) { 527 /* BUG: don't need this if BUG below is fixed */ 528 // TODO(rsc): What BUG? 529 continue 530 } 531 a := t.l[i].origin 532 n := rcontig(&t.rasp, a, a+l.f.NumChars, true) 533 if n < l.f.NumChars { /* text missing in middle of screen */ 534 a += n 535 } else { /* text missing at end of screen? */ 536 Again: 537 if l.f.LastLineFull { 538 goto Checksel /* all's well */ 539 } 540 a = t.l[i].origin + l.f.NumChars 541 n = t.rasp.nrunes - a 542 if n == 0 { 543 goto Checksel 544 } 545 if n > TBLOCKSIZE { 546 n = TBLOCKSIZE 547 } 548 n = rcontig(&t.rasp, a, a+n, true) 549 if n > 0 { 550 rp := rload(&t.rasp, a, a+n) 551 nl := l.f.NumChars 552 flinsert(l, rp, l.origin+nl) 553 if nl == l.f.NumChars { /* made no progress */ 554 goto Checksel 555 } 556 goto Again 557 } 558 } 559 if !reqd { 560 n = rcontig(&t.rasp, a, a+TBLOCKSIZE, false) 561 if n <= 0 { 562 panic("hcheck request==0") 563 } 564 outTsls(Trequest, m, a, int(n)) 565 outTs(Tcheck, m) 566 t.lock++ /* for the Trequest */ 567 t.lock++ /* for the Tcheck */ 568 reqd = true 569 } 570 Checksel: 571 flsetselect(l, l.p0, l.p1) 572 } 573 } 574 575 func flnewlyvisible(l *Flayer) { 576 hcheck(l.text.tag) 577 } 578 579 func hsetsnarf(nc int) { 580 display.SwitchCursor(&deadmouse) 581 osnarf := make([]byte, nc) 582 for i := range osnarf { 583 osnarf[i] = byte(getch()) 584 } 585 nsnarf := snarfswap(osnarf) 586 if nsnarf != nil { 587 if len(nsnarf) > SNARFSIZE { 588 nsnarf = []byte("<snarf too long>") 589 } 590 snarflen = len(nsnarf) 591 outTs(Tsetsnarf, len(nsnarf)) 592 if len(nsnarf) > 0 { 593 if n, err := hostfd[1].Write(nsnarf); n != len(nsnarf) { 594 panic("snarf write error: " + err.Error()) 595 } 596 } 597 } else { 598 outTs(Tsetsnarf, 0) 599 } 600 display.SwitchCursor(cursor) 601 } 602 603 func hplumb(nc int) { 604 s := make([]byte, nc) 605 for i := range s { 606 s[i] = byte(getch()) 607 } 608 if plumbfd != nil { 609 m := new(plumb.Message) 610 if err := m.Recv(bytes.NewReader(s)); err == nil { 611 m.Send(plumbfd) 612 } 613 } 614 } 615 616 func hgrow(m int, a int, new int, req int) { 617 if new <= 0 { 618 panic("hgrow") 619 } 620 t := whichtext(m) 621 rresize(&t.rasp, a, 0, new) 622 for i := 0; i < NL; i++ { 623 l := &t.l[i] 624 if l.textfn == nil { 625 continue 626 } 627 o := l.origin 628 b := a - o - rmissing(&t.rasp, o, a) 629 if a < o { 630 l.origin += new 631 } 632 if a < l.p0 { 633 l.p0 += new 634 } 635 if a < l.p1 { 636 l.p1 += new 637 } 638 /* must prevent b temporarily becoming unsigned */ 639 if req == 0 || a < o || (b > 0 && b > l.f.NumChars) || (l.f.NumChars == 0 && a-o > 0) { 640 continue 641 } 642 if new > TBLOCKSIZE { 643 new = TBLOCKSIZE 644 } 645 outTsls(Trequest, m, a, new) 646 t.lock++ 647 req = 0 648 } 649 } 650 651 func hdata1(t *Text, a int, rp []rune) int { 652 for i := 0; i < NL; i++ { 653 l := &t.l[i] 654 if l.textfn == nil { 655 continue 656 } 657 o := l.origin 658 b := a - o - rmissing(&t.rasp, o, a) 659 /* must prevent b temporarily becoming unsigned */ 660 if a < o || (b > 0 && b > l.f.NumChars) { 661 continue 662 } 663 flinsert(l, rp, o+b) 664 } 665 rdata(&t.rasp, a, a+len(rp), rp) 666 rclean(&t.rasp) 667 return len(rp) 668 } 669 670 func hdata(m int, a int, s []byte) int { 671 t := whichtext(m) 672 if t.lock != 0 { 673 t.lock-- 674 } 675 if len(s) == 0 { 676 return 0 677 } 678 r := []rune(string(s)) 679 return hdata1(t, a, r) 680 } 681 682 func hdatarune(m int, a int, rp []rune) int { 683 t := whichtext(m) 684 if t.lock != 0 { 685 t.lock-- 686 } 687 if len(rp) == 0 { 688 return 0 689 } 690 return hdata1(t, a, rp) 691 } 692 693 func hcut(m, a, old int) { 694 t := whichtext(m) 695 if t.lock != 0 { 696 t.lock-- 697 } 698 for i := 0; i < NL; i++ { 699 l := &t.l[i] 700 if l.textfn == nil { 701 continue 702 } 703 o := l.origin 704 b := a - o - rmissing(&t.rasp, o, a) 705 /* must prevent b temporarily becoming unsigned */ 706 if (b < 0 || b < l.f.NumChars) && a+old >= o { 707 p := o 708 if b >= 0 { 709 p += b 710 } 711 fldelete(l, p, a+old-rmissing(&t.rasp, o, a+old)) 712 } 713 if a+old < o { 714 l.origin -= old 715 } else if a <= o { 716 l.origin = a 717 } 718 if a+old < l.p0 { 719 l.p0 -= old 720 } else if a <= l.p0 { 721 l.p0 = a 722 } 723 if a+old < l.p1 { 724 l.p1 -= old 725 } else if a <= l.p1 { 726 l.p1 = a 727 } 728 } 729 rresize(&t.rasp, a, old, 0) 730 rclean(&t.rasp) 731 }