1 /*
2 * Text editing windows
3 * Copyright
4 * (C) 1992 Joseph H. Allen
5 *
6 * This file is part of JOE (Joe's Own Editor)
7 */
8 #include "types.h"
9
10 int staen = 0;
11 int staupd = 0;
12 int keepup = 0;
13 int bg_stalin;
14
15 /* Move text window */
16
movetw(W * w,ptrdiff_t x,ptrdiff_t y)17 static void movetw(W *w, ptrdiff_t x, ptrdiff_t y)
18 {
19 BW *bw = (BW *)w->object;
20 TW *tw = (TW *)bw->object;
21
22 if ((y || !staen) && w->h > 1) {
23 if (!tw->staon) { /* Scroll down and shrink */
24 nscrldn(bw->parent->t->t, y, bw->parent->nh + y, 1);
25 }
26 bwmove(bw, x + bw->lincols, y + 1);
27 tw->staon = 1;
28 } else {
29 if (tw->staon) { /* Scroll up and grow */
30 nscrlup(bw->parent->t->t, y, bw->parent->nh + y, 1);
31 }
32 bwmove(bw, x + bw->lincols, y);
33 tw->staon = 0;
34 }
35 }
36
37 /* Resize text window */
38
resizetw(W * w,ptrdiff_t wi,ptrdiff_t he)39 static void resizetw(W *w, ptrdiff_t wi, ptrdiff_t he)
40 {
41 BW *bw = (BW *)w->object;
42 if ((bw->parent->ny || !staen) && he > 1)
43 bwresz(bw, wi - bw->lincols, he - 1);
44 else
45 bwresz(bw, wi - bw->lincols, he);
46 }
47
48 /* Get current context */
49
50 /* Use context.jsf to determine context. The advantage of this vs. the old
51 * method is that the line attribute cache will help find context line
52 * quickly in large files.
53 */
54
55 static struct high_syntax *context_syntax;
56
get_context(BW * bw)57 static const int *get_context(BW *bw)
58 {
59 static int buf1[SAVED_SIZE*2]; /* Double size because we replace \ with \\ */
60 const int *src;
61 P *p;
62 struct lattr_db *db;
63 HIGHLIGHT_STATE st;
64 clear_state(&st);
65 p = pdup(bw->cursor, "get_context");
66 p_goto_bol(p);
67 if (!context_syntax)
68 context_syntax = load_syntax("context");
69 if (context_syntax) {
70 db = find_lattr_db(bw->b, context_syntax);
71 if (db) {
72 st = lattr_get(db, context_syntax, p, p->line + 1);
73 /* Handles last line better */
74 /* st = parse(context_syntax, p, st, p->b->o.charmap); */
75 }
76 }
77 prm(p);
78 src = st.saved_s;
79 buf1[0] = 0;
80 if (src) {
81 ptrdiff_t i, j, spc;
82 /* replace tabs to spaces and remove adjoining spaces */
83 for (i=0,j=0,spc=0; src[i] && i < SAVED_SIZE-1; i++) {
84 if (src[i]=='\t' || src[i]==' ') {
85 if (spc) continue;
86 spc = 1;
87 }
88 else spc = 0;
89 if (src[i]=='\t')
90 buf1[j++] = ' ';
91 else if (src[i]=='\\') {
92 buf1[j++] = '\\';
93 buf1[j++] = '\\';
94 } else if (src[i] != '\r') {
95 buf1[j++] = src[i];
96 }
97 }
98 buf1[j]= '\0';
99 }
100 return buf1;
101 }
102
103 /* Find first line (going backwards) which has 0 indentation level
104 * and is not a comment, blank, or block structuring line. This is
105 * likely to be the line with the function name.
106 *
107 * There are actually two possibilities:
108 *
109 * We want the first line-
110 *
111 * int
112 * foo(int x,int y) {
113 *
114 * }
115 *
116 * We want the last line-
117 *
118 * program foo(input,output);
119 * var a, b, c : real;
120 * begin
121 *
122 */
123
124 #if 0
125 static char *get_context(BW *bw)
126 {
127 P *p = pdup(bw->cursor, "get_context");
128 static char buf1[stdsiz];
129 int i, j, spc;
130
131
132 buf1[0] = 0;
133 /* Find first line with 0 indentation which is not a comment line */
134 do {
135 p_goto_bol(p);
136 if (!pisindent(p) && !pisblank(p)) {
137 /* next: */
138 brzs(p,stdbuf,stdsiz/8); /* To avoid buffer overruns with my_iconv */
139 /* Ignore comment and block structuring lines */
140 if (!(stdbuf[0]=='{' ||
141 (stdbuf[0]=='/' && stdbuf[1]=='*') ||
142 stdbuf[0]=='\f' ||
143 (stdbuf[0]=='/' && stdbuf[1]=='/') ||
144 stdbuf[0]=='#' ||
145 (stdbuf[0]=='b' && stdbuf[1]=='e' && stdbuf[2]=='g' && stdbuf[3]=='i' && stdbuf[4]=='n') ||
146 (stdbuf[0]=='B' && stdbuf[1]=='E' && stdbuf[2]=='G' && stdbuf[3]=='I' && stdbuf[4]=='N') ||
147 (stdbuf[0]=='-' && stdbuf[1]=='-') ||
148 stdbuf[0]==';')) {
149 /* zlcpy(buf1, SIZEOF(buf1), stdbuf); */
150 /* replace tabs to spaces and remove adjoining spaces */
151 for (i=0,j=0,spc=0; stdbuf[i]; i++) {
152 if (stdbuf[i]=='\t' || stdbuf[i]==' ') {
153 if (spc) continue;
154 spc = 1;
155 }
156 else spc = 0;
157 if (stdbuf[i]=='\t')
158 buf1[j++] = ' ';
159 else if (stdbuf[i]=='\\') {
160 buf1[j++] = '\\';
161 buf1[j++] = '\\';
162 } else
163 buf1[j++] = stdbuf[i];
164 }
165 buf1[j]= '\0';
166 /* Uncomment to get the last line instead of the first line (see above)
167 if (pprevl(p)) {
168 p_goto_bol(p);
169 if (!pisindent(p) && !pisblank(p))
170 goto next;
171 }
172 */
173 break;
174 }
175
176 }
177 } while (!buf1[0] && pprevl(p));
178
179 prm(p);
180
181 return buf1;
182 }
183 #endif
184
duplicate_backslashes(const char * s,ptrdiff_t len)185 char *duplicate_backslashes(const char *s, ptrdiff_t len)
186 {
187 char *m;
188 ptrdiff_t x, count;
189 for (x = count = 0; x != len; ++x)
190 if (s[x] == '\\')
191 ++count;
192 m = vsmk(len + count);
193 for (x = 0; x != len; ++x) {
194 m = vsadd(m, s[x]);
195 if (s[x] == '\\')
196 m = vsadd(m, '\\');
197 }
198 return m;
199 }
200
stagen(char * stalin,BW * bw,const char * s,char fill)201 char *stagen(char *stalin, BW *bw, const char *s, char fill)
202 {
203 char buf[80];
204 int x;
205 int field;
206 W *w = bw->parent;
207 time_t n=time(NULL);
208 struct tm *cas;
209 cas=localtime(&n);
210
211 stalin = vstrunc(stalin, 0);
212 while (*s) {
213 if (*s == '%' && s[1]) {
214 field = 0;
215 ++s;
216 while (*s >= '0' && *s <= '9' && s[1]) {
217 field = field * 10 + *s - '0';
218 ++s;
219 }
220 switch (*s) {
221 case 'v': /* Version of JOE */
222 {
223 joe_snprintf_1(buf, SIZEOF(buf), "%s", VERSION);
224 stalin = vsncpy(sv(stalin), sz(buf));
225 }
226 break;
227
228 case 'x': /* Context (but only if autoindent is enabled) */
229 {
230 if (bw->o.title) {
231 const int *ts = get_context(bw);
232 if (ts) {
233 /* We need to translate between file's character set to
234 locale */
235 my_iconv1(stdbuf, SIZEOF(stdbuf), locale_map,ts);
236 stalin = vsncpy(sv(stalin), sz(stdbuf));
237 }
238 }
239 }
240 break;
241
242 case 'y':
243 {
244 if (bw->o.syntax) {
245 joe_snprintf_1(buf, SIZEOF(buf), "(%s)", bw->o.syntax->name);
246 stalin = vsncpy(sv(stalin), sz(buf));
247 }
248 }
249 break;
250 case 't':
251 {
252 time_t curtime = time(NULL);
253 int l;
254 char *d = ctime(&curtime);
255
256 l = (d[11] - '0') * 10 + d[12] - '0';
257 if (l > 12)
258 l -= 12;
259 joe_snprintf_1(buf, SIZEOF(buf), "%2.2d", l);
260 if (buf[0] == '0')
261 buf[0] = fill;
262 stalin = vsncpy(sv(stalin), buf, 2);
263 stalin = vsncpy(sv(stalin), d + 13, 3);
264 }
265 break;
266 case 'd':
267 {
268 if (s[1]) switch (*++s) {
269 case 'd' : joe_snprintf_1(buf, SIZEOF(buf), "%02d",cas->tm_mday); break;
270 case 'm' : joe_snprintf_1(buf, SIZEOF(buf), "%02d",cas->tm_mon + 1); break;
271 case 'y' : joe_snprintf_1(buf, SIZEOF(buf), "%02d",cas->tm_year % 100); break;
272 case 'Y' : joe_snprintf_1(buf, SIZEOF(buf), "%04d",cas->tm_year + 1900); break;
273 case 'w' : joe_snprintf_1(buf, SIZEOF(buf), "%d",cas->tm_wday); break;
274 case 'D' : joe_snprintf_1(buf, SIZEOF(buf), "%03d",cas->tm_yday); break;
275 default : buf[0]='d'; buf[1]=*s; buf[2]=0;
276 } else {
277 buf[0]='d'; buf[1]=0;
278 }
279 stalin=vsncpy(sv(stalin),sz(buf));
280 }
281 break;
282
283 case 'E':
284 {
285 char *ch;
286 int l;
287 buf[0]=0;
288 for(l=0;s[l+1] && s[l+1] != '%'; l++) buf[l]=s[l+1];
289 if (s[l+1]=='%' && buf[0]) {
290 buf[l]=0;
291 s+=l+1;
292 ch=getenv(buf);
293 if (ch) stalin=vsncpy(sv(stalin),sz(ch));
294 }
295 }
296 break;
297
298 case 'Z':
299 {
300 const char *ch;
301 int l;
302 buf[0]=0;
303 for(l=0;s[l+1] && s[l+1] != '%'; l++) buf[l]=s[l+1];
304 if (s[l+1]=='%' && buf[0]) {
305 buf[l]=0;
306 s+=l+1;
307 ch=get_status(bw, buf);
308 if (ch) stalin=vsncpy(sv(stalin),sz(ch));
309 }
310 }
311 break;
312
313 case 'u':
314 {
315 time_t curtime = time(NULL);
316 char *d = ctime(&curtime);
317
318 stalin = vsncpy(sv(stalin), d + 11, 5);
319 }
320 break;
321 case 'T':
322 if (bw->o.overtype)
323 stalin = vsadd(stalin, 'O');
324 else
325 stalin = vsadd(stalin, 'I');
326 break;
327 case 'W':
328 if (bw->o.wordwrap)
329 stalin = vsadd(stalin, 'W');
330 else
331 stalin = vsadd(stalin, fill);
332 break;
333 case 'I':
334 if (bw->o.autoindent)
335 stalin = vsadd(stalin, 'A');
336 else
337 stalin = vsadd(stalin, fill);
338 break;
339 case 'X':
340 if (square)
341 stalin = vsadd(stalin, 'X');
342 else
343 stalin = vsadd(stalin, fill);
344 break;
345 case 'n':
346 {
347 if (bw->b->name) {
348 char *tmp = simplify_prefix(bw->b->name);
349 char *tmp1 = duplicate_backslashes(sv(tmp));
350 vsrm(tmp);
351 stalin = vsncpy(sv(stalin), sv(tmp1));
352 vsrm(tmp1);
353 } else {
354 stalin = vsncpy(sv(stalin), sz(joe_gettext(_("Unnamed"))));
355 }
356 }
357 break;
358 case 'm':
359 if (bw->b->changed)
360 stalin = vsncpy(sv(stalin), sz(joe_gettext(_("(Modified)"))));
361 break;
362 case 'R':
363 if (bw->b->rdonly)
364 stalin = vsncpy(sv(stalin), sz(joe_gettext(_("(Read only)"))));
365 break;
366 case '*':
367 if (bw->b->changed)
368 stalin = vsadd(stalin, '*');
369 else
370 stalin = vsadd(stalin, fill);
371 break;
372 case 'r':
373 if (field)
374 #ifdef HAVE_LONG_LONG
375 joe_snprintf_1(buf, SIZEOF(buf), "%-4lld", (long long)(bw->cursor->line + 1));
376 #else
377 joe_snprintf_1(buf, SIZEOF(buf), "%-4ld", (long)(bw->cursor->line + 1));
378 #endif
379 else
380 #ifdef HAVE_LONG_LONG
381 joe_snprintf_1(buf, SIZEOF(buf), "%lld", (long long)(bw->cursor->line + 1));
382 #else
383 joe_snprintf_1(buf, SIZEOF(buf), "%ld", (long)(bw->cursor->line + 1));
384 #endif
385 for (x = 0; buf[x]; ++x)
386 if (buf[x] == ' ')
387 buf[x] = fill;
388 stalin = vsncpy(sv(stalin), sz(buf));
389 break;
390 case 'o':
391 if (field)
392 #ifdef HAVE_LONG_LONG
393 joe_snprintf_1(buf, SIZEOF(buf), "%-4lld", (long long)bw->cursor->byte);
394 #else
395 joe_snprintf_1(buf, SIZEOF(buf), "%-4ld", (long)bw->cursor->byte);
396 #endif
397 else
398 #ifdef HAVE_LONG_LONG
399 joe_snprintf_1(buf, SIZEOF(buf), "%lld", (long long)bw->cursor->byte);
400 #else
401 joe_snprintf_1(buf, SIZEOF(buf), "%ld", (long)bw->cursor->byte);
402 #endif
403 for (x = 0; buf[x]; ++x)
404 if (buf[x] == ' ')
405 buf[x] = fill;
406 stalin = vsncpy(sv(stalin), sz(buf));
407 break;
408 case 'O':
409 if (field)
410 #ifdef HAVE_LONG_LONG
411 joe_snprintf_1(buf, SIZEOF(buf), "%-4llX", (unsigned long long)bw->cursor->byte);
412 #else
413 joe_snprintf_1(buf, SIZEOF(buf), "%-4lX", (unsigned long)bw->cursor->byte);
414 #endif
415 else
416 #ifdef HAVE_LONG_LONG
417 joe_snprintf_1(buf, SIZEOF(buf), "%llX", (unsigned long long)bw->cursor->byte);
418 #else
419 joe_snprintf_1(buf, SIZEOF(buf), "%lX", (unsigned long)bw->cursor->byte);
420 #endif
421 for (x = 0; buf[x]; ++x)
422 if (buf[x] == ' ')
423 buf[x] = fill;
424 stalin = vsncpy(sv(stalin), sz(buf));
425 break;
426 case 'a':
427 if (!piseof(bw->cursor))
428 joe_snprintf_1(buf, SIZEOF(buf), "%3d", brch(bw->cursor));
429 else
430 joe_snprintf_0(buf, SIZEOF(buf), " ");
431 for (x = 0; buf[x]; ++x)
432 if (buf[x] == ' ')
433 buf[x] = fill;
434 stalin = vsncpy(sv(stalin), sz(buf));
435 break;
436 case 'A':
437 if (field)
438 if (!piseof(bw->cursor))
439 joe_snprintf_1(buf, SIZEOF(buf), "%2.2X", brch(bw->cursor));
440 else
441 joe_snprintf_0(buf, SIZEOF(buf), " ");
442 else
443 if (!piseof(bw->cursor))
444 joe_snprintf_1(buf, SIZEOF(buf), "%x", brch(bw->cursor));
445 else
446 joe_snprintf_0(buf, SIZEOF(buf), "");
447 for (x = 0; buf[x]; ++x)
448 if (buf[x] == ' ')
449 buf[x] = fill;
450 stalin = vsncpy(sv(stalin), sz(buf));
451 break;
452 case 'c':
453 if (field)
454 #ifdef HAVE_LONG_LONG
455 joe_snprintf_1(buf, SIZEOF(buf), "%-3lld", (long long)(piscol(bw->cursor) + 1));
456 #else
457 joe_snprintf_1(buf, SIZEOF(buf), "%-3ld", (long)(piscol(bw->cursor) + 1));
458 #endif
459 else
460 #ifdef HAVE_LONG_LONG
461 joe_snprintf_1(buf, SIZEOF(buf), "%lld", (long long)(piscol(bw->cursor) + 1));
462 #else
463 joe_snprintf_1(buf, SIZEOF(buf), "%ld", (long)(piscol(bw->cursor) + 1));
464 #endif
465 for (x = 0; buf[x]; ++x)
466 if (buf[x] == ' ')
467 buf[x] = fill;
468 stalin = vsncpy(sv(stalin), sz(buf));
469 break;
470 case 'p':
471 if (bw->b->eof->byte >= 1024*1024)
472 #ifdef HAVE_LONG_LONG
473 joe_snprintf_1(buf, SIZEOF(buf), "%3lld", ((long long)bw->cursor->byte >> 10) * 100 / ((long long)bw->b->eof->byte >> 10));
474 #else
475 joe_snprintf_1(buf, SIZEOF(buf), "%3ld", ((long)bw->cursor->byte >> 10) * 100 / ((long)bw->b->eof->byte >> 10));
476 #endif
477 else if (bw->b->eof->byte)
478 #ifdef HAVE_LONG_LONG
479 joe_snprintf_1(buf, SIZEOF(buf), "%3lld", (long long)bw->cursor->byte * 100 / (long long)bw->b->eof->byte);
480 #else
481 joe_snprintf_1(buf, SIZEOF(buf), "%3ld", (long)bw->cursor->byte * 100 / (long)bw->b->eof->byte);
482 #endif
483 else
484 joe_snprintf_0(buf, SIZEOF(buf), "100");
485 for (x = 0; buf[x]; ++x)
486 if (buf[x] == ' ')
487 buf[x] = fill;
488 stalin = vsncpy(sv(stalin), sz(buf));
489 break;
490 case 'l':
491 if (field)
492 #ifdef HAVE_LONG_LONG
493 joe_snprintf_1(buf, SIZEOF(buf), "%-4lld", (long long)(bw->b->eof->line + 1));
494 #else
495 joe_snprintf_1(buf, SIZEOF(buf), "%-4ld", (long)(bw->b->eof->line + 1));
496 #endif
497 else
498 #ifdef HAVE_LONG_LONG
499 joe_snprintf_1(buf, SIZEOF(buf), "%lld", (long long)(bw->b->eof->line + 1));
500 #else
501 joe_snprintf_1(buf, SIZEOF(buf), "%ld", (long)(bw->b->eof->line + 1));
502 #endif
503 for (x = 0; buf[x]; ++x)
504 if (buf[x] == ' ')
505 buf[x] = fill;
506 stalin = vsncpy(sv(stalin), sz(buf));
507 break;
508 case 'k':
509 {
510 ptrdiff_t i;
511 char *mycpos = buf;
512
513 buf[0] = 0;
514 if (w->kbd->x && w->kbd->seq[0])
515 for (i = 0; i != w->kbd->x; ++i) {
516 char c = w->kbd->seq[i] & 127;
517
518 if (c < 32) {
519 mycpos[0] = '^';
520 mycpos[1] = (char)(c + '@');
521 mycpos += 2;
522 } else if (c == 127) {
523 mycpos[0] = '^';
524 mycpos[1] = '?';
525 mycpos += 2;
526 } else {
527 mycpos[0] = c;
528 mycpos += 1;
529 }
530 }
531 *mycpos++ = fill;
532 while (mycpos - buf < 4)
533 *mycpos++ = fill;
534 stalin = vsncpy(sv(stalin), buf, mycpos - buf);
535 }
536 break;
537 case 'S':
538 if (bw->b->pid)
539 stalin = vsncpy(sv(stalin), sz(joe_gettext(_("*SHELL*"))));
540 break;
541 case 'M':
542 if (recmac) {
543 joe_snprintf_1(buf, SIZEOF(buf), joe_gettext(_("(Macro %d recording...)")), recmac->n);
544 stalin = vsncpy(sv(stalin), sz(buf));
545 }
546 break;
547 case 'e':
548 stalin = vsncpy(sv(stalin), sz(bw->b->o.charmap->name));
549 break;
550 case 'b':
551 stalin = vsncpy(sv(stalin), sz(locale_map->name));
552 break;
553 case 'w':
554 if (!piseof(bw->cursor)) {
555 joe_snprintf_1(buf, SIZEOF(buf), "%d", joe_wcwidth(bw->o.charmap->type, brch(bw->cursor)));
556 stalin = vsncpy(sv(stalin), sz(buf));
557 }
558 break;
559 default:
560 stalin = vsadd(stalin, *s);
561 }
562 } else
563 stalin = vsadd(stalin, *s);
564 ++s;
565 }
566 return stalin;
567 }
568
disptw(W * w,int flg)569 static void disptw(W *w, int flg)
570 {
571 BW *bw = (BW *)w->object;
572 TW *tw = (TW *)bw->object;
573 int newcols = calclincols(bw);
574 int linchg = 0;
575
576 if (bw->lincols != newcols) {
577 bw->lincols = newcols;
578 resizetw(w, w->w, w->h);
579 movetw(w, w->x, w->y);
580 bwfllw(w);
581 linchg = 1;
582 }
583
584 if (bw->o.hex) {
585 w->cury = TO_DIFF_OK((bw->cursor->byte-bw->top->byte)/16 + bw->y - w->y);
586 w->curx = TO_DIFF_OK((bw->cursor->byte-bw->top->byte)%16 + 60 - bw->offset);
587 } else {
588 w->cury = TO_DIFF_OK(bw->cursor->line - bw->top->line + bw->y - w->y);
589 w->curx = TO_DIFF_OK(bw->cursor->xcol - bw->offset + newcols);
590 }
591
592 if ((staupd || keepup || bw->cursor->line != tw->prevline || bw->b->changed != tw->changed || bw->b != tw->prev_b) && (w->y || !staen) && w->h > 1) {
593 char fill;
594
595 tw->prevline = bw->cursor->line;
596 tw->changed = bw->b->changed;
597 tw->prev_b = bw->b;
598 if (bw->o.rmsg[0])
599 fill = bw->o.rmsg[0];
600 else
601 fill = ' ';
602 tw->stalin = stagen(tw->stalin, bw, bw->o.lmsg, fill);
603 tw->staright = stagen(tw->staright, bw, bw->o.rmsg, fill);
604 if (fmtlen(tw->staright) < w->w) {
605 ptrdiff_t x = fmtpos(tw->stalin, w->w - fmtlen(tw->staright));
606
607 if (x > sLEN(tw->stalin))
608 tw->stalin = vsfill(sv(tw->stalin), fill, x - sLEN(tw->stalin));
609 tw->stalin = vsncpy(tw->stalin, fmtpos(tw->stalin, w->w - fmtlen(tw->staright)), sv(tw->staright));
610 }
611 tw->stalin = vstrunc(tw->stalin, fmtpos(tw->stalin, w->w));
612 genfmt(w->t->t, w->x, w->y, 0, tw->stalin, bg_stalin, 0, 0);
613 w->t->t->updtab[w->y] = 0;
614 }
615
616 if (flg) {
617 if (bw->o.hex)
618 bwgenh(bw);
619 else
620 bwgen(bw, bw->o.linums, linchg);
621 }
622 }
623
624 /* Split current window */
625
iztw(TW * tw,ptrdiff_t y)626 static void iztw(TW *tw, ptrdiff_t y)
627 {
628 tw->stalin = NULL;
629 tw->staright = NULL;
630 tw->changed = -1;
631 tw->prevline = -1;
632 tw->staon = (!staen || y);
633 tw->prev_b = 0;
634 }
635
usplitw(W * w,int k)636 int usplitw(W *w, int k)
637 {
638 BW *bw;
639 ptrdiff_t newh = getgrouph(w);
640 W *neww;
641 TW *newtw;
642 BW *newbw;
643 WIND_BW(bw, w);
644
645 dostaupd = 1;
646 if (newh / 2 < FITHEIGHT)
647 return -1;
648 neww = wcreate(w->t, w->watom, findbotw(w), NULL, w, newh / 2 + (newh & 1), NULL, NULL);
649 if (!neww)
650 return -1;
651 // wfit(neww->t);
652 neww->object = (void *) (newbw = bwmk(neww, bw->b, 0));
653 ++bw->b->count;
654 newbw->offset = bw->offset;
655 newbw->object = (void *) (newtw = (TW *) joe_malloc(SIZEOF(TW)));
656 iztw(newtw, neww->y);
657 pset(newbw->top, bw->top);
658 pset(newbw->cursor, bw->cursor);
659 newbw->cursor->xcol = bw->cursor->xcol;
660 neww->t->curwin = neww;
661 wfit(neww->t);
662 return 0;
663 }
664
uduptw(W * w,int k)665 int uduptw(W *w, int k)
666 {
667 BW *bw;
668 ptrdiff_t newh = getgrouph(w);
669 W *neww;
670 TW *newtw;
671 BW *newbw;
672 WIND_BW(bw, w);
673
674 dostaupd = 1;
675 neww = wcreate(w->t, w->watom, findbotw(w), NULL, NULL, newh, NULL, NULL);
676 if (!neww)
677 return -1;
678 if (demotegroup(w))
679 neww->t->topwin = neww;
680 neww->object = (void *) (newbw = bwmk(neww, bw->b, 0));
681 ++bw->b->count;
682 newbw->offset = bw->offset;
683 newbw->object = (void *) (newtw = (TW *) joe_malloc(SIZEOF(TW)));
684 iztw(newtw, neww->y);
685 pset(newbw->top, bw->top);
686 pset(newbw->cursor, bw->cursor);
687 newbw->cursor->xcol = bw->cursor->xcol;
688 neww->t->curwin = neww;
689 wfit(w->t);
690 return 0;
691 }
692
instw(W * w,B * b,off_t l,off_t n,int flg)693 static void instw(W *w, B *b, off_t l, off_t n, int flg)
694 {
695 BW *bw = (BW *)w->object;
696 if (b == bw->b)
697 bwins(bw, l, n, flg);
698 }
699
deltw(W * w,B * b,off_t l,off_t n,int flg)700 static void deltw(W *w, B *b, off_t l, off_t n, int flg)
701 {
702 BW *bw = (BW *)w->object;
703 if (b == bw->b)
704 bwdel(bw, l, n, flg);
705 }
706
707 WATOM watomtw = {
708 "main",
709 disptw,
710 bwfllw,
711 NULL,
712 rtntw,
713 utypew,
714 resizetw,
715 movetw,
716 instw,
717 deltw,
718 TYPETW
719 };
720
abortit(W * w,int k)721 int abortit(W *w, int k)
722 {
723 BW *bw;
724 TW *tw;
725 B *b;
726 WIND_BW(bw, w);
727 if (bw->parent->watom != &watomtw)
728 return wabort(bw->parent);
729 if (bw->b->pid && bw->b->count==1)
730 return ukillpid(bw->parent, 0);
731 w = bw->parent;
732 tw = (TW *) bw->object;
733 /* If only one main window on the screen... */
734 if (countmain(w->t) == 1)
735 /* Replace it with an orphaned buffer if there are any */
736 if ((b = borphan()) != NULL) {
737 void *object = bw->object;
738 /* FIXME: Shouldn't we wabort() and wcreate here to kill
739 any prompt windows? */
740
741 bwrm(bw);
742 w->object = (void *) (bw = bwmk(w, b, 0));
743 wredraw(bw->parent);
744 bw->object = object;
745 bw = (BW *)w->object;
746 bw->cursor->xcol = piscol(bw->cursor);
747 return 0;
748 }
749 bwrm(bw);
750 vsrm(tw->stalin);
751 joe_free(tw);
752 w->object = NULL;
753 wabort(w); /* Eliminate this window and it's children */
754 return 0;
755 }
756
757 /* User routine for aborting a text window */
758
naborttw(W * w,int k,void * object,int * notify)759 static int naborttw(W *w, int k, void *object, int *notify)
760 {
761 BW *bw = (BW *)w->object;
762 if (notify)
763 *notify = 1;
764 if (k != YES_CODE && !yncheck(yes_key, k))
765 return -1;
766
767 if (bw->b->count == 1)
768 genexmsg(bw, 0, NULL);
769 return abortit(bw->parent, 0);
770 }
771
naborttw1(W * w,int k,void * object,int * notify)772 static int naborttw1(W *w, int k, void *object, int *notify)
773 {
774 BW *bw = (BW *)w->object;
775 if (notify)
776 *notify = 1;
777 if (k != YES_CODE && !yncheck(yes_key, k))
778 return -1;
779
780 if (!exmsg) genexmsg(bw, 0, NULL);
781 return abortit(bw->parent, 0);
782 }
783
wpop(BW * bw)784 static B *wpop(BW *bw)
785 {
786 B *b;
787 struct bstack *e = bw->parent->bstack;
788 b = e->b;
789 if (b->oldcur) prm(b->oldcur);
790 if (b->oldtop) prm(b->oldtop);
791 b->oldcur = e->cursor;
792 b->oldtop = e->top;
793 bw->parent->bstack = e->next;
794 free(e);
795 --b->count;
796 return b;
797 }
798
799 /* Pop, or do nothing if no window on stack */
upopabort(W * w,int k)800 int upopabort(W *w, int k)
801 {
802 BW *bw;
803 WIND_BW(bw, w);
804 if (bw->parent->bstack) {
805 int rtn;
806 B *b = wpop(bw);
807 w = bw->parent;
808 rtn = get_buffer_in_window(bw, b);
809 bw = (BW *)w->object;
810 bw->cursor->xcol = piscol(bw->cursor);
811 return rtn;
812 } else {
813 return 0;
814 }
815 }
816
817 /* k is last character types which lead to uabort. If k is -1, it means uabort
818 was called internally, and not by the user: which means uabort will not send
819 Ctrl-C to process */
uabort(W * w,int k)820 int uabort(W *w, int k)
821 {
822 BW *bw;
823 if (w->watom != &watomtw)
824 return wabort(w);
825 WIND_BW(bw, w);
826 if (markv(0) && markb->b == bw->b) {
827 prm(markk);
828 markk = 0;
829 updall();
830 return 0;
831 }
832 if (bw->parent->bstack) {
833 int rtn;
834 B *b = wpop(bw);
835 w = bw->parent;
836 rtn = get_buffer_in_window(bw, b);
837 bw = (BW *)w->object;
838 bw->cursor->xcol = piscol(bw->cursor);
839 return rtn;
840 }
841 if (bw->b->pid && bw->b->count==1)
842 return ukillpid(bw->parent, 0);
843 if (bw->b->changed && bw->b->count == 1 && !bw->b->scratch)
844 if (mkqw(w, sz(joe_gettext(_("Lose changes to this file (y,n,%{abort})? "))), naborttw, NULL, NULL, NULL))
845 return 0;
846 else
847 return -1;
848 else
849 return naborttw(bw->parent, YES_CODE, NULL, NULL);
850 }
851
ucancel(W * w,int k)852 int ucancel(W *w, int k)
853 {
854 if (w->watom != &watomtw) {
855 wabort(w);
856 return 0;
857 } else
858 return uabort(w, k);
859 }
860
861 /* Same as above, but only calls genexmsg if nobody else has */
862
uabort1(W * w,int k)863 int uabort1(W *w, int k)
864 {
865 BW *bw;
866 if (w->watom != &watomtw)
867 return wabort(w);
868 bw = (BW *)w->object;
869 if (bw->b->pid && bw->b->count==1)
870 return ukillpid(bw->parent, 0);
871 if (bw->b->changed && bw->b->count == 1 && !bw->b->scratch)
872 if (mkqw(w, sz(joe_gettext(_("Lose changes to this file (y,n,%{abort})? "))), naborttw1, NULL, NULL, NULL))
873 return 0;
874 else
875 return -1;
876 else
877 return naborttw1(w, YES_CODE, NULL, NULL);
878 }
879
880 /* Abort buffer without prompting: just fail if this is last window on buffer */
881
uabortbuf(W * w,int k)882 int uabortbuf(W *w, int k)
883 {
884 BW *bw;
885 B *b;
886
887 WIND_BW(bw, w);
888
889 if (bw->b->pid && bw->b->count==1)
890 return ukillpid(w, 0);
891
892 if (okrepl(bw))
893 return -1;
894
895 if ((b = borphan()) != NULL) {
896 void *object = bw->object;
897
898 bwrm(bw);
899 w->object = (void *) (bw = bwmk(w, b, 0));
900 wredraw(bw->parent);
901 bw->object = object;
902 return 0;
903 }
904
905 return naborttw(w, YES_CODE, NULL, NULL);
906 }
907
908 /* Kill current window (orphans buffer) */
909
utw0(W * w,int k)910 int utw0(W *w, int k)
911 {
912 BW *bw;
913 w = w->main;
914 bw = (BW *)w->object;
915
916 if (w->bstack)
917 return uabort(w, -1);
918 if (countmain(w->t) == 1)
919 return -1;
920 if (bw->b->count == 1)
921 orphit(bw);
922 return uabort(w, -1);
923 }
924
925 /* Kill all other windows (orphans buffers) */
926
utw1(W * w,int k)927 int utw1(W *w, int k)
928 {
929 W *starting = w;
930 W *mainw = starting->main;
931 Screen *t = mainw->t;
932 int myyn;
933
934 do {
935 myyn = 0;
936 loop:
937 do {
938 wnext(t);
939 } while (t->curwin->main == mainw && t->curwin != starting);
940 if (t->curwin->main != mainw) {
941 utw0(t->curwin->main, 0);
942 myyn = 1;
943 goto loop;
944 }
945 } while (myyn);
946 return 0;
947 }
948
setline(B * b,off_t line)949 void setline(B *b, off_t line)
950 {
951 W *w = maint->curwin;
952
953 do {
954 if (w->watom->what == TYPETW) {
955 BW *bw = (BW *)w->object;
956
957 if (bw->b == b) {
958 off_t oline = bw->top->line;
959
960 /* pline(bw->top, line); */
961 pline(bw->cursor, line);
962 if (!bw->b->err)
963 bw->b->err = pdup(bw->cursor, "setline");
964 pline(bw->b->err, line);
965 if (w->y >= 0 && bw->top->line > oline && bw->top->line - oline < bw->h)
966 nscrlup(w->t->t, bw->y, bw->y + bw->h, (int) (bw->top->line - oline));
967 else if (w->y >= 0 && bw->top->line < oline && oline - bw->top->line < bw->h)
968 nscrldn(w->t->t, bw->y, bw->y + bw->h, (int) (oline - bw->top->line));
969 msetI(bw->t->t->updtab + bw->y, 1, bw->h);
970 }
971 }
972 } while ((w = w->link.next) != maint->curwin);
973 /* In case error buffer was orphaned */
974 if (errbuf == b && b->oldcur) {
975 pline(b->oldcur, line);
976 if (!b->err)
977 b->err = pdup(b->oldcur, ("setline1"));
978 pline(b->err, line);
979 }
980 }
981
982 /* Create a text window. It becomes the last window on the screen */
983
wmktw(Screen * t,B * b)984 BW *wmktw(Screen *t, B *b)
985 {
986 W *w;
987 BW *bw;
988 TW *tw;
989
990 w = wcreate(t, &watomtw, NULL, NULL, NULL, t->h, NULL, NULL);
991 wfit(w->t);
992 w->object = (void *) (bw = bwmk(w, b, 0));
993 bw->object = (void *) (tw = (TW *) joe_malloc(SIZEOF(TW)));
994 iztw(tw, w->y);
995 return bw;
996 }
997