|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: scrn.c,v 2.5 85/08/22 16:07:10 timo Exp $";
3:
4: /*
5: * B editor -- Screen management package, higher level routines.
6: */
7:
8: #include "b.h"
9: #include "erro.h"
10: #include "bobj.h"
11: #include "node.h"
12: #include "supr.h"
13: #include "gram.h"
14: #include "cell.h"
15:
16:
17: extern bool dflag;
18:
19: cell *gettop();
20: extern int focy;
21: extern int focx;
22:
23: Visible int winstart;
24:
25: Visible int winheight;
26: Visible int indent;
27: Visible int llength;
28:
29: Visible bool noscroll;
30: Visible bool nosense;
31:
32: Hidden cell *tops;
33:
34:
35: /*
36: * Actual screen update.
37: */
38:
39: Visible Procedure
40: actupdate(copybuffer, recording, lasttime)
41: value copybuffer;
42: bool recording;
43: bool lasttime; /* Yes if called from final screen update */
44: {
45: register cell *p;
46: cell *top = tops;
47: register int diff;
48: register int curlno;
49: register int delcnt = 0; /* Lines deleted during the process. */
50: /* Used as offset for lines that are on the screen. */
51: int totlines = 0;
52: int topline = 0;
53: int scrlines = 0;
54:
55: if (winstart > 0)
56: growwin();
57: if (winstart <= 0) {
58: top = gettop(tops);
59: for (p = tops; p && p != top; p = p->c_link)
60: ++topline;
61: totlines = topline;
62: }
63: startactupdate(lasttime);
64: focy = Nowhere;
65: for (p = top, curlno = winstart; p && curlno < winheight;
66: curlno += Space(p), p = p->c_link) {
67: ++scrlines;
68: if (lasttime) {
69: p->c_newfocus = No;
70: p->c_newvhole = 0;
71: }
72: if (p->c_onscreen != Nowhere && Space(p) == Oldspace(p)) {
73: /* Old comrade */
74: diff = p->c_onscreen - (curlno+delcnt);
75: /* diff can't be negative due to 'makeroom' below! */
76: if (diff > 0) { /* Get him here */
77: trmscrollup(curlno, winheight, diff);
78: delcnt += diff;
79: }
80: if (p->c_oldfocus || p->c_newfocus
81: || p->c_oldindent != p->c_newindent
82: || p->c_onscreen + Space(p) >= winheight) {
83: delcnt = make2room(p, curlno, delcnt);
84: outline(p, curlno);
85: }
86: }
87: else { /* New guy, make him toe the line */
88: delcnt = makeroom(p, curlno, delcnt);
89: delcnt = make2room(p, curlno, delcnt);
90: outline(p, curlno);
91: }
92: p->c_onscreen = curlno;
93: p->c_oldindent = p->c_newindent;
94: p->c_oldvhole = p->c_newvhole;
95: p->c_oldfocus = p->c_newfocus;
96: }
97: totlines += scrlines;
98: for (; p; p = p->c_link) { /* Count rest and remove old memories */
99: ++totlines;
100: /* This code should never find any garbage?! */
101: #ifndef NDEBUG
102: if (p->c_onscreen != Nowhere)
103: debug("[Garbage removed from screen list]");
104: #endif NDEBUG
105: p->c_onscreen = Nowhere;
106: }
107: trmscrollup(curlno, winheight, -delcnt);
108: curlno += delcnt;
109: if (curlno < winheight) { /* Clear lines beyond end of unit */
110: trmputdata(curlno, winheight-1, 0, "");
111: scrlines += winheight-curlno;
112: }
113: if (!lasttime) {
114: stsline(totlines, topline, scrlines, copybuffer, recording);
115: if (focy != Nowhere)
116: trmsync(focy, focx);
117: else
118: trmsync(winheight, 0);
119: }
120: endactupdate();
121: }
122:
123:
124: /*
125: * Grow the window if not maximum size.
126: */
127:
128: Hidden Procedure
129: growwin()
130: {
131: register int winsize;
132: register int growth;
133: register cell *p;
134:
135: winsize = 0;
136: for (p = tops; p; p = p->c_link)
137: winsize += Space(p);
138: if (winsize <= winheight - winstart)
139: return; /* No need to grow */
140: if (winsize > winheight)
141: winsize = winheight; /* Limit size to maximum available */
142:
143: growth = winsize - (winheight - winstart);
144: trmscrollup(0, winheight - (winstart!=winheight), growth);
145: winstart -= growth;
146: for (p = tops; p; p = p->c_link) {
147: if (p->c_onscreen != Nowhere)
148: p->c_onscreen -= growth;
149: }
150: }
151:
152:
153: /*
154: * Make room for possible insertions.
155: * (If a line is inserted, it may be necessary to delete lines
156: * further on the screen.)
157: */
158:
159: Hidden Procedure
160: makeroom(p, curlno, delcnt)
161: register cell *p;
162: register int curlno;
163: register int delcnt;
164: {
165: register int here = 0;
166: register int need = Space(p);
167: register int amiss;
168: int avail;
169: int diff;
170:
171: Assert(p);
172: do {
173: p = p->c_link;
174: if (!p)
175: return delcnt;
176: } while (p->c_onscreen == Nowhere);
177: here = p->c_onscreen - delcnt;
178: avail = here - curlno;
179: amiss = need - avail;
180: #ifndef NDEBUG
181: if (dflag)
182: debug("[makeroom: curlno=%d, delcnt=%d, here=%d, avail=%d, amiss=%d]",
183: curlno, delcnt, here, avail, amiss);
184: #endif NDEBUG
185: if (amiss <= 0)
186: return delcnt;
187: if (amiss > delcnt) {
188: for (; p; p = p->c_link) {
189: if (p->c_onscreen != Nowhere) {
190: diff = amiss-delcnt;
191: if (p->c_onscreen - delcnt - here < diff)
192: diff = p->c_onscreen - delcnt - here;
193: if (diff > 0) {
194: trmscrollup(here, winheight, diff);
195: delcnt += diff;
196: }
197: p->c_onscreen += -delcnt + amiss;
198: here = p->c_onscreen - amiss;
199: if (p->c_onscreen >= winheight)
200: p->c_onscreen = Nowhere;
201: }
202: here += Space(p);
203: }
204: /* Now for all p encountered whose p->c_onscreen != Nowhere,
205: /* p->c_onscreen - amiss is its actual position. */
206: if (amiss > delcnt) {
207: trmscrollup(winheight - amiss, winheight, amiss-delcnt);
208: delcnt = amiss;
209: }
210: }
211: /* Now amiss <= delcnt */
212: trmscrollup(curlno + avail, winheight, -amiss);
213: return delcnt - amiss;
214: }
215:
216:
217: /*
218: * Addition to makeroom - make sure the status line is not overwritten.
219: * Returns new delcnt, like makeroom does.
220: */
221:
222: Hidden int
223: make2room(p, curlno, delcnt)
224: cell *p;
225: int curlno;
226: int delcnt;
227: {
228: int nextline = curlno + Space(p);
229: int sline = winheight - delcnt;
230: int diff;
231:
232: if (sline < curlno) {
233: #ifndef NDEBUG
234: debug("[Status line overwritten]");
235: #endif NDEBUG
236: return delcnt;
237: }
238: if (nextline > winheight)
239: nextline = winheight;
240: diff = nextline - sline;
241: if (diff > 0) {
242: trmscrollup(sline, winheight, -diff);
243: delcnt -= diff;
244: }
245: return delcnt;
246:
247: }
248:
249:
250: /*
251: * Routine called for every change in the screen.
252: */
253:
254: Visible Procedure
255: virtupdate(oldep, newep, highest)
256: environ *oldep;
257: environ *newep;
258: int highest;
259: {
260: environ old;
261: environ new;
262: register int oldlno;
263: register int newlno;
264: register int oldlcnt;
265: register int newlcnt;
266: register int i;
267:
268: if (!oldep) {
269: highest = 1;
270: trmputdata(winstart, winheight, indent, "");
271: discard(tops);
272: tops = Cnil;
273: Ecopy(*newep, old);
274: }
275: else {
276: Ecopy(*oldep, old);
277: }
278: Ecopy(*newep, new);
279:
280: savefocus(&new);
281:
282: oldlcnt = fixlevels(&old, &new, highest);
283: newlcnt = -width(tree(new.focus));
284: if (newlcnt < 0)
285: newlcnt = 0;
286: i = -width(tree(old.focus));
287: if (i < 0)
288: i = 0;
289: newlcnt -= i - oldlcnt;
290: /* Offset newlcnt as much as oldcnt is offset */
291:
292: oldlno = Ycoord(old.focus);
293: newlno = Ycoord(new.focus);
294: if (!atlinestart(&old))
295: ++oldlcnt;
296: else
297: ++oldlno;
298: if (!atlinestart(&new))
299: ++newlcnt;
300: else
301: ++newlno;
302: Assert(oldlno == newlno);
303:
304: tops = replist(tops, build(new.focus, newlcnt), oldlno, oldlcnt);
305:
306: setfocus(tops); /* Incorporate the information saved by savefocus */
307:
308: Erelease(old);
309: Erelease(new);
310: }
311:
312:
313: Hidden bool
314: atlinestart(ep)
315: environ *ep;
316: {
317: register string repr = noderepr(tree(ep->focus))[0];
318:
319: return Fw_negative(repr);
320: }
321:
322:
323: /*
324: * Make the two levels the same, and make sure they both are line starters
325: * if at all possible. Return the OLD number of lines to be replaced.
326: * (0 if the whole unit has no linefeeds.)
327: */
328:
329: Hidden int
330: fixlevels(oldep, newep, highest)
331: register environ *oldep;
332: register environ *newep;
333: register int highest;
334: {
335: register int oldpl = pathlength(oldep->focus);
336: register int newpl = pathlength(newep->focus);
337: register bool intraline = No;
338: register int w;
339:
340: if (oldpl < highest)
341: highest = oldpl;
342: if (newpl < highest)
343: highest = newpl;
344: while (oldpl > highest) {
345: up(&oldep->focus) || Abort();
346: --oldpl;
347: }
348: while (newpl > highest) {
349: up(&newep->focus) || Abort();
350: --newpl;
351: }
352: if (Ycoord(newep->focus) != Ycoord(oldep->focus) ||
353: Level(newep->focus) != Level(newep->focus)) {
354: /* Inconsistency found. */
355: Assert(highest > 1); /* Inconsistency at top level. Stop. */
356: return fixlevels(oldep, newep, 1); /* Try to recover. */
357: }
358: intraline = width(tree(oldep->focus)) >= 0
359: && width(tree(newep->focus)) >= 0;
360: while (!atlinestart(oldep) || !atlinestart(newep)) {
361: /* Find beginning of lines for both */
362: if (!up(&newep->focus)) {
363: Assert(!up(&newep->focus));
364: break;
365: }
366: --oldpl;
367: up(&oldep->focus) || Abort();
368: --newpl;
369: }
370: if (intraline)
371: return atlinestart(oldep);
372: w = width(tree(oldep->focus));
373: return w < 0 ? -w : 0;
374: }
375:
376:
377: /*
378: * Initialization code.
379: */
380:
381: Visible Procedure
382: initshow()
383: {
384: int flags = 0;
385: #ifndef NDEBUG
386: if (dflag)
387: fprintf(stderr, "*** initshow();\n\r");
388: #endif NDEBUG
389: if (!trmstart(&winheight, &llength, &flags)) {
390: endunix();
391: exit(2);
392: }
393: noscroll = (flags&2) == 0;
394: nosense = (flags&8) == 0;
395: winstart = --winheight;
396: }
397:
398:
399: /*
400: * Routine to move the cursor to the first line after the just edited
401: * document. (Called after each editing action.)
402: */
403:
404: Visible Procedure
405: endshow()
406: {
407: register cell *p;
408: register int last = winheight;
409:
410: for (p = tops; p; p = p->c_link) {
411: if (p->c_onscreen != Nowhere)
412: last = p->c_onscreen + Oldspace(p);
413: }
414: if (last > winheight)
415: last = winheight;
416: discard(tops);
417: tops = Cnil;
418: trmputdata(last, winheight, 0, "");
419: trmsync(last, 0);
420: trmend();
421: }
422:
423:
424: /*
425: * Translate a cursor position in tree coordinates.
426: *
427: * ***** DOESN'T WORK IF SCREEN INDENT DIFFERS FROM TREE INDENT! *****
428: * (I.e. for lines with >= 80 spaces indentation)
429: */
430:
431: Visible bool
432: backtranslate(py, px)
433: int *py;
434: int *px;
435: {
436: cell *p;
437: int y = *py;
438: int x = *px;
439: int i;
440:
441: for (i = 0, p = tops; p; ++i, p = p->c_link) {
442: if (p->c_onscreen != Nowhere
443: && y >= p->c_onscreen && y < p->c_onscreen + Space(p)) {
444: *px += (y - p->c_onscreen) * llength - indent;
445: if (*px < 0)
446: *px = 0;
447: *py = i;
448: if (p->c_oldvhole && (y > focy || y == focy && x > focx))
449: --*px; /* Correction if beyond Vhole on same logical line */
450: return Yes;
451: }
452: }
453: error(GOTO_OUT);
454: return No;
455: }
456:
457:
458: /*
459: * Set the indent level and window start line.
460: */
461:
462: Visible Procedure
463: setindent(x)
464: int x;
465: {
466: winstart= winheight;
467: indent= x;
468: }
469:
470:
471: /*
472: * Show the command prompt.
473: */
474:
475: Visible Procedure cmdprompt(prompt)
476: string prompt;
477: {
478: setindent(strlen(prompt));
479: trmputdata(winstart, winstart, 0, prompt);
480: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.