|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: ins2.c,v 2.4 84/10/26 12:08:24 guido Exp $";
3:
4: /*
5: * B editor -- Insert characters from keyboard.
6: */
7:
8: #include "b.h"
9: #include "bobj.h"
10: #include "node.h"
11: #include "supr.h"
12: #include "queu.h"
13: #include "gram.h"
14: #include "tabl.h"
15:
16:
17: /*
18: * Insert a character.
19: */
20:
21: Visible bool
22: ins_char(ep, c, alt_c)
23: register environ *ep;
24: int c;
25: int alt_c;
26: {
27: auto queue q = Qnil;
28: auto queue qf = Qnil;
29: auto value copyout();
30: auto string str;
31: char buf[2];
32: int where;
33: bool spwhere;
34:
35: higher(ep);
36: shrink(ep);
37: if (index("({[`'\"", c) && !ishole(ep)) {
38: /* Surround something. Wonder what will happen! */
39: qf = (queue) copyout(ep);
40: if (!delbody(ep)) {
41: qrelease(qf);
42: return No;
43: }
44: }
45: fixit(ep);
46: ep->changed = Yes;
47: buf[0] = c;
48: buf[1] = 0;
49: if (!ins_string(ep, buf, &q, alt_c))
50: return No;
51: if (!emptyqueue(q) || !emptyqueue(qf)) {
52: /* Slight variation on app_queue */
53: if (!emptyqueue(qf) && emptyqueue(q))
54: ritevhole(ep); /* Wizardry. Why does this work? */
55: spwhere = ep->spflag;
56: ep->spflag = No;
57: where = focoffset(ep);
58: markpath(&ep->focus, 1);
59: ep->spflag = spwhere;
60: if (ep->mode == FHOLE && ep->s2 > 0) {
61: /* If we just caused a suggestion, insert the remains
62: after the suggested text, not after its first character. */
63: str = "";
64: if (!soften(ep, &str, 0)) {
65: ep->mode = ATEND;
66: leftvhole(ep);
67: if (symbol(tree(ep->focus)) == Hole) {
68: ep->mode = ATBEGIN;
69: leftvhole(ep);
70: }
71: }
72: }
73: if (!emptyqueue(q)) { /* Re-insert stuff queued by ins_string */
74: if (!ins_queue(ep, &q, &q))
75: return No;
76: where += spwhere;
77: spwhere = No;
78: }
79: if (!emptyqueue(qf)) { /* Re-insert deleted old focus */
80: firstmarked(&ep->focus, 1) || Abort();
81: fixfocus(ep, where);
82: if (!ins_queue(ep, &qf, &qf))
83: return No;
84: }
85: firstmarked(&ep->focus, 1) || Abort();
86: unmkpath(&ep->focus, 1);
87: ep->spflag = No;
88: fixfocus(ep, where + spwhere);
89: }
90: return Yes;
91: }
92:
93:
94: /*
95: * Insert a newline.
96: */
97:
98: Visible bool
99: ins_newline(ep)
100: register environ *ep;
101: {
102: register node n;
103: register int sym;
104: auto bool mayindent;
105:
106: ep->changed = Yes;
107: if (!fiddle(ep, &mayindent))
108: return No;
109: for (;;) {
110: switch (ep->mode) {
111:
112: case VHOLE:
113: ep->mode = ATEND;
114: continue;
115:
116: case FHOLE:
117: ep->s2 = lenitem(ep);
118: if (!fix_move(ep))
119: return No;
120: continue;
121:
122: case ATEND:
123: if (!joinstring(&ep->focus, "\n", No, 0, mayindent)) {
124: if (!move_on(ep))
125: return No;
126: continue;
127: }
128: s_downi(ep, 2);
129: s_downi(ep, 1);
130: ep->mode = WHOLE;
131: Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
132: return Yes;
133:
134: case ATBEGIN:
135: n = tree(ep->focus);
136: if (Type(n) == Tex) {
137: ep->mode = ATEND;
138: continue;
139: }
140: sym = symbol(n);
141: if (sym == Hole || sym == Optional) {
142: ep->mode = WHOLE;
143: continue;
144: }
145: n = nodecopy(n);
146: if (!fitstring(&ep->focus, "\n", 0)) {
147: if (!down(&ep->focus))
148: ep->mode = ATEND;
149: noderelease(n);
150: continue;
151: }
152: s_downrite(ep);
153: if (fitnode(&ep->focus, n)) {
154: noderelease(n);
155: s_up(ep);
156: s_down(ep);
157: ep->mode = WHOLE;
158: return Yes;
159: }
160: s_up(ep);
161: s_down(ep);
162: if (!fitnode(&ep->focus, n)) {
163: noderelease(n);
164: #ifndef NDEBUG
165: debug("[Sorry, I don't see how to insert a newline here]");
166: #endif NDEBUG
167: return No;
168: }
169: noderelease(n);
170: ep->mode = ATBEGIN;
171: return Yes;
172:
173: case WHOLE:
174: Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
175: if (!fitstring(&ep->focus, "\n", 0)) {
176: ep->mode = ATEND;
177: continue;
178: }
179: s_downi(ep, 1);
180: Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
181: ep->mode = WHOLE;
182: return Yes;
183:
184: default:
185: Abort();
186:
187: }
188: }
189: }
190:
191:
192: /*
193: * Refinement for ins_newline() to do the initial processing.
194: */
195:
196: Hidden bool
197: fiddle(ep, pmayindent)
198: register environ *ep;
199: bool *pmayindent;
200: {
201: register int level;
202: auto string str = "";
203:
204: higher(ep);
205: while (rnarrow(ep))
206: ;
207: fixit(ep);
208: soften(ep, &str, 0);
209: higher(ep);
210: *pmayindent = Yes;
211: if (atdedent(ep)) {
212: *pmayindent = No;
213: s_up(ep);
214: level = Level(ep->focus);
215: delfocus(&ep->focus);
216: if (symbol(tree(ep->focus)) == Hole) {
217: if (hackhack(ep))
218: return Yes;
219: }
220: while (Level(ep->focus) >= level) {
221: if (!nexthole(ep)) {
222: ep->mode = ATEND;
223: break;
224: }
225: }
226: if (ep->mode == ATEND) {
227: leftvhole(ep);
228: ep->mode = ATEND;
229: while (Level(ep->focus) >= level) {
230: if (!up(&ep->focus))
231: return No;
232: }
233: }
234: return Yes;
235: }
236: return Yes;
237: }
238:
239:
240: /*
241: * "Hier komen de houthakkers."
242: *
243: * Incredibly ugly hack to delete a join whose second child begins with \n,
244: * such as a suite after an IF, FOR or WHILE or unit heading.
245: * Inspects the parent node.
246: * If this has rp[0] ands rp[1] both empty, replace it by its first child.
247: * (caller assures this makes sense).
248: * Return Yes if this happened AND rp[1] contained a \t.
249: */
250:
251: Hidden Procedure
252: hackhack(ep)
253: environ *ep;
254: {
255: node n;
256: int ich = ichild(ep->focus);
257: string *rp;
258:
259: if (!up(&ep->focus))
260: return No;
261: higher(ep);
262: rp = noderepr(tree(ep->focus));
263: if (!Fw_zero(rp[0]) || !Fw_zero(rp[1])) {
264: s_downi(ep, ich);
265: return No;
266: }
267: n = nodecopy(firstchild(tree(ep->focus)));
268: delfocus(&ep->focus);
269: replace(&ep->focus, n);
270: ep->mode = ATEND;
271: return rp[1] && rp[1][0] == '\t';
272: }
273:
274:
275: /*
276: * Refinement for fiddle() to find out whether we are at a possible
277: * decrease-indentation position.
278: */
279:
280: Hidden bool
281: atdedent(ep)
282: register environ *ep;
283: {
284: register path pa;
285: register node npa;
286: register int i;
287: register int sym = symbol(tree(ep->focus));
288:
289: if (sym != Hole && sym != Optional)
290: return No;
291: if (ichild(ep->focus) != 1)
292: return No;
293: switch (ep->mode) {
294: case FHOLE:
295: if (ep->s1 != 1 || ep->s2 != 0)
296: return No;
297: break;
298: case ATBEGIN:
299: case WHOLE:
300: case SUBSET:
301: break;
302: default:
303: return No;
304: }
305: pa = parent(ep->focus);
306: if (!pa)
307: return No;
308: npa = tree(pa);
309: if (fwidth(noderepr(npa)[0]) >= 0)
310: return No;
311: for (i = nchildren(npa); i > 1; --i) {
312: sym = symbol(child(npa, i));
313: if (sym != Hole && sym != Optional)
314: return No;
315: }
316: return Yes; /* Sigh! */
317: }
318:
319: /*
320: * Refinement for ins_node() and fiddle() to find the next hole,
321: * skipping blank space only.
322: */
323:
324: Hidden bool
325: nexthole(ep)
326: register environ *ep;
327: {
328: register node n;
329: register int ich;
330: register string repr;
331:
332: do {
333: ich = ichild(ep->focus);
334: if (!up(&ep->focus))
335: return No;
336: higher(ep);
337: n = tree(ep->focus);
338: repr = noderepr(n)[ich];
339: if (!Fw_zero(repr) && !allspaces(repr))
340: return No;
341: } while (ich >= nchildren(n));
342: s_downi(ep, ich+1);
343: return Yes;
344: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.