386BSD 0.1 development
[unix-history] / usr / othersrc / public / zsh-2.2 / src / zle_refresh.c
CommitLineData
dbf02a84
WJ
1/*
2 *
3 * zle_refresh.c - screen update
4 *
5 * This file is part of zsh, the Z shell.
6 *
7 * This software is Copyright 1992 by Paul Falstad
8 *
9 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
10 * use this software as long as: there is no monetary profit gained
11 * specifically from the use or reproduction of this software, it is not
12 * sold, rented, traded or otherwise marketed, and this copyright notice is
13 * included prominently in any copy made.
14 *
15 * The author make no claims as to the fitness or correctness of this software
16 * for any use whatsoever, and it is provided as is. Any use of this software
17 * is at the user's own risk.
18 *
19 */
20
21#define ZLE
22#include "zsh.h"
23
24char **obuf = NULL,**nbuf = NULL;
25int olnct,nlnct;
26int winw,winh,winpos;
27
28int vcs,vln,vmaxln;
29
30void resetvideo() /**/
31{
32int ln;
33static int lwinw = -1,lwinh = -1;
34
35 setterm();
36 winw = columns-1;
37 if (isset(SINGLELINEZLE) || !termok)
38 winh = 1;
39 else
40 winh = (lines < 2) ? 24 : lines;
41 winpos = vln = vmaxln = 0;
42 if (lwinw != winw || lwinh != winh)
43 {
44 if (nbuf)
45 {
46 for (ln = 0; ln != lwinh; ln++)
47 {
48 free(nbuf[ln]);
49 free(obuf[ln]);
50 }
51 free(nbuf);
52 free(obuf);
53 }
54 nbuf = (char **) zalloc((winh+1)*sizeof(char *));
55 obuf = (char **) zalloc((winh+1)*sizeof(char *));
56 for (ln = 0; ln != winh+1; ln++)
57 {
58 nbuf[ln] = zalloc(winw+1);
59 obuf[ln] = zalloc(winw+1);
60 }
61 lwinw = winw;
62 lwinh = winh;
63 }
64 for (ln = 0; ln != winh+1; ln++)
65 {
66 *nbuf[ln] = '\0';
67 *obuf[ln] = '\0';
68 }
69 if (!pptlen)
70 nbuf[0][0] = obuf[0][0] = '\0';
71 else
72 {
73 for (ln = 0; ln != pptlen-1; ln++)
74 nbuf[0][ln] = obuf[0][ln] = ' ';
75 nbuf[0][ln] = obuf[0][ln] = '>';
76 nbuf[0][pptlen] = obuf[0][pptlen] = '\0';
77 }
78 vcs = pptlen;
79 olnct = nlnct = 1;
80}
81
82int scrollwindow() /**/
83{
84int t0,hwinh = winh/2;
85
86 for (t0 = 0; t0 != winh-hwinh; t0++)
87 {
88 char *s;
89
90 s = nbuf[t0];
91 nbuf[t0] = nbuf[t0+hwinh];
92 nbuf[t0+hwinh] = s;
93 }
94 for (t0 = 0; t0 != pptlen-1; t0++)
95 nbuf[0][t0] = ' ';
96 strcpy(nbuf[0]+t0,"> ...");
97 return winh-hwinh;
98}
99
100/* this is the messy part. */
101/* this define belongs where it's used!!! */
102
103#define nextline { *s = (unsigned char)'\0'; \
104 if (winh == ln+1) if (nvln != -1) break; else ln = scrollwindow()-1; \
105 s = (unsigned char *)nbuf[++ln]; sen = s+winw; \
106 }
107
108void refresh() /**/
109{
110unsigned char *s,*t,*sen,*scs = line+cs; char **qbuf;
111int ln = 0,nvcs,nvln = -1,t0;
112
113 cost = 0;
114 if (resetneeded)
115 {
116 resetvideo();
117 resetneeded = 0;
118 if (isset(SINGLELINEZLE) || !termok)
119 vcs = 0;
120 else
121 printf("%s",pmpt);
122 }
123 zleactive = 1;
124 if (isset(SINGLELINEZLE) || !termok)
125 {
126 singlerefresh();
127 return;
128 }
129
130/* first, we generate the video line buffers so we know what to
131 put on the screen.
132
133 s = ptr into the video buffer.
134 t = ptr into the real buffer.
135 sen = end of the video buffer (eol)
136*/
137
138 s = (unsigned char *)(nbuf[ln = 0]+pptlen);
139 t = line;
140 sen = (unsigned char *)(*nbuf+winw);
141 for (; *t; t++)
142 {
143 if (icntrl((char)*t))
144 if (*t == '\n')
145 {
146 if (t == scs)
147 {
148 nvcs = (char *)s-nbuf[nvln = ln];
149 scs = (unsigned char *)NULL;
150 }
151 nextline
152 }
153 else if ((char)*t == '\t')
154 {
155 int t1 = (char *)s-nbuf[ln];
156
157 if ((t1|7)+1 >= winw) nextline
158 else
159 do
160 *s++ = ' ';
161 while ((++t1) & 7);
162 }
163 else
164 {
165 if (s == sen) nextline
166 *s++ = '^';
167 if (s == sen) nextline
168 *s++ = (*t == 127) ? '?' : (*t | '@');
169 }
170 else
171 {
172 if (s == sen) nextline
173 *s++ = *t;
174 }
175/* if the cursor is here, remember it */
176
177 if (t == scs)
178 nvcs = s-(unsigned char *)nbuf[nvln = ln]-1;
179 }
180 if (scs == t)
181 nvcs = s-(unsigned char *)nbuf[nvln = ln];
182 *s = '\0';
183 nlnct = ln+1;
184 if (statusline)
185 strcpy(nbuf[(nlnct == winh) ? winh-1 : nlnct++],statusline);
186
187/* do RPROMPT */
188
189 if (pmpt2 && ln == 0 && strlen(nbuf[0])+strlen(pmpt2) < winw)
190 {
191 for (t0 = strlen(nbuf[0]); t0 != winw; t0++)
192 nbuf[0][t0] = ' ';
193 strcpy(nbuf[0]+winw-strlen(pmpt2),pmpt2);
194 }
195 for (ln = 0; ln < nlnct; ln++)
196 {
197
198/* if old line and new line are different,
199 see if we can insert/delete a line */
200
201 if (ln < olnct && strncmp(nbuf[ln],obuf[ln],16))
202 {
203 if (tccan(TCDELLINE) && !strncmp(nbuf[ln],obuf[ln+1],16)
204 && obuf[ln+1][0] && ln != olnct)
205 {
206 int t0;
207
208 moveto(ln,0);
209 tcout(TCDELLINE);
210 for (t0 = ln; t0 != olnct; t0++)
211 strcpy(obuf[t0],obuf[t0+1]);
212 olnct--;
213 }
214
215/* don't try to insert a line if olnct < vmaxln (vmaxln is the number
216 of lines that have been displayed by this routine) so that we don't
217 go off the end of the screen. */
218
219 else if (tccan(TCINSLINE) && !strncmp(nbuf[ln+1],obuf[ln],16) &&
220 olnct < vmaxln && nbuf[ln+1][0] && ln != olnct)
221 {
222 int t0;
223
224 moveto(ln,0);
225 tcout(TCINSLINE);
226 for (t0 = olnct; t0 != ln; t0--)
227 strcpy(obuf[t0],obuf[t0-1]);
228 *obuf[ln] = '\0';
229 olnct++;
230 }
231 }
232 refreshline(ln);
233 }
234
235/* if old buffer had extra lines, do a clear-end-of-display if we can,
236 otherwise, just fill new buffer with blank lines and refresh them */
237
238 if (olnct > nlnct)
239 {
240 for (ln = nlnct; ln < olnct; ln++)
241 nbuf[ln][0] = '\0';
242 if (tccan(TCCLEAREOD))
243 {
244 moveto(nlnct,0);
245 tcout(TCCLEAREOD);
246 }
247 else
248 for (ln = nlnct; ln < olnct; ln++)
249 refreshline(ln);
250 }
251
252/* move to the new cursor position */
253
254 moveto(nvln,nvcs);
255 qbuf = nbuf;
256 nbuf = obuf;
257 obuf = qbuf;
258 olnct = nlnct;
259 if (nlnct > vmaxln)
260 vmaxln = nlnct;
261 fflush(stdout);
262}
263
264#define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
265#define tcdelcost(X) (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL])
266#define tc_delchars(X) tcmultout(TCDEL,TCMULTDEL,(X))
267#define tc_inschars(X) tcmultout(TCINS,TCMULTINS,(X))
268#define tc_upcurs(X) tcmultout(TCUP,TCMULTUP,(X))
269#define tc_leftcurs(X) tcmultout(TCLEFT,TCMULTLEFT,(X))
270
271void refreshline(ln) /**/
272int ln;
273{
274char *nl = nbuf[ln],*ol = obuf[ln];
275char *p1;
276char junk,*truncptr = &junk;
277int ccs = 0;
278
279 if (ln >= olnct)
280 *ol = '\0';
281 for (;;)
282 {
283 while (*nl && *nl == *ol)
284 {
285 nl++,ol++,ccs++;
286 }
287 if (!*nl && !*ol)
288 { *truncptr = '\0'; return; }
289
290/* if this is the end of the new buffer but the old buffer has stuff
291 here, clear to end of line if we can, otherwise fill the new buffer
292 with blanks and continue. */
293
294 if (!*nl)
295 {
296 if (tccan(TCCLEAREOL) && strlen(ol) > tclen[TCCLEAREOL])
297 {
298 moveto(ln,ccs);
299 tcout(TCCLEAREOL);
300 *ol = '\0';
301 *truncptr = '\0';
302 return;
303 }
304 else
305 {
306 int x = strlen(ol);
307 char *p = nl;
308
309 truncptr = p;
310 while (x--)
311 *p++ = ' ';
312 *p = '\0';
313 continue;
314 }
315 }
316
317/* if this is the end of the old buffer, just dump the rest of the
318 new buffer. */
319
320 if (!*ol)
321 {
322 while (*nl == ' ')
323 nl++,ccs++;
324 if (*nl)
325 {
326 moveto(ln,ccs);
327 fwrite(nl,strlen(nl),1,stdout);
328 cost += strlen(nl);
329 ccs = (vcs += strlen(nl));
330 }
331 *truncptr = 0;
332 return;
333 }
334 moveto(ln,ccs);
335
336/* try to insert/delete characters */
337
338 if (ol[1] != nl[1] && tccan(TCDEL))
339 {
340 int ct = 0;
341
342 for (p1 = ol; *p1; p1++,ct++)
343 if (tcdelcost(ct) < streqct(p1,nl))
344 {
345 tc_delchars(ct);
346 ol = p1;
347 break;
348 }
349 if (*p1)
350 continue;
351 }
352
353 if (ol[1] != nl[1] && tccan(TCINS))
354 {
355 int ct = 0;
356
357 for (p1 = nl; *p1; p1++,ct++)
358 if (tcinscost(ct) < streqct(p1,ol)+ct)
359 {
360#if 0
361/* make sure we aren't inserting characters off the end of the screen;
362 if we are, jump to the end and truncate the line, if we can do
363 it quickly (gee, clever idea, Paul!) */
364 if (ct+ccs+strlen(ol) >= winw-1)
365 {
366 if (!tccan(TCMULTRIGHT) || ccs > winw-tclen[TCMULTRIGHT])
367 continue;
368 moveto(ln,winw-1-ct);
369 if (!tccan(TCCLEAREOL) || ct < tclen[TCCLEAREOL])
370 {
371 int x = ct;
372
373 while (vcs++,x--)
374 putchar(' ');
375 }
376 else
377 tcout(TCCLEAREOL);
378 moveto(ln,ccs);
379 }
380#endif
381 if (ct+ccs+strlen(ol) < winw-1)
382 {
383 tc_inschars(ct = p1-nl);
384 ccs = (vcs += p1-nl);
385 cost += ct;
386 fwrite(nl,ct,1,stdout);
387 nl += ct;
388 break;
389 }
390 }
391 if (*p1)
392 continue;
393 }
394
395/* if we can't do anything fancy, just write the new character and
396 keep going. */
397
398 putchar(*nl);
399 cost++;
400 nl++,ol++,ccs = ++vcs;
401 }
402}
403
404void moveto(ln,cl) /**/
405int ln;int cl;
406{
407
408/* move up */
409
410 if (ln < vln)
411 {
412 tc_upcurs(vln-ln);
413 vln = ln;
414 }
415
416/* move down; if we might go off the end of the screen, use newlines
417 instead of TCDOWN */
418
419 while (ln > vln)
420 if (cl < (vcs/2) || ln >= vmaxln || !tccan(TCLEFT))
421 {
422 putchar('\r');
423 putchar('\n');
424 cost+=2;
425 vln++;
426 vcs = 0;
427 }
428 else
429 {
430 tc_downcurs(ln-vln);
431 vln = ln;
432 }
433 if (cl < (vcs/2) || !tccan(TCLEFT))
434 {
435 putchar('\r');
436 cost++;
437 vcs = 0;
438 }
439 if (vcs < cl)
440 tc_rightcurs(cl-vcs);
441 else if (vcs > cl)
442 tc_leftcurs(vcs-cl);
443 vcs = cl;
444}
445
446void tcmultout(cap,multcap,ct) /**/
447int cap;int multcap;int ct;
448{
449 if (tccan(multcap) && (!tccan(cap) || tclen[multcap] < tclen[cap]*ct))
450 tcoutarg(multcap,ct);
451 else while (ct--)
452 tcout(cap);
453}
454
455void tc_rightcurs(ct) /**/
456int ct;
457{
458
459/* do a multright if it's cheaper or if we're walking over the prompt. */
460
461 if (tccan(TCMULTRIGHT) &&
462 (ct > tclen[TCMULTRIGHT] || vln == 0 && vcs < pptlen))
463 tcoutarg(TCMULTRIGHT,ct);
464
465/* if we're walking over the prompt and we can do a bunch of cursor rights,
466 do them, even though they're more expensive. (We can't redraw the
467 prompt very easily in general.) */
468
469 else if (vln == 0 && vcs < pptlen && tccan(TCRIGHT))
470 while (ct--)
471 tcout(TCRIGHT);
472
473/* otherwise write the contents of the video buffer. */
474
475 else
476 fwrite(nbuf[vln]+vcs,ct,1,stdout);
477}
478
479void tc_downcurs(ct) /**/
480int ct;
481{
482 if (tccan(TCMULTDOWN) &&
483 (!tccan(TCDOWN) || tclen[TCMULTDOWN] < tclen[TCDOWN]*ct))
484 tcoutarg(TCMULTDOWN,ct);
485 else if (tccan(TCDOWN))
486 while (ct--)
487 tcout(TCDOWN);
488 else
489 {
490 while (ct--)
491 putchar('\n');
492 vcs = 0;
493 }
494}
495
496/* I'm NOT going to worry about padding unless anyone complains. */
497
498void tcout(cap) /**/
499int cap;
500{
501 tputs(tcstr[cap],1,putraw);
502}
503
504void tcoutarg(cap,arg) /**/
505int cap;int arg;
506{
507 tputs(tgoto(tcstr[cap],arg,arg),1,putraw);
508}
509
510void clearscreen() /**/
511{
512 tcout(TCCLEARSCREEN);
513 resetneeded = 1;
514}
515
516void redisplay() /**/
517{
518 trashzle();
519}
520
521void trashzle() /**/
522{
523 if (zleactive)
524 {
525 refresh();
526 moveto(nlnct,0);
527 printf("%s",postedit);
528 fflush(stdout);
529 unsetterm();
530 resetneeded = 1;
531 }
532}
533
534void singlerefresh() /**/
535{
536char *vbuf,*vp,**qbuf,*op;
537int t0,vsiz,nvcs;
538
539 for (vsiz = 1+pptlen, t0 = 0; t0 != ll; t0++,vsiz++)
540 if (line[t0] == '\t')
541 vsiz += 7;
542 else if (icntrl(line[t0]))
543 vsiz++;
544 vbuf = zalloc(vsiz);
545 strcpy(vbuf,pmpt);
546 vp = vbuf+pptlen;
547 for (t0 = 0; t0 != ll; t0++)
548 {
549 if (line[t0] == '\t')
550 do
551 *vp++ = ' ';
552 while ((vp-vbuf) & 7);
553 else if (line[t0] == '\n')
554 {
555 *vp++ = '\\';
556 *vp++ = 'n';
557 }
558 else if (line[t0] == 0x7f)
559 {
560 *vp++ = '^';
561 *vp++ = '?';
562 }
563 else if (icntrl(line[t0]))
564 {
565 *vp++ = '^';
566 *vp++ = line[t0] | '@';
567 }
568 else
569 *vp++ = line[t0];
570 if (t0 == cs)
571 nvcs = vp-vbuf-1;
572 }
573 if (t0 == cs)
574 nvcs = vp-vbuf;
575 *vp = '\0';
576 if ((winpos && nvcs < winpos+1) || (nvcs > winpos+winw-1))
577 {
578 if ((winpos = nvcs-(winw/2)) < 0)
579 winpos = 0;
580 }
581 if (winpos)
582 vbuf[winpos] = '<';
583 if (strlen(vbuf+winpos) > winw)
584 {
585 vbuf[winpos+winw-1] = '>';
586 vbuf[winpos+winw] = '\0';
587 }
588 strcpy(nbuf[0],vbuf+winpos);
589 free(vbuf);
590 nvcs -= winpos;
591 for (t0 = 0,vp = *nbuf,op = *obuf; *vp; t0++,vp++)
592 {
593 if (*vp != *op && !(*vp == ' ' && !*op))
594 {
595 singmoveto(t0);
596 putchar(*vp);
597 vcs++;
598 }
599 if (*op)
600 op++;
601 }
602 if (*op)
603 {
604 singmoveto(t0);
605 for (; *op; op++)
606 {
607 putchar(' ');
608 vcs++;
609 }
610 }
611 singmoveto(nvcs);
612 qbuf = nbuf;
613 nbuf = obuf;
614 obuf = qbuf;
615 fflush(stdout);
616}
617
618void singmoveto(pos) /**/
619int pos;
620{
621 while (pos < vcs)
622 {
623 vcs--;
624 putchar('\b');
625 }
626 while (pos > vcs)
627 {
628 putchar(nbuf[0][vcs]);
629 vcs++;
630 }
631}
632
633int streqct(s,t) /**/
634char *s;char *t;
635{
636int ct = 0;
637
638 while (*s && *s == *t) s++,t++,ct++;
639 return ct;
640}
641