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: }

Defined functions

atdedent defined in line 280; used 1 times
fiddle defined in line 196; used 1 times
hackhack defined in line 251; used 1 times
ins_char defined in line 21; used 2 times
nexthole defined in line 324; used 1 times

Defined variables

rcsid defined in line 2; never used
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3194
Valid CSS Valid XHTML 1.0 Strict