]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/acme/rows.c
stats: show amount of reclaimable pages (add -r flag)
[plan9front.git] / sys / src / cmd / acme / rows.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 <bio.h>
11 #include <plumb.h>
12 #include "dat.h"
13 #include "fns.h"
14
15 void
16 rowinit(Row *row, Rectangle r)
17 {
18         Rectangle r1;
19         Text *t;
20
21         draw(screen, r, display->white, nil, ZP);
22         row->r = r;
23         row->col = nil;
24         row->ncol = 0;
25         r1 = r;
26         r1.max.y = r1.min.y + font->height;
27         t = &row->tag;
28         textinit(t, fileaddtext(nil, t), r1, rfget(FALSE, FALSE, FALSE, nil), tagcols);
29         t->what = Rowtag;
30         t->row = row;
31         t->w = nil;
32         t->col = nil;
33         r1.min.y = r1.max.y;
34         r1.max.y += Border;
35         draw(screen, r1, display->black, nil, ZP);
36         textinsert(t, 0, L"Newcol Kill Putall Dump Exit ", 29, TRUE);
37         textsetselect(t, t->file->nc, t->file->nc);
38 }
39
40 Column*
41 rowadd(Row *row, Column *c, int x)
42 {
43         Rectangle r, r1;
44         Column *d;
45         int i;
46
47         d = nil;
48         r = row->r;
49         r.min.y = row->tag.r.max.y+Border;
50         if(x<r.min.x && row->ncol>0){   /*steal 40% of last column by default */
51                 d = row->col[row->ncol-1];
52                 x = d->r.min.x + 3*Dx(d->r)/5;
53         }
54         /* look for column we'll land on */
55         for(i=0; i<row->ncol; i++){
56                 d = row->col[i];
57                 if(x < d->r.max.x)
58                         break;
59         }
60         if(row->ncol > 0){
61                 if(i < row->ncol)
62                         i++;    /* new column will go after d */
63                 r = d->r;
64                 if(Dx(r) < 100)
65                         return nil;
66                 draw(screen, r, display->white, nil, ZP);
67                 r1 = r;
68                 r1.max.x = min(x, r.max.x-50);
69                 if(Dx(r1) < 50)
70                         r1.max.x = r1.min.x+50;
71                 colresize(d, r1);
72                 r1.min.x = r1.max.x;
73                 r1.max.x = r1.min.x+Border;
74                 draw(screen, r1, display->black, nil, ZP);
75                 r.min.x = r1.max.x;
76         }
77         if(c == nil){
78                 c = emalloc(sizeof(Column));
79                 colinit(c, r);
80                 incref(&reffont);
81         }else
82                 colresize(c, r);
83         c->row = row;
84         c->tag.row = row;
85         row->col = realloc(row->col, (row->ncol+1)*sizeof(Column*));
86         memmove(row->col+i+1, row->col+i, (row->ncol-i)*sizeof(Column*));
87         row->col[i] = c;
88         row->ncol++;
89         clearmouse();
90         return c;
91 }
92
93 void
94 rowresize(Row *row, Rectangle r)
95 {
96         int i, dx, odx;
97         Rectangle r1, r2;
98         Column *c;
99
100         dx = Dx(r);
101         odx = Dx(row->r);
102         row->r = r;
103         r1 = r;
104         r1.max.y = r1.min.y + font->height;
105         textresize(&row->tag, r1);
106         r1.min.y = r1.max.y;
107         r1.max.y += Border;
108         draw(screen, r1, display->black, nil, ZP);
109         r.min.y = r1.max.y;
110         r1 = r;
111         r1.max.x = r1.min.x;
112         for(i=0; i<row->ncol; i++){
113                 c = row->col[i];
114                 r1.min.x = r1.max.x;
115                 if(i == row->ncol-1)
116                         r1.max.x = r.max.x;
117                 else
118                         r1.max.x = r1.min.x+Dx(c->r)*dx/odx;
119                 if(i > 0){
120                         r2 = r1;
121                         r2.max.x = r2.min.x+Border;
122                         draw(screen, r2, display->black, nil, ZP);
123                         r1.min.x = r2.max.x;
124                 }
125                 colresize(c, r1);
126         }
127 }
128
129 void
130 rowdragcol(Row *row, Column *c, int)
131 {
132         Rectangle r;
133         int i, b, x;
134         Point p, op;
135         Column *d;
136
137         clearmouse();
138         setcursor(mousectl, &boxcursor);
139         b = mouse->buttons;
140         op = mouse->xy;
141         while(mouse->buttons == b)
142                 readmouse(mousectl);
143         setcursor(mousectl, nil);
144         if(mouse->buttons){
145                 while(mouse->buttons)
146                         readmouse(mousectl);
147                 return;
148         }
149
150         for(i=0; i<row->ncol; i++)
151                 if(row->col[i] == c)
152                         goto Found;
153         error("can't find column");
154
155   Found:
156         p = mouse->xy;
157         if((abs(p.x-op.x)<5 && abs(p.y-op.y)<5))
158                 return;
159         if((i>0 && p.x<row->col[i-1]->r.min.x) || (i<row->ncol-1 && p.x>c->r.max.x)){
160                 /* shuffle */
161                 x = c->r.min.x;
162                 rowclose(row, c, FALSE);
163                 if(rowadd(row, c, p.x) == nil)  /* whoops! */
164                 if(rowadd(row, c, x) == nil)            /* WHOOPS! */
165                 if(rowadd(row, c, -1)==nil){            /* shit! */
166                         rowclose(row, c, TRUE);
167                         return;
168                 }
169                 colmousebut(c);
170                 return;
171         }
172         if(i == 0)
173                 return;
174         d = row->col[i-1];
175         if(p.x < d->r.min.x+80+Scrollwid)
176                 p.x = d->r.min.x+80+Scrollwid;
177         if(p.x > c->r.max.x-80-Scrollwid)
178                 p.x = c->r.max.x-80-Scrollwid;
179         r = d->r;
180         r.max.x = c->r.max.x;
181         draw(screen, r, display->white, nil, ZP);
182         r.max.x = p.x;
183         colresize(d, r);
184         r = c->r;
185         r.min.x = p.x;
186         r.max.x = r.min.x;
187         r.max.x += Border;
188         draw(screen, r, display->black, nil, ZP);
189         r.min.x = r.max.x;
190         r.max.x = c->r.max.x;
191         colresize(c, r);
192         colmousebut(c);
193 }
194
195 void
196 rowclose(Row *row, Column *c, int dofree)
197 {
198         Rectangle r;
199         int i;
200
201         for(i=0; i<row->ncol; i++)
202                 if(row->col[i] == c)
203                         goto Found;
204         error("can't find column");
205   Found:
206         r = c->r;
207         if(dofree)
208                 colcloseall(c);
209         memmove(row->col+i, row->col+i+1, (row->ncol-i)*sizeof(Column*));
210         row->ncol--;
211         row->col = realloc(row->col, row->ncol*sizeof(Column*));
212         if(row->ncol == 0){
213                 draw(screen, r, display->white, nil, ZP);
214                 return;
215         }
216         if(i == row->ncol){             /* extend last column right */
217                 c = row->col[i-1];
218                 r.min.x = c->r.min.x;
219                 r.max.x = row->r.max.x;
220         }else{                  /* extend next window left */
221                 c = row->col[i];
222                 r.max.x = c->r.max.x;
223         }
224         draw(screen, r, display->white, nil, ZP);
225         colresize(c, r);
226 }
227
228 Column*
229 rowwhichcol(Row *row, Point p)
230 {
231         int i;
232         Column *c;
233
234         for(i=0; i<row->ncol; i++){
235                 c = row->col[i];
236                 if(ptinrect(p, c->r))
237                         return c;
238         }
239         return nil;
240 }
241
242 Text*
243 rowwhich(Row *row, Point p)
244 {
245         Column *c;
246
247         if(ptinrect(p, row->tag.all))
248                 return &row->tag;
249         c = rowwhichcol(row, p);
250         if(c)
251                 return colwhich(c, p);
252         return nil;
253 }
254
255 Text*
256 rowtype(Row *row, Rune r, Point p)
257 {
258         Window *w;
259         Text *t;
260
261         clearmouse();
262         qlock(row);
263         if(bartflag)
264                 t = barttext;
265         else
266                 t = rowwhich(row, p);
267         if(t!=nil && !(t->what==Tag && ptinrect(p, t->scrollr))){
268                 w = t->w;
269                 if(w == nil)
270                         texttype(t, r);
271                 else{
272                         winlock(w, 'K');
273                         wintype(w, t, r);
274                         winunlock(w);
275                 }
276         }
277         qunlock(row);
278         return t;
279 }
280
281 int
282 rowclean(Row *row)
283 {
284         int clean;
285         int i;
286
287         clean = TRUE;
288         for(i=0; i<row->ncol; i++)
289                 clean &= colclean(row->col[i]);
290         return clean;
291 }
292
293 void
294 rowdump(Row *row, char *file)
295 {
296         int i, j, fd, m, n, dumped;
297         uint q0, q1;
298         Biobuf *b;
299         char *buf, *a, *fontname;
300         Rune *r;
301         Column *c;
302         Window *w, *w1;
303         Text *t;
304
305         if(row->ncol == 0)
306                 return;
307         buf = fbufalloc();
308         if(file == nil){
309                 if(home == nil){
310                         warning(nil, "can't find file for dump: $home not defined\n");
311                         goto Rescue;
312                 }
313                 sprint(buf, "%s/acme.dump", home);
314                 file = buf;
315         }
316         fd = create(file, OWRITE, 0600);
317         if(fd < 0){
318                 warning(nil, "can't open %s: %r\n", file);
319                 goto Rescue;
320         }
321         b = emalloc(sizeof(Biobuf));
322         Binit(b, fd, OWRITE);
323         r = fbufalloc();
324         Bprint(b, "%s\n", wdir);
325         Bprint(b, "%s\n", fontnames[0]);
326         Bprint(b, "%s\n", fontnames[1]);
327         for(i=0; i<row->ncol; i++){
328                 c = row->col[i];
329                 Bprint(b, "%11d", 100*(c->r.min.x-row->r.min.x)/Dx(row->r));
330                 if(i == row->ncol-1)
331                         Bputc(b, '\n');
332                 else
333                         Bputc(b, ' ');
334         }
335         for(i=0; i<row->ncol; i++){
336                 c = row->col[i];
337                 for(j=0; j<c->nw; j++)
338                         c->w[j]->body.file->dumpid = 0;
339         }
340         for(i=0; i<row->ncol; i++){
341                 c = row->col[i];
342                 for(j=0; j<c->nw; j++){
343                         w = c->w[j];
344                         wincommit(w, &w->tag);
345                         t = &w->body;
346                         /* windows owned by others get special treatment */
347                         if(w->nopen[QWevent] > 0)
348                                 if(w->dumpstr == nil)
349                                         continue;
350                         /* zeroxes of external windows are tossed */
351                         if(t->file->ntext > 1)
352                                 for(n=0; n<t->file->ntext; n++){
353                                         w1 = t->file->text[n]->w;
354                                         if(w == w1)
355                                                 continue;
356                                         if(w1->nopen[QWevent])
357                                                 goto Continue2;
358                                 }
359                         fontname = "";
360                         if(t->reffont->f != font)
361                                 fontname = t->reffont->f->name;
362                         if(t->file->nname)
363                                 a = runetobyte(t->file->name, t->file->nname);
364                         else
365                                 a = emalloc(1);
366                         if(t->file->dumpid){
367                                 dumped = FALSE;
368                                 Bprint(b, "x%11d %11d %11d %11d %11d %s\n", i, t->file->dumpid,
369                                         w->body.q0, w->body.q1,
370                                         100*(w->r.min.y-c->r.min.y)/Dy(c->r),
371                                         fontname);
372                         }else if(w->dumpstr){
373                                 dumped = FALSE;
374                                 Bprint(b, "e%11d %11d %11d %11d %11d %s\n", i, t->file->dumpid,
375                                         0, 0,
376                                         100*(w->r.min.y-c->r.min.y)/Dy(c->r),
377                                         fontname);
378                         }else if((w->dirty==FALSE && access(a, 0)==0) || w->isdir){
379                                 dumped = FALSE;
380                                 t->file->dumpid = w->id;
381                                 Bprint(b, "f%11d %11d %11d %11d %11d %s\n", i, w->id,
382                                         w->body.q0, w->body.q1,
383                                         100*(w->r.min.y-c->r.min.y)/Dy(c->r),
384                                         fontname);
385                         }else{
386                                 dumped = TRUE;
387                                 t->file->dumpid = w->id;
388                                 Bprint(b, "F%11d %11d %11d %11d %11d %11d %s\n", i, j,
389                                         w->body.q0, w->body.q1,
390                                         100*(w->r.min.y-c->r.min.y)/Dy(c->r),
391                                         w->body.file->nc, fontname);
392                         }
393                         free(a);
394                         winctlprint(w, buf, 0);
395                         Bwrite(b, buf, strlen(buf));
396                         m = min(RBUFSIZE, w->tag.file->nc);
397                         bufread(w->tag.file, 0, r, m);
398                         n = 0;
399                         while(n<m && r[n]!='\n')
400                                 n++;
401                         r[n++] = '\n';
402                         Bprint(b, "%.*S", n, r);
403                         if(dumped){
404                                 q0 = 0;
405                                 q1 = t->file->nc;
406                                 while(q0 < q1){
407                                         n = q1 - q0;
408                                         if(n > BUFSIZE/UTFmax)
409                                                 n = BUFSIZE/UTFmax;
410                                         bufread(t->file, q0, r, n);
411                                         Bprint(b, "%.*S", n, r);
412                                         q0 += n;
413                                 }
414                         }
415                         if(w->dumpstr){
416                                 if(w->dumpdir)
417                                         Bprint(b, "%s\n%s\n", w->dumpdir, w->dumpstr);
418                                 else
419                                         Bprint(b, "\n%s\n", w->dumpstr);
420                         }
421     Continue2:;
422                 }
423         }
424         Bterm(b);
425         close(fd);
426         free(b);
427         fbuffree(r);
428
429    Rescue:
430         fbuffree(buf);
431 }
432
433 static
434 char*
435 rdline(Biobuf *b, int *linep)
436 {
437         char *l;
438
439         l = Brdline(b, '\n');
440         if(l)
441                 (*linep)++;
442         return l;
443 }
444
445 /*
446  * Get font names from load file so we don't load fonts we won't use
447  */
448 void
449 rowloadfonts(char *file)
450 {
451         int i;
452         Biobuf *b;
453         char *l;
454
455         b = Bopen(file, OREAD);
456         if(b == nil)
457                 return;
458         /* current directory */
459         l = Brdline(b, '\n');
460         if(l == nil)
461                 goto Return;
462         /* global fonts */
463         for(i=0; i<2; i++){
464                 l = Brdline(b, '\n');
465                 if(l == nil)
466                         goto Return;
467                 l[Blinelen(b)-1] = 0;
468                 if(*l && strcmp(l, fontnames[i])!=0){
469                         free(fontnames[i]);
470                         fontnames[i] = estrdup(l);
471                 }
472         }
473     Return:
474         Bterm(b);
475 }
476
477 int
478 rowload(Row *row, char *file, int initing)
479 {
480         int i, j, line, percent, y, nr, nfontr, n, ns, ndumped, dumpid, x, fd;
481         Biobuf *b, *bout;
482         char *buf, *l, *t, *fontname;
483         Rune *r, rune, *fontr;
484         Column *c, *c1, *c2;
485         uint q0, q1;
486         Rectangle r1, r2;
487         Window *w;
488
489         buf = fbufalloc();
490         if(file == nil){
491                 if(home == nil){
492                         warning(nil, "can't find file for load: $home not defined\n");
493                         goto Rescue1;
494                 }
495                 sprint(buf, "%s/acme.dump", home);
496                 file = buf;
497         }
498         b = Bopen(file, OREAD);
499         if(b == nil){
500                 warning(nil, "can't open load file %s: %r\n", file);
501                 goto Rescue1;
502         }
503         /* current directory */
504         line = 0;
505         l = rdline(b, &line);
506         if(l == nil)
507                 goto Rescue2;
508         l[Blinelen(b)-1] = 0;
509         if(chdir(l) < 0){
510                 warning(nil, "can't chdir %s\n", l);
511                 goto Rescue2;
512         }
513         /* global fonts */
514         for(i=0; i<2; i++){
515                 l = rdline(b, &line);
516                 if(l == nil)
517                         goto Rescue2;
518                 l[Blinelen(b)-1] = 0;
519                 if(*l && strcmp(l, fontnames[i])!=0)
520                         rfget(i, TRUE, i==0 && initing, l);
521         }
522         if(initing && row->ncol==0)
523                 rowinit(row, screen->clipr);
524         l = rdline(b, &line);
525         if(l == nil)
526                 goto Rescue2;
527         j = Blinelen(b)/12;
528         if(j<=0 || j>10)
529                 goto Rescue2;
530         for(i=0; i<j; i++){
531                 percent = atoi(l+i*12);
532                 if(percent<0 || percent>=100)
533                         goto Rescue2;
534                 x = row->r.min.x+percent*Dx(row->r)/100;
535                 if(i < row->ncol){
536                         if(i == 0)
537                                 continue;
538                         c1 = row->col[i-1];
539                         c2 = row->col[i];
540                         r1 = c1->r;
541                         r2 = c2->r;
542                         r1.max.x = x;
543                         r2.min.x = x+Border;
544                         if(Dx(r1) < 50 || Dx(r2) < 50)
545                                 continue;
546                         draw(screen, Rpt(r1.min, r2.max), display->white, nil, ZP);
547                         colresize(c1, r1);
548                         colresize(c2, r2);
549                         r2.min.x = x;
550                         r2.max.x = x+Border;
551                         draw(screen, r2, display->black, nil, ZP);
552                 }
553                 if(i >= row->ncol)
554                         rowadd(row, nil, x);
555         }
556         for(;;){
557                 l = rdline(b, &line);
558                 if(l == nil)
559                         break;
560                 dumpid = 0;
561                 switch(l[0]){
562                 case 'e':
563                         if(Blinelen(b) < 1+5*12+1)
564                                 goto Rescue2;
565                         l = rdline(b, &line);   /* ctl line; ignored */
566                         if(l == nil)
567                                 goto Rescue2;
568                         l = rdline(b, &line);   /* directory */
569                         if(l == nil)
570                                 goto Rescue2;
571                         l[Blinelen(b)-1] = 0;
572                         if(*l == '\0'){
573                                 if(home == nil)
574                                         r = bytetorune("./", &nr);
575                                 else{
576                                         t = emalloc(strlen(home)+1+1);
577                                         sprint(t, "%s/", home);
578                                         r = bytetorune(t, &nr);
579                                         free(t);
580                                 }
581                         }else
582                                 r = bytetorune(l, &nr);
583                         l = rdline(b, &line);   /* command */
584                         if(l == nil)
585                                 goto Rescue2;
586                         t = emalloc(Blinelen(b)+1);
587                         memmove(t, l, Blinelen(b));
588                         run(nil, t, r, nr, TRUE, nil, nil, FALSE);
589                         /* r is freed in run() */
590                         continue;
591                 case 'f':
592                         if(Blinelen(b) < 1+5*12+1)
593                                 goto Rescue2;
594                         fontname = l+1+5*12;
595                         ndumped = -1;
596                         break;
597                 case 'F':
598                         if(Blinelen(b) < 1+6*12+1)
599                                 goto Rescue2;
600                         fontname = l+1+6*12;
601                         ndumped = atoi(l+1+5*12+1);
602                         break;
603                 case 'x':
604                         if(Blinelen(b) < 1+5*12+1)
605                                 goto Rescue2;
606                         fontname = l+1+5*12;
607                         ndumped = -1;
608                         dumpid = atoi(l+1+1*12);
609                         break;
610                 default:
611                         goto Rescue2;
612                 }
613                 l[Blinelen(b)-1] = 0;
614                 fontr = nil;
615                 nfontr = 0;
616                 if(*fontname)
617                         fontr = bytetorune(fontname, &nfontr);
618                 i = atoi(l+1+0*12);
619                 j = atoi(l+1+1*12);
620                 q0 = atoi(l+1+2*12);
621                 q1 = atoi(l+1+3*12);
622                 percent = atoi(l+1+4*12);
623                 if(i<0 || i>10)
624                         goto Rescue2;
625                 if(i > row->ncol)
626                         i = row->ncol;
627                 c = row->col[i];
628                 y = c->r.min.y+(percent*Dy(c->r))/100;
629                 if(y<c->r.min.y || y>=c->r.max.y)
630                         y = -1;
631                 if(dumpid == 0)
632                         w = coladd(c, nil, nil, y);
633                 else
634                         w = coladd(c, nil, lookid(dumpid, TRUE), y);
635                 if(w == nil)
636                         continue;
637                 w->dumpid = j;
638                 l = rdline(b, &line);
639                 if(l == nil)
640                         goto Rescue2;
641                 l[Blinelen(b)-1] = 0;
642                 r = bytetorune(l+5*12, &nr);
643                 ns = -1;
644                 for(n=0; n<nr; n++){
645                         if(r[n] == '/')
646                                 ns = n;
647                         if(r[n] == ' ')
648                                 break;
649                 }
650                 if(dumpid == 0)
651                         winsetname(w, r, n);
652                 for(; n<nr; n++)
653                         if(r[n] == '|')
654                                 break;
655                 wincleartag(w);
656                 textinsert(&w->tag, w->tag.file->nc, r+n+1, nr-(n+1), TRUE);
657                 if(ndumped >= 0){
658                         /* simplest thing is to put it in a file and load that */
659                         sprint(buf, "/tmp/d%d.%.4sacme", getpid(), getuser());
660                         fd = create(buf, OWRITE|ORCLOSE, 0600);
661                         if(fd < 0){
662                                 free(r);
663                                 warning(nil, "can't create temp file: %r\n");
664                                 goto Rescue2;
665                         }
666                         bout = emalloc(sizeof(Biobuf));
667                         Binit(bout, fd, OWRITE);
668                         for(n=0; n<ndumped; n++){
669                                 rune = Bgetrune(b);
670                                 if(rune == '\n')
671                                         line++;
672                                 if(rune == (Rune)Beof){
673                                         free(r);
674                                         Bterm(bout);
675                                         free(bout);
676                                         close(fd);
677                                         goto Rescue2;
678                                 }
679                                 Bputrune(bout, rune);
680                         }
681                         Bterm(bout);
682                         free(bout);
683                         textload(&w->body, 0, buf, 1);
684                         close(fd);
685                         w->body.file->mod = TRUE;
686                         for(n=0; n<w->body.file->ntext; n++)
687                                 w->body.file->text[n]->w->dirty = TRUE;
688                         winsettag(w);
689                 }else if(dumpid==0 && r[ns+1]!='+' && r[ns+1]!='-')
690                         get(&w->body, nil, nil, FALSE, XXX, nil, 0);
691                 if(fontr){
692                         fontx(&w->body, nil, nil, 0, 0, fontr, nfontr);
693                         free(fontr);
694                 }
695                 free(r);
696                 if(q0>w->body.file->nc || q1>w->body.file->nc || q0>q1)
697                         q0 = q1 = 0;
698                 textshow(&w->body, q0, q1, 1);
699                 w->maxlines = min(w->body.nlines, max(w->maxlines, w->body.maxlines));
700         }
701         Bterm(b);
702         fbuffree(buf);
703         return TRUE;
704
705 Rescue2:
706         warning(nil, "bad load file %s:%d\n", file, line);
707         Bterm(b);
708 Rescue1:
709         fbuffree(buf);
710         return FALSE;
711 }
712
713 void
714 allwindows(void (*f)(Window*, void*), void *arg)
715 {
716         int i, j;
717         Column *c;
718
719         for(i=0; i<row.ncol; i++){
720                 c = row.col[i];
721                 for(j=0; j<c->nw; j++)
722                         (*f)(c->w[j], arg);
723         }
724 }