/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ static char rcsid[] = "\$Header: move.c,v 2.4 85/08/22 16:05:16 timo Exp \$"; /* * B editor -- Process arrow keys in four directions, plus TAB. */ #include "b.h" #include "bobj.h" #include "node.h" #include "supr.h" #include "gram.h" #define Left (-1) #define Rite 1 /* * Common code for PREVIOUS and NEXT commands. */ Hidden bool prevnext(ep, direction) environ *ep; { node n; node n1; int nch; int i; int len; int sym; string *rp; higher(ep); switch (ep->mode) { case VHOLE: case FHOLE: case ATBEGIN: case ATEND: if (direction == Left) leftvhole(ep); else ritevhole(ep); } for (;;) { n = tree(ep->focus); nch = nchildren(n); rp = noderepr(n); switch (ep->mode) { case ATBEGIN: case ATEND: ep->mode = WHOLE; continue; case VHOLE: case FHOLE: if (direction == Rite) { if (ep->s1&1) len = Fwidth(rp[ep->s1/2]); else { n1 = child(n, ep->s1/2); len = width(n1); } } if (direction == Rite ? ep->s2 >= len : ep->s2 <= 0) { ep->mode = SUBSET; ep->s2 = ep->s1; return nextchar(ep, direction); } ep->s2 += direction; return Yes; case SUBRANGE: if (direction == Rite) { if (ep->s1&1) len = Fwidth(rp[ep->s1/2]); else { n1 = child(n, ep->s1/2); len = width(n1); } } if (direction == Left ? ep->s2 <= 0 : ep->s3 >= len-1) { ep->mode = SUBSET; ep->s2 = ep->s1; return nextchar(ep, direction); } if (direction == Rite) ep->s2 = ++ep->s3; else ep->s3 = --ep->s2; return Yes; case SUBSET: if (direction == Rite ? ep->s2 > 2*nch : ep->s1 <= 1) { ep->mode = WHOLE; continue; } if (direction == Rite) ep->s1 = ++ep->s2; else ep->s2 = --ep->s1; if (ep->s1&1) { if (!Fw_positive(rp[ep->s1/2]) || allspaces(rp[ep->s1/2])) continue; } else { sym = symbol(n); if (downi(&ep->focus, ep->s1/2)) { n = tree(ep->focus); if (((value)n)->type == Tex) s_up(ep); else { if (ep->s1 == 2*nch && direction == Rite && issublist(sym) && samelevel(sym, symbol(n))) { ep->mode = SUBLIST; ep->s3 = 1; return Yes; } ep->mode = WHOLE; if (width(n) == 0) continue; } } } return Yes; case SUBLIST: sym = symbol(n); if (direction == Left) { i = ichild(ep->focus); if (!up(&ep->focus)) return No; higher(ep); n = tree(ep->focus); if (i == nchildren(n) && samelevel(sym, symbol(n))) { ep->s3 = 1; return Yes; } ep->mode = SUBSET; ep->s1 = ep->s2 = 2*i; continue; } for (i = ep->s3; i > 0; --i) if (!downrite(&ep->focus)) return No; /* Sorry... */ if (samelevel(sym, symbol(tree(ep->focus)))) ep->s3 = 1; else ep->mode = WHOLE; return Yes; case WHOLE: i = ichild(ep->focus); if (!up(&ep->focus)) return No; higher(ep); ep->mode = SUBSET; ep->s1 = ep->s2 = 2*i; continue; default: Abort(); } } /* Not reached */ } Visible bool leftarrow(ep) environ *ep; { int w; bool hole; if (narrow(ep)) { while (narrow(ep)) ; return Yes; } hole= ep->mode == WHOLE; /* Can't narrow and still WHOLE: */ /* a real hole which needs some hacking. */ if (!previous(ep)) return No; if (hole) { for (;;) { w= focwidth(ep); if (w >= 0 && w <= 1) break; if (!rnarrow(ep)) return No; } narrow(ep); } else { while (rnarrow(ep)) ; } return Yes; } Visible bool ritearrow(ep) environ *ep; { while (narrow(ep)) ; if (!next(ep)) return No; while (narrow(ep)) ; return Yes; } Visible bool previous(ep) environ *ep; { if (!prevnext(ep, Left)) return No; return Yes; } Visible bool next(ep) environ *ep; { if (!prevnext(ep, Rite)) return No; return Yes; } /* * Position focus at next or previous char relative to current position. * Assume current position given as SUBSET. */ Hidden bool nextchar(ep, direction) register environ *ep; register int direction; { register int ich; register int nch; register node n; node n1; register int len; string *rp; Assert(ep->mode == SUBSET); for (;;) { n = tree(ep->focus); rp = noderepr(n); nch = nchildren(n); if (direction == Left) ep->s2 = --ep->s1; else ep->s1 = ++ep->s2; if (direction == Left ? ep->s1 < 1 : ep->s2 > 2*nch+1) { ich = ichild(ep->focus); if (!up(&ep->focus)) return No; /* *ep is garbage now! */ higher(ep); ep->s1 = ep->s2 = 2*ich; continue; } if (ep->s1&1) { len = Fwidth(rp[ep->s1/2]); if (len > 0) { ep->mode = SUBRANGE; ep->s2 = ep->s3 = direction == Left ? len-1 : 0; return Yes; } continue; } n1 = child(n, ep->s1/2); len = width(n1); if (len == 0) continue; if (!downi(&ep->focus, ep->s1/2)) return No; /* Sorry... */ n = tree(ep->focus); if (((value)n)->type == Tex) { s_up(ep); ep->mode = SUBRANGE; ep->s2 = ep->s3 = direction == Left ? len-1 : 0; return Yes; } if (direction == Left) { nch = nchildren(n); ep->s1 = ep->s2 = 2*(nch+1); } else ep->s1 = ep->s2 = 0; } /* Not reached */ } /* * Up and down arrows. */ Hidden bool updownarrow(ep, yincr) environ *ep; int yincr; { int y, x; while (narrow(ep)) ; y= lineno(ep) + yincr; x= colno(ep); if (!gotoyx(ep, y, x)) return No; gotofix(ep, y, x); while (narrow(ep)) ; return Yes; } Visible bool uparrow(ep) environ *ep; { return updownarrow(ep, -1); } Visible bool downarrow(ep) environ *ep; { return updownarrow(ep, 1); } Visible bool upline(ep) register environ *ep; { register int y; y = lineno(ep); if (y <= 0) return No; if (!gotoyx(ep, y-1, 0)) return No; oneline(ep); return Yes; } Visible bool downline(ep) register environ *ep; { register int w; if (!parent(ep->focus) && ep->mode == ATEND) return No; /* Superfluous? */ w = -focwidth(ep); if (w <= 0) w = 1; if (!gotoyx(ep, lineno(ep) + w, 0)) return No; oneline(ep); return Yes; } /* * ACCEPT command * move to next Hole hole or to end of suggestion or to end of line. */ Visible bool accept(ep) environ *ep; { int i; string repr; shrink(ep); switch (ep->mode) { case ATBEGIN: case ATEND: case FHOLE: case VHOLE: ritevhole(ep); } if (symbol(tree(ep->focus)) == Hole) ep->mode = ATEND; switch (ep->mode) { case ATBEGIN: case SUBLIST: case WHOLE: i = 1; break; case ATEND: i = 2*nchildren(tree(ep->focus)) + 2; break; case SUBRANGE: case VHOLE: case FHOLE: i = ep->s1; if (ep->s2 > 0 && i > 2*nchildren(tree(ep->focus))) ++i; /* Kludge so after E?LSE: the focus moves to ELSE: ? */ break; case SUBSET: i = ep->s1 - 1; break; default: Abort(); } ep->mode = WHOLE; for (;;) { if (i/2 == nchildren(tree(ep->focus))) { repr = noderepr(tree(ep->focus))[i/2]; if (Fw_positive(repr)) break; } if (tabstop(ep, i + 1)) return Yes; i = 2*ichild(ep->focus) + 1; if (!up(&ep->focus)) break; higher(ep); } ep->mode = ATEND; return Yes; } /* * Find suitable tab stops for accept. */ Hidden bool tabstop(ep, i) environ *ep; int i; { node n = tree(ep->focus); int nch; string repr; if (Type(n) == Tex) return No; nch = nchildren(n); if (i/2 > nch) return No; if (symbol(n) == Hole) { ep->mode = WHOLE; return Yes; } if (i < 2) { i = 2; if (width(n) < 0) { repr = noderepr(n)[0]; if (Fw_negative(repr)) { ep->mode = ATBEGIN; leftvhole(ep); return Yes; } } } for (i /= 2; i <= nch; ++i) { s_downi(ep, i); if (tabstop(ep, 1)) return Yes; s_up(ep); } return No; }