1implement Rowm; 2 3include "common.m"; 4 5sys : Sys; 6bufio : Bufio; 7utils : Utils; 8drawm : Draw; 9acme : Acme; 10graph : Graph; 11gui : Gui; 12dat : Dat; 13bufferm : Bufferm; 14textm : Textm; 15filem : Filem; 16windowm : Windowm; 17columnm : Columnm; 18exec : Exec; 19look : Look; 20edit : Edit; 21ecmd : Editcmd; 22 23ALLLOOPER, ALLTOFILE, ALLMATCHFILE, ALLFILECHECK, ALLELOGTERM, ALLEDITINIT, ALLUPDATE: import Edit; 24sprint : import sys; 25FALSE, TRUE, XXX : import Dat; 26Border, BUFSIZE, Astring : import Dat; 27Reffont, reffont, Lock, Ref : import dat; 28row, home, mouse : import dat; 29fontnames : import acme; 30font, draw : import graph; 31Point, Rect, Image : import drawm; 32min, max, abs, error, warning, clearmouse, stralloc, strfree : import utils; 33black, white, mainwin : import gui; 34Buffer : import bufferm; 35Tag, Rowtag, Text : import textm; 36Window : import windowm; 37File : import filem; 38Column : import columnm; 39Iobuf : import bufio; 40 41init(mods : ref Dat->Mods) 42{ 43 sys = mods.sys; 44 bufio = mods.bufio; 45 dat = mods.dat; 46 utils = mods.utils; 47 drawm = mods.draw; 48 acme = mods.acme; 49 graph = mods.graph; 50 gui = mods.gui; 51 bufferm = mods.bufferm; 52 textm = mods.textm; 53 filem = mods.filem; 54 windowm = mods.windowm; 55 columnm = mods.columnm; 56 exec = mods.exec; 57 look = mods.look; 58 edit = mods.edit; 59 ecmd = mods.editcmd; 60} 61 62newrow() : ref Row 63{ 64 r := ref Row; 65 r.qlock = Lock.init(); 66 r.r = ((0, 0), (0, 0)); 67 r.tag = nil; 68 r.col = nil; 69 r.ncol = 0; 70 return r; 71} 72 73Row.init(row : self ref Row, r : Rect) 74{ 75 r1 : Rect; 76 t : ref Text; 77 dummy : ref File = nil; 78 79 draw(mainwin, r, white, nil, (0, 0)); 80 row.r = r; 81 row.col = nil; 82 row.ncol = 0; 83 r1 = r; 84 r1.max.y = r1.min.y + font.height; 85 row.tag = textm->newtext(); 86 t = row.tag; 87 t.init(dummy.addtext(t), r1, Reffont.get(FALSE, FALSE, FALSE, nil), acme->tagcols); 88 t.what = Rowtag; 89 t.row = row; 90 t.w = nil; 91 t.col = nil; 92 r1.min.y = r1.max.y; 93 r1.max.y += Border; 94 draw(mainwin, r1, black, nil, (0, 0)); 95 t.insert(0, "Newcol Kill Putall Dump Exit ", 29, TRUE, 0); 96 t.setselect(t.file.buf.nc, t.file.buf.nc); 97} 98 99Row.add(row : self ref Row, c : ref Column, x : int) : ref Column 100{ 101 r, r1 : Rect; 102 d : ref Column; 103 i : int; 104 105 d = nil; 106 r = row.r; 107 r.min.y = row.tag.frame.r.max.y+Border; 108 if(x<r.min.x && row.ncol>0){ #steal 40% of last column by default 109 d = row.col[row.ncol-1]; 110 x = d.r.min.x + 3*d.r.dx()/5; 111 } 112 # look for column we'll land on 113 for(i=0; i<row.ncol; i++){ 114 d = row.col[i]; 115 if(x < d.r.max.x) 116 break; 117 } 118 if(row.ncol > 0){ 119 if(i < row.ncol) 120 i++; # new column will go after d 121 r = d.r; 122 if(r.dx() < 100) 123 return nil; 124 draw(mainwin, r, white, nil, (0, 0)); 125 r1 = r; 126 r1.max.x = min(x, r.max.x-50); 127 if(r1.dx() < 50) 128 r1.max.x = r1.min.x+50; 129 d.reshape(r1); 130 r1.min.x = r1.max.x; 131 r1.max.x = r1.min.x+Border; 132 draw(mainwin, r1, black, nil, (0, 0)); 133 r.min.x = r1.max.x; 134 } 135 if(c == nil){ 136 c = ref Column; 137 c.init(r); 138 reffont.r.inc(); 139 }else 140 c.reshape(r); 141 c.row = row; 142 c.tag.row = row; 143 orc := row.col; 144 row.col = array[row.ncol+1] of ref Column; 145 row.col[0:] = orc[0:i]; 146 row.col[i+1:] = orc[i:row.ncol]; 147 orc = nil; 148 row.col[i] = c; 149 row.ncol++; 150 clearmouse(); 151 return c; 152} 153 154Row.reshape(row : self ref Row, r : Rect) 155{ 156 i, dx, odx : int; 157 r1, r2 : Rect; 158 c : ref Column; 159 160 dx = r.dx(); 161 odx = row.r.dx(); 162 row.r = r; 163 r1 = r; 164 r1.max.y = r1.min.y + font.height; 165 row.tag.reshape(r1); 166 r1.min.y = r1.max.y; 167 r1.max.y += Border; 168 draw(mainwin, r1, black, nil, (0, 0)); 169 r.min.y = r1.max.y; 170 r1 = r; 171 r1.max.x = r1.min.x; 172 for(i=0; i<row.ncol; i++){ 173 c = row.col[i]; 174 r1.min.x = r1.max.x; 175 if(i == row.ncol-1) 176 r1.max.x = r.max.x; 177 else 178 r1.max.x = r1.min.x+c.r.dx()*dx/odx; 179 r2 = r1; 180 r2.max.x = r2.min.x+Border; 181 draw(mainwin, r2, black, nil, (0, 0)); 182 r1.min.x = r2.max.x; 183 c.reshape(r1); 184 } 185} 186 187Row.dragcol(row : self ref Row, c : ref Column) 188{ 189 r : Rect; 190 i, b, x : int; 191 p, op : Point; 192 d : ref Column; 193 194 clearmouse(); 195 graph->cursorswitch(dat->boxcursor); 196 b = mouse.buttons; 197 op = mouse.xy; 198 while(mouse.buttons == b) 199 acme->frgetmouse(); 200 graph->cursorswitch(dat->arrowcursor); 201 if(mouse.buttons){ 202 while(mouse.buttons) 203 acme->frgetmouse(); 204 return; 205 } 206 207 for(i=0; i<row.ncol; i++) 208 if(row.col[i] == c) 209 break; 210 if (i == row.ncol) 211 error("can't find column"); 212 213 if(i == 0) 214 return; 215 p = mouse.xy; 216 if((abs(p.x-op.x)<5 && abs(p.y-op.y)<5)) 217 return; 218 if((i>0 && p.x<row.col[i-1].r.min.x) || (i<row.ncol-1 && p.x>c.r.max.x)){ 219 # shuffle 220 x = c.r.min.x; 221 row.close(c, FALSE); 222 if(row.add(c, p.x) == nil) # whoops! 223 if(row.add(c, x) == nil) # WHOOPS! 224 if(row.add(c, -1)==nil){ # shit! 225 row.close(c, TRUE); 226 return; 227 } 228 c.mousebut(); 229 return; 230 } 231 d = row.col[i-1]; 232 if(p.x < d.r.min.x+80+Dat->Scrollwid) 233 p.x = d.r.min.x+80+Dat->Scrollwid; 234 if(p.x > c.r.max.x-80-Dat->Scrollwid) 235 p.x = c.r.max.x-80-Dat->Scrollwid; 236 r = d.r; 237 r.max.x = c.r.max.x; 238 draw(mainwin, r, white, nil, (0, 0)); 239 r.max.x = p.x; 240 d.reshape(r); 241 r = c.r; 242 r.min.x = p.x; 243 r.max.x = r.min.x; 244 r.max.x += Border; 245 draw(mainwin, r, black, nil, (0, 0)); 246 r.min.x = r.max.x; 247 r.max.x = c.r.max.x; 248 c.reshape(r); 249 c.mousebut(); 250} 251 252Row.close(row : self ref Row, c : ref Column, dofree : int) 253{ 254 r : Rect; 255 i : int; 256 257 for(i=0; i<row.ncol; i++) 258 if(row.col[i] == c) 259 break; 260 if (i == row.ncol) 261 error("can't find column"); 262 263 r = c.r; 264 if(dofree) 265 c.closeall(); 266 orc := row.col; 267 row.col = array[row.ncol-1] of ref Column; 268 row.col[0:] = orc[0:i]; 269 row.col[i:] = orc[i+1:row.ncol]; 270 orc = nil; 271 row.ncol--; 272 if(row.ncol == 0){ 273 draw(mainwin, r, white, nil, (0, 0)); 274 return; 275 } 276 if(i == row.ncol){ # extend last column right 277 c = row.col[i-1]; 278 r.min.x = c.r.min.x; 279 r.max.x = row.r.max.x; 280 }else{ # extend next window left 281 c = row.col[i]; 282 r.max.x = c.r.max.x; 283 } 284 draw(mainwin, r, white, nil, (0, 0)); 285 c.reshape(r); 286} 287 288Row.whichcol(row : self ref Row, p : Point) : ref Column 289{ 290 i : int; 291 c : ref Column; 292 293 for(i=0; i<row.ncol; i++){ 294 c = row.col[i]; 295 if(p.in(c.r)) 296 return c; 297 } 298 return nil; 299} 300 301Row.which(row : self ref Row, p : Point) : ref Text 302{ 303 c : ref Column; 304 305 if(p.in(row.tag.all)) 306 return row.tag; 307 c = row.whichcol(p); 308 if(c != nil) 309 return c.which(p); 310 return nil; 311} 312 313Row.typex(row : self ref Row, r : int, p : Point) : ref Text 314{ 315 w : ref Window; 316 t : ref Text; 317 318 clearmouse(); 319 row.qlock.lock(); 320 if(dat->bartflag) 321 t = dat->barttext; 322 else 323 t = row.which(p); 324 if(t!=nil && !(t.what==Tag && p.in(t.scrollr))){ 325 w = t.w; 326 if(w == nil) 327 t.typex(r, 0); 328 else{ 329 w.lock('K'); 330 w.typex(t, r); 331 w.unlock(); 332 } 333 } 334 row.qlock.unlock(); 335 return t; 336} 337 338Row.clean(row : self ref Row, exiting : int) : int 339{ 340 clean : int; 341 i : int; 342 343 clean = TRUE; 344 for(i=0; i<row.ncol; i++) 345 clean &= row.col[i].clean(exiting); 346 return clean; 347} 348 349Row.dump(row : self ref Row, file : string) 350{ 351 i, j, m, n, dumped : int; 352 q0, q1 : int; 353 b : ref Iobuf; 354 buf, fontname, a : string; 355 r : ref Astring; 356 c : ref Column; 357 w, w1 : ref Window; 358 t : ref Text; 359 360 if(row.ncol == 0) 361 return; 362 363 { 364 if(file == nil){ 365 if(home == nil){ 366 warning(nil, "can't find file for dump: $home not defined\n"); 367 raise "e"; 368 } 369 buf = sprint("%s/acme.dump", home); 370 file = buf; 371 } 372 b = bufio->create(file, Bufio->OWRITE, 8r600); 373 if(b == nil){ 374 warning(nil, sprint("can't open %s: %r\n", file)); 375 raise "e"; 376 } 377 r = stralloc(BUFSIZE); 378 b.puts(acme->wdir); b.putc('\n'); 379 b.puts(fontnames[0]); b.putc('\n'); 380 b.puts(fontnames[1]); b.putc('\n'); 381 for(i=0; i<row.ncol; i++){ 382 c = row.col[i]; 383 b.puts(sprint("%11d", 100*(c.r.min.x-row.r.min.x)/row.r.dx())); 384 if(i == row.ncol-1) 385 b.putc('\n'); 386 else 387 b.putc(' '); 388 } 389 for(i=0; i<row.ncol; i++){ 390 c = row.col[i]; 391 for(j=0; j<c.nw; j++) 392 c.w[j].body.file.dumpid = 0; 393 } 394 for(i=0; i<row.ncol; i++){ 395 c = row.col[i]; 396 for(j=0; j<c.nw; j++){ 397 w = c.w[j]; 398 w.commit(w.tag); 399 t = w.body; 400 # windows owned by others get special treatment 401 if(w.nopen[Dat->QWevent] > byte 0) 402 if(w.dumpstr == nil) 403 continue; 404 # zeroxes of external windows are tossed 405 if(t.file.ntext > 1) 406 for(n=0; n<t.file.ntext; n++){ 407 w1 = t.file.text[n].w; 408 if(w == w1) 409 continue; 410 if(w1.nopen[Dat->QWevent] != byte 0) { 411 j = c.nw; 412 continue; 413 } 414 } 415 fontname = ""; 416 if(t.reffont.f != font) 417 fontname = t.reffont.f.name; 418 a = t.file.name; 419 if(t.file.dumpid){ 420 dumped = FALSE; 421 b.puts(sprint("x%11d %11d %11d %11d %11d %s\n", i, t.file.dumpid, 422 w.body.q0, w.body.q1, 423 100*(w.r.min.y-c.r.min.y)/c.r.dy(), 424 fontname)); 425 }else if(w.dumpstr != nil){ 426 dumped = FALSE; 427 b.puts(sprint("e%11d %11d %11d %11d %11d %s\n", i, t.file.dumpid, 428 0, 0, 429 100*(w.r.min.y-c.r.min.y)/c.r.dy(), 430 fontname)); 431 }else if(len a == 0){ # don't save unnamed windows 432 continue; 433 }else if((!w.dirty && utils->access(a)==0) || w.isdir){ 434 dumped = FALSE; 435 t.file.dumpid = w.id; 436 b.puts(sprint("f%11d %11d %11d %11d %11d %s\n", i, w.id, 437 w.body.q0, w.body.q1, 438 100*(w.r.min.y-c.r.min.y)/c.r.dy(), 439 fontname)); 440 }else{ 441 dumped = TRUE; 442 t.file.dumpid = w.id; 443 b.puts(sprint("F%11d %11d %11d %11d %11d %11d %s\n", i, j, 444 w.body.q0, w.body.q1, 445 100*(w.r.min.y-c.r.min.y)/c.r.dy(), 446 w.body.file.buf.nc, fontname)); 447 } 448 a = nil; 449 buf = w.ctlprint(0); 450 b.puts(buf); 451 m = min(BUFSIZE, w.tag.file.buf.nc); 452 w.tag.file.buf.read(0, r, 0, m); 453 n = 0; 454 while(n<m && r.s[n]!='\n') 455 n++; 456 r.s[n++] = '\n'; 457 b.puts(r.s[0:n]); 458 if(dumped){ 459 q0 = 0; 460 q1 = t.file.buf.nc; 461 while(q0 < q1){ 462 n = q1 - q0; 463 if(n > Dat->BUFSIZE) 464 n = Dat->BUFSIZE; 465 t.file.buf.read(q0, r, 0, n); 466 b.puts(r.s[0:n]); 467 q0 += n; 468 } 469 } 470 if(w.dumpstr != nil){ 471 if(w.dumpdir != nil) 472 b.puts(sprint("%s\n%s\n", w.dumpdir, w.dumpstr)); 473 else 474 b.puts(sprint("\n%s\n", w.dumpstr)); 475 } 476 } 477 } 478 b.close(); 479 b = nil; 480 strfree(r); 481 r = nil; 482 } 483 exception{ 484 * => 485 return; 486 } 487} 488 489rdline(b : ref Iobuf, line : int) : (int, string) 490{ 491 l : string; 492 493 l = b.gets('\n'); 494 if(l != nil) 495 line++; 496 return (line, l); 497} 498 499Row.loadx(row : self ref Row, file : string, initing : int) 500{ 501 i, j, line, percent, y, nr, nfontr, n, ns, ndumped, dumpid, x : int; 502 b, bout : ref Iobuf; 503 fontname : string; 504 l, buf, t : string; 505 rune : int; 506 r, fontr : string; 507 c, c1, c2 : ref Column; 508 q0, q1 : int; 509 r1, r2 : Rect; 510 w : ref Window; 511 512 { 513 if(file == nil){ 514 if(home == nil){ 515 warning(nil, "can't find file for load: $home not defined\n"); 516 raise "e"; 517 } 518 buf = sprint("%s/acme.dump", home); 519 file = buf; 520 } 521 b = bufio->open(file, Bufio->OREAD); 522 if(b == nil){ 523 warning(nil, sprint("can't open load file %s: %r\n", file)); 524 raise "e"; 525 } 526 527 { 528 # current directory 529 (line, l) = rdline(b, 0); 530 if(l == nil) 531 raise "e"; 532 l = l[0:len l - 1]; 533 if(sys->chdir(l) < 0){ 534 warning(nil, sprint("can't chdir %s\n", l)); 535 b.close(); 536 return; 537 } 538 # global fonts 539 for(i=0; i<2; i++){ 540 (line, l) = rdline(b, line); 541 if(l == nil) 542 raise "e"; 543 l = l[0:len l -1]; 544 if(l != nil && l != fontnames[i]) 545 Reffont.get(i, TRUE, i==0 && initing, l); 546 } 547 if(initing && row.ncol==0) 548 row.init(mainwin.clipr); 549 (line, l) = rdline(b, line); 550 if(l == nil) 551 raise "e"; 552 j = len l/12; 553 if(j<=0 || j>10) 554 raise "e"; 555 for(i=0; i<j; i++){ 556 percent = int l[12*i:12*i+11]; 557 if(percent<0 || percent>=100) 558 raise "e"; 559 x = row.r.min.x+percent*row.r.dx()/100; 560 if(i < row.ncol){ 561 if(i == 0) 562 continue; 563 c1 = row.col[i-1]; 564 c2 = row.col[i]; 565 r1 = c1.r; 566 r2 = c2.r; 567 r1.max.x = x; 568 r2.min.x = x+Border; 569 if(r1.dx() < 50 || r2.dx() < 50) 570 continue; 571 draw(mainwin, (r1.min, r2.max), white, nil, (0, 0)); 572 c1.reshape(r1); 573 c2.reshape(r2); 574 r2.min.x = x; 575 r2.max.x = x+Border; 576 draw(mainwin, r2, black, nil, (0, 0)); 577 } 578 if(i >= row.ncol) 579 row.add(nil, x); 580 } 581 for(;;){ 582 (line, l) = rdline(b, line); 583 if(l == nil) 584 break; 585 dumpid = 0; 586 case(l[0]){ 587 'e' => 588 if(len l < 1+5*12+1) 589 raise "e"; 590 (line, l) = rdline(b, line); # ctl line; ignored 591 if(l == nil) 592 raise "e"; 593 (line, l) = rdline(b, line); # directory 594 if(l == nil) 595 raise "e"; 596 l = l[0:len l -1]; 597 if(len l != 0) 598 r = l; 599 else{ 600 if(home == nil) 601 r = "./"; 602 else 603 r = home+"/"; 604 } 605 nr = len r; 606 (line, l) = rdline(b, line); # command 607 if(l == nil) 608 raise "e"; 609 t = l[0:len l -1]; 610 spawn exec->run(nil, t, r, nr, TRUE, nil, nil, FALSE); 611 # r is freed in run() 612 continue; 613 'f' => 614 if(len l < 1+5*12+1) 615 raise "e"; 616 fontname = l[1+5*12:len l - 1]; 617 ndumped = -1; 618 'F' => 619 if(len l < 1+6*12+1) 620 raise "e"; 621 fontname = l[1+6*12:len l - 1]; 622 ndumped = int l[1+5*12:1+5*12+11]; 623 'x' => 624 if(len l < 1+5*12+1) 625 raise "e"; 626 fontname = l[1+5*12: len l - 1]; 627 ndumped = -1; 628 dumpid = int l[1+1*12:1+1*12+11]; 629 * => 630 raise "e"; 631 } 632 l = l[0:len l -1]; 633 if(len fontname != 0) { 634 fontr = fontname; 635 nfontr = len fontname; 636 } 637 else 638 (fontr, nfontr) = (nil, 0); 639 i = int l[1+0*12:1+0*12+11]; 640 j = int l[1+1*12:1+1*12+11]; 641 q0 = int l[1+2*12:1+2*12+11]; 642 q1 = int l[1+3*12:1+3*12+11]; 643 percent = int l[1+4*12:1+4*12+11]; 644 if(i<0 || i>10) 645 raise "e"; 646 if(i > row.ncol) 647 i = row.ncol; 648 c = row.col[i]; 649 y = c.r.min.y+(percent*c.r.dy())/100; 650 if(y<c.r.min.y || y>=c.r.max.y) 651 y = -1; 652 if(dumpid == 0) 653 w = c.add(nil, nil, y); 654 else 655 w = c.add(nil, look->lookid(dumpid, TRUE), y); 656 if(w == nil) 657 continue; 658 w.dumpid = j; 659 (line, l) = rdline(b, line); 660 if(l == nil) 661 raise "e"; 662 l = l[0:len l - 1]; 663 r = l[5*12:len l]; 664 nr = len r; 665 ns = -1; 666 for(n=0; n<nr; n++){ 667 if(r[n] == '/') 668 ns = n; 669 if(r[n] == ' ') 670 break; 671 } 672 if(dumpid == 0) 673 w.setname(r, n); 674 for(; n<nr; n++) 675 if(r[n] == '|') 676 break; 677 w.cleartag(); 678 w.tag.insert(w.tag.file.buf.nc, r[n+1:len r], nr-(n+1), TRUE, 0); 679 if(ndumped >= 0){ 680 # simplest thing is to put it in a file and load that 681 buf = sprint("/tmp/d%d.%.4sacme", sys->pctl(0, nil), utils->getuser()); 682 bout = bufio->create(buf, Bufio->OWRITE, 8r600); 683 if(bout == nil){ 684 warning(nil, "can't create temp file: %r\n"); 685 b.close(); 686 return; 687 } 688 for(n=0; n<ndumped; n++){ 689 rune = b.getc(); 690 if(rune == '\n') 691 line++; 692 if(rune == Bufio->EOF){ 693 bout.close(); 694 bout = nil; 695 raise "e"; 696 } 697 bout.putc(rune); 698 } 699 bout.close(); 700 bout = nil; 701 w.body.loadx(0, buf, 1); 702 w.body.file.mod = TRUE; 703 for(n=0; n<w.body.file.ntext; n++) 704 w.body.file.text[n].w.dirty = TRUE; 705 w.settag(); 706 sys->remove(buf); 707 buf = nil; 708 }else if(dumpid==0 && r[ns+1]!='+' && r[ns+1]!='-') 709 exec->get(w.body, nil, nil, FALSE, nil, 0); 710 l = r = nil; 711 if(fontr != nil){ 712 exec->fontx(w.body, nil, nil, fontr, nfontr); 713 fontr = nil; 714 } 715 if(q0>w.body.file.buf.nc || q1>w.body.file.buf.nc || q0>q1) 716 q0 = q1 = 0; 717 w.body.show(q0, q1, TRUE); 718 w.maxlines = min(w.body.frame.nlines, max(w.maxlines, w.body.frame.maxlines)); 719 } 720 b.close(); 721 } 722 exception{ 723 * => 724 warning(nil, sprint("bad load file %s:%d\n", file, line)); 725 b.close(); 726 raise "e"; 727 } 728 } 729 exception{ 730 * => 731 return; 732 } 733} 734 735allwindows(o: int, aw: ref Dat->Allwin) 736{ 737 for(i:=0; i<row.ncol; i++){ 738 c := row.col[i]; 739 for(j:=0; j<c.nw; j++){ 740 w := c.w[j]; 741 case (o){ 742 ALLLOOPER => 743 pick k := aw{ 744 LP => ecmd->alllooper(w, k.lp); 745 } 746 ALLTOFILE => 747 pick k := aw{ 748 FF => ecmd->alltofile(w, k.ff); 749 } 750 ALLMATCHFILE => 751 pick k := aw{ 752 FF => ecmd->allmatchfile(w, k.ff); 753 } 754 ALLFILECHECK => 755 pick k := aw{ 756 FC => ecmd->allfilecheck(w, k.fc); 757 } 758 ALLELOGTERM => 759 edit->allelogterm(w); 760 ALLEDITINIT => 761 edit->alleditinit(w); 762 ALLUPDATE => 763 edit->allupdate(w); 764 } 765 } 766 } 767}