]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/spred/cmdw.c
exec(2): fix prototypes
[plan9front.git] / sys / src / cmd / spred / cmdw.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <thread.h>
5 #include <draw.h>
6 #include <mouse.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include "dat.h"
10 #include "fns.h"
11
12 static int
13 cmdinit(Win *)
14 {
15         return 0;
16 }
17
18 static void
19 scrollbar(Win *w)
20 {
21         int h, t0, t1;
22
23         h = Dy(w->inner);
24         draw(w->im, rectaddpt(Rect(0, 0, SCRBSIZ+1, h), w->inner.min), w->tab->cols[BORD], nil, ZP);
25         t0 = w->toprune * h;
26         t1 = (w->toprune + w->fr.nchars) * h;
27         if(w->nrunes == 0){
28                  t0 = 0;
29                  t1 = h;
30         }else{
31                 t0 /= w->nrunes;
32                 t1 /= w->nrunes;
33         }
34         draw(w->im, rectaddpt(Rect(0, t0, SCRBSIZ, t1), w->inner.min), w->tab->cols[BACK], nil, ZP);
35 }
36
37 static void
38 cmddraw(Win *w)
39 {
40         Rectangle r;
41         
42         frclear(&w->fr, 0);
43         r = insetrect(w->inner, 1);
44         r.min.x += SCRTSIZ;
45         scrollbar(w);
46         frinit(&w->fr, r, display->defaultfont, w->im, w->tab->cols);
47         frinsert(&w->fr, w->runes + w->toprune, w->runes + w->nrunes, 0);
48 }
49
50 void
51 cmdscroll(Win *w, int l)
52 {
53         int r;
54         
55         if(l == 0)
56                 return;
57         if(l > 0){
58                 for(r = w->toprune; r < w->nrunes && l != 0; r++)
59                         if(w->runes[r] == '\n')
60                                 l--;
61                 w->toprune = r;
62         }else{
63                 for(r = w->toprune; r > 0; r--)
64                         if(w->runes[r] == '\n' && ++l == 0){
65                                 r++;
66                                 break;
67                         }
68                 w->toprune = r;
69         
70         }
71         frdelete(&w->fr, 0, w->fr.nchars);
72         frinsert(&w->fr, w->runes + w->toprune, w->runes + w->nrunes, 0);
73         scrollbar(w);
74 }
75
76 static void
77 cmdclick(Win *w, Mousectl *mc)
78 {
79         if(mc->xy.x <= w->inner.min.x + SCRBSIZ){
80                 cmdscroll(w, -5);
81                 return;
82         }
83         frselect(&w->fr, mc);
84 }
85
86 static int
87 cmdrmb(Win *w, Mousectl *mc)
88 {
89         if(mc->xy.x > w->inner.min.x + SCRBSIZ)
90                 return -1;
91         cmdscroll(w, 5);
92         return 0;
93 }
94
95 int
96 cmdinsert(Win *w, Rune *r, int nr, int rp)
97 {
98         Rune *s;
99
100         if(nr < 0)
101                 for(nr = 0, s = r; *s++ != 0; nr++)
102                         ;
103         if(rp < 0 || rp > w->nrunes)
104                 rp = w->nrunes;
105         if(w->nrunes + nr > w->arunes){
106                 w->runes = realloc(w->runes, w->arunes = w->arunes + (nr + RUNEBLK - 1) & ~(RUNEBLK - 1));
107                 if(w->runes == nil)
108                         sysfatal("realloc: %r");
109         }
110         if(rp != w->nrunes)
111                 memmove(w->runes + rp, w->runes + rp + nr, (w->nrunes - rp) * sizeof(Rune));
112         memmove(w->runes + rp, r, nr * sizeof(Rune));
113         w->nrunes += nr;
114         if(w->toprune > rp)
115                 w->toprune += nr;
116         else{
117                 frinsert(&w->fr, w->runes + rp, w->runes + rp + nr, rp - w->toprune);
118                 if(rp == w->nrunes - nr){
119                         if(w->fr.lastlinefull)
120                                 cmdscroll(w, 1);
121                 }
122         }
123         if(w->opoint > rp)
124                 w->opoint += nr;
125         return nr;
126 }
127
128 static void
129 cmddel(Win *w, int a, int b)
130 {
131         if(a >= b)
132                 return;
133         memmove(w->runes + a, w->runes + b, w->nrunes - b);
134         w->nrunes -= b - a;
135         if(w->toprune >= b)
136                 w->toprune -= b - a;
137         else{
138                 frdelete(&w->fr, a - w->toprune, b - w->toprune);
139                 if(w->toprune >= a)
140                         w->toprune = a;
141         }
142         if(a <= w->opoint && w->opoint < b)
143                 w->opoint = a;
144         else if(w->opoint >= b)
145                 w->opoint -= b -  a;
146 }
147
148 static void
149 setsel(Win *w, int p0, int p1)
150 {
151         frdrawsel(&w->fr, frptofchar(&w->fr, w->fr.p0), w->fr.p0, w->fr.p1, 0);
152         w->fr.p0 = p0;
153         w->fr.p1 = p1;
154         frdrawsel(&w->fr, frptofchar(&w->fr, p0), p0, p1, 1);
155 }
156
157 static void
158 cmdline(Win *w)
159 {
160         static char buf[4096];
161         Rune *q;
162         char *p;
163
164         q = w->runes + w->opoint;
165         p = buf;
166         while(q < w->runes + w->nrunes && p < buf + nelem(buf) + 1)
167                 p += runetochar(p, q++);
168         *p = 0;
169         w->opoint = w->nrunes;
170         docmd(buf);
171 }
172
173 static void
174 cmdkey(Win *w, Rune r)
175 {
176         switch(r){
177         case Kview:
178                 cmdscroll(w, 3);
179                 return;
180         case Kup:
181                 cmdscroll(w, -3);
182                 return;
183         case Kleft:
184                 if(w->fr.p0 == 0)
185                         return;
186                 setsel(w, w->fr.p0 - 1, w->fr.p0 - 1);
187                 return;
188         case Kright:
189                 if(w->toprune + w->fr.p1 == w->nrunes)
190                         return;
191                 setsel(w, w->fr.p1 + 1, w->fr.p1 + 1);
192                 return;
193         }
194         if(w->fr.p0 < w->fr.p1)
195                 cmddel(w, w->toprune + w->fr.p0, w->toprune + w->fr.p1);
196         switch(r){
197         case 0x00:
198         case Kesc:
199                 break;
200         case '\b':
201                 if(w->fr.p0 > 0 && w->toprune + w->fr.p0 != w->opoint)
202                         cmddel(w, w->toprune + w->fr.p0 - 1, w->toprune + w->fr.p0);
203                 break;
204         case '\n':
205                 cmdinsert(w, &r, 1, w->fr.p0 + w->toprune);
206                 if(w->toprune + w->fr.p0 == w->nrunes)
207                         cmdline(w);
208                 break;
209         default:
210                 cmdinsert(w, &r, 1, w->fr.p0 + w->toprune);
211         }
212 }
213
214 static int
215 tosnarf(Win *w, int p0, int p1)
216 {
217         int fd;
218         static char buf[512];
219         char *c, *ce;
220         Rune *rp, *re;
221         
222         if(p0 >= p1)
223                 return 0;
224         fd = open("/dev/snarf", OWRITE|OTRUNC);
225         if(fd < 0){
226                 cmdprint("tosnarf: %r");
227                 return -1;
228         }
229         c = buf;
230         ce = buf + sizeof(buf);
231         rp = w->runes + p0;
232         re = w->runes + p1;
233         for(; rp < re; rp++){
234                 if(c + UTFmax > ce){
235                         write(fd, buf, c - buf);
236                         c = buf;
237                 }
238                 c += runetochar(c, rp);
239         }
240         if(c > buf)
241                 write(fd, buf, c - buf);
242         close(fd);
243         return 0;
244 }
245
246 static int
247 fromsnarf(Win *w, int p0)
248 {
249         int fd, rc;
250         char *buf, *p;
251         Rune *rbuf, *r;
252         int nc, end;
253         
254         fd = open("/dev/snarf", OREAD);
255         if(fd < 0){
256                 cmdprint("fromsnarf: %r");
257                 return -1;
258         }
259         buf = nil;
260         nc = 0;
261         for(;;){
262                 buf = realloc(buf, nc + 4096);
263                 rc = readn(fd, buf + nc, nc + 4096);
264                 if(rc <= 0)
265                         break;
266                 nc += rc;
267                 if(rc < 4096)
268                         break;
269         }
270         close(fd);
271         rbuf = emalloc(sizeof(Rune) * nc);
272         r = rbuf;
273         for(p = buf; p < buf + nc; r++)
274                 p += chartorune(r, p);
275         end = p0 == w->nrunes;
276         cmdinsert(w, rbuf, r - rbuf, p0);
277         if(end && r > rbuf && r[-1] == '\n')
278                 cmdline(w);
279         return 0;
280 }
281
282 static void
283 cmdmenu(Win *w, Mousectl *mc)
284 {
285         enum {
286                 CUT,
287                 PASTE,
288                 SNARF,
289         };
290         static char *ms[] = {
291                 [CUT] "cut",
292                 [PASTE] "paste",
293                 [SNARF] "snarf",
294                 nil,
295         };
296         static Menu m = {ms};
297         
298         switch(menuhit(2, mc, &m, nil)){
299         case CUT:
300                 if(tosnarf(w, w->toprune + w->fr.p0, w->toprune + w->fr.p1) >= 0)
301                         cmddel(w, w->toprune + w->fr.p0, w->toprune + w->fr.p1);
302                 break;
303         case SNARF:
304                 tosnarf(w, w->toprune + w->fr.p0, w->toprune + w->fr.p1);
305                 break;
306         case PASTE:
307                 if(w->fr.p0 < w->fr.p1)
308                         cmddel(w, w->toprune + w->fr.p0, w->toprune + w->fr.p1);
309                 fromsnarf(w, w->toprune + w->fr.p0);
310                 break;
311         }
312 }
313
314 void
315 cmdprint(char *fmt, ...)
316 {
317         Rune *r;
318         va_list va;
319         
320         va_start(va, fmt);
321         r = runevsmprint(fmt, va);
322         va_end(va);
323         if(r != nil)
324                 cmdw->opoint += cmdinsert(cmdw, r, -1, cmdw->opoint);
325 }
326
327 Wintab cmdtab = {
328         .init = cmdinit,
329         .draw = cmddraw,
330         .click = cmdclick,
331         .menu = cmdmenu,
332         .rmb = cmdrmb,
333         .key = cmdkey,
334         .hexcols = {
335                 [BORD] DPurpleblue,
336                 [DISB] 0xCCCCEEFF,
337                 [BACK] 0xCCFFFFFF,
338                 [HIGH] DPalegreygreen
339         }
340 };