/************************************************************************ * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * * provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ************************************************************************/ /* * Modified: October 1988 by T.R.Hageman */ #include "jove.h" RCS("$Id: move.c,v 14.30.0.10 1994/05/09 09:04:17 tom Exp tom $") #include "ctype.h" #include "re.h" /* this kludge to determine whether ForChar was invoked directly */ #define DIRECT_CMD (LastCmd->Type & ARG(0x80)) /* Move over characters. Bidirectional. */ DEF_CMD( "backward-character", ForChar, NEGATE|ARG(0x80) ); DEF_CMD( "forward-character", ForChar, ARG(0x80) ) { register Buffer *cb = curbuf; register int num; if ((num = exp) <= 0) { /* backward move is simple. */ while ((cb->b_char += num) < 0) { num = cb->b_char + 1; cb->b_char = 0; /* Go to the previous Line */ if (firstp(cb, cb->b_dot)) break; /* ...except when we're in overwrite mode */ /* AND invoked directly by the dispatcher */ if (BufMinorMode(cb, OverWrite) && DIRECT_CMD && exp_p != YES_NODIGIT) break; SetLine(cb->b_dot->l_prev); cb->b_char = strlen(linebuf); } } else { /* forward move is more complicated. */ register char *cp = &linebuf[cb->b_char]; do { if (*cp++) continue; /* Go to the next Line */ --cp; /* ...except when we're in overwrite mode */ /* AND invoked directly by the dispatcher */ if (BufMinorMode(cb, OverWrite) && DIRECT_CMD && exp_p != YES_NODIGIT) { ins_c(' ', cp, 0, num, (int)(&linebuf[LBSIZE] - cp)); cp += num; break; } if (Asking) { /* This avoids losing the line when we're editing minibuf. */ break; } if (lastp(cb, cb->b_dot)) break; SetLine(cb->b_dot->l_next); cp = linebuf; } while (--num); cb->b_char = cp - linebuf; } } DEF_CMD( "beginning-of-line", Bol, NO ) { curchar = 0; } DEF_CMD( "end-of-line", Eol, NO ) { curchar = strlen(linebuf); } DEF_CMD( "end-of-file", Eof, NO ) { PushPntp(curbuf->b_last); ToLast(); } DEF_CMD( "beginning-of-file", Bof, NO ) { PushPntp(curbuf->b_first); ToFirst(); } /* moves NUM lines down (up if NUM < 0) */ void line_move(num) { register Buffer *cb = curbuf; register Line *line; line = next_line(cb->b_dot, num); if (line == cb->b_dot) if (num <= 0) cb->b_char = 0; /* Bol(); */ else Eol(); else SetLine(line); /* curline is in linebuf now */ } /* * Move over lines. Bidirectional. * (we don't use the above `line_move' since we want to line up with the * column of the current line, and some other funny stuff in Overwrite mode) */ DEF_CMD( "previous-line", NextLine, NEGATE ); DEF_CMD( "next-line", NextLine, NO ) { extern void AskNextLine __(( void )); static int line_pos; register Buffer *cb = curbuf; register Line *line; register int num; if (Asking) { AskNextLine(); return; } if ((num = exp) == 0) return; this_cmd = LINECMD; if (last_cmd != LINECMD) line_pos = calc_pos(linebuf, cb->b_char); line = next_line(cb->b_dot, num); if (line == cb->b_dot) { if (num < 0) { if (cb->b_char == 0) complain((char *)0); cb->b_char = 0; /* Bol(); */ return; } if (!BufMinorMode(cb, OverWrite)) { if (eolp(cb)) complain((char *)0); Eol(); return; } /* append empty lines to buffer in Overwrite mode */ do { line = listput(cb, line); SavLine(line, NullStr); } while (--num); } DotTo(line, how_far(lcontents(line), line_pos)); } #ifdef SKIPTABS DEF_INT( "skip-partial-tabs", SkipTabs, V_BOOL ) _IF(def SKIPTABS)_IF(def PRIVATE) ZERO; #endif /* returns what cur_char should be for that position col. If in OverWrite mode, we allow moving ``beyond end-of-line''. (These are handled in DotTo.) */ int how_far(base, col) const char *base; { register const char *lp = base; register int pos = 0, c; /* position to start of tab if between tab stops [TRH] 5-Sep-88 */ while (pos < col && (c = *lp++)) UpdVisPos(pos, c); if (pos != col) { #ifdef SKIPTABS if (pos < col || False(SkipTabs)) #endif lp--; if (pos < col && MinorMode(OverWrite)) lp += col - pos; } return lp - base; } /* Move forward (if dir > 0) or backward (if dir < 0) a word. */ private void to_word __(( int _(dir) )); private void to_word(dir) int dir; { register Buffer *cb = curbuf; register char *cp = &linebuf[cb->b_char]; register Line *lp = cb->b_dot; if (dir > 0) for (;;) { if (*cp) { if (isword(*cp++)) { --cp; break; } continue; } if ((lp = lp->l_next) == NULL) /* eobp() */ break; SetLine(lp); cp = linebuf; } else for (;;) { if (cp > linebuf) { if (isword(*--cp)) { ++cp; break; } continue; } if ((lp = lp->l_prev) == NULL) /* bobp() */ break; SetLine(lp); while (*cp++) ; /* skip to end of line */ } cb->b_char = cp - linebuf; } /* Move over words. Bidirectional */ DEF_CMD( "backward-word", ForWord, NEGATE ); DEF_CMD( "forward-word", ForWord, NO ) { register Buffer *cb = curbuf; register int num; register char *cp; this_cmd = 0; /* Semi kludge to stop some unfavorable behavior */ if ((num = exp) == 0) return; if (num < 0) { do { to_word(BACKWARD); /* Now, move to start of word. */ cp = &linebuf[cb->b_char]; while (cb->b_char > 0 && isword(*--cp)) cb->b_char--; if (bobp(cb)) break; } while (++num); } else { do { to_word(FORWARD); /* Now, move to end of word. */ cp = &linebuf[cb->b_char]; while (*cp != '\0' && isword(*cp++)) cb->b_char++; if (eobp(cb)) break; } while (--num); } } /* Move forward (if dir > 0) or backward (if dir < 0) a sentence. Deals with all the kludgery involved with paragraphs, and moving backwards is particularly yucky. */ DEF_STR( "sentence-end", SentEndRE, 80, V_REGEXP ) = "^[ \t]*$\\|[.?!:][]'\")}]*"; /* How to find the end of a sentence. */ DEF_STR( "sentence-sep", SentSepRE, 40, V_REGEXP ) = "\\{\\{ ,\t\\}[\t ]*,[\t ]*$\\}"; /* What should follow eos. */ private Bufpos *to_sent __(( int _(dir) )); private Bufpos * to_sent(dir) register int dir; { register Buffer *cb = curbuf; register Bufpos *new; Bufpos old; for (;;) { DOTsave(&old); /* [TRH] Sentence search string is now a user-variable. Also moved end-of-sentence check to the front in order to make backward- and forward scans consistent. */ if ((new = dosearch(SentEndRE, dir, YES)) == NULL) { if (dir < 0) ToFirst(); else ToLast(); break; } SetDot(new); /* Consider match at beginning of line a paragraph boundary, so certainly (probably, hopefully) a sentence boundary. Otherwise punctuation *must* be followed by whitespace (or end-of-line) to qualify as a true end-of-sentence. */ if (REbom > 0 && !LookingAt(SentSepRE, linebuf, REeom)) continue; /* Make sure we don't move in the wrong direction. */ if (dir < 0) /* BACKWARD */{ cb->b_char = REeom; /* Avoid problems in Fundamental mode */ to_word(FORWARD); if ((old.p_line == cb->b_dot && old.p_char <= cb->b_char) || (inorder(new->p_line, new->p_char, old.p_line, old.p_char) && inorder(old.p_line, old.p_char, cb->b_dot, cb->b_char))) { SetDot(new); continue; } } else /* FORWARD */ if (REbom == 0) { /* Assume paragraph boundary */ line_move(BACKWARD); Eol(); if (old.p_line == cb->b_dot && old.p_char >= cb->b_char) { to_word(FORWARD); /* Oh brother this is painful */ continue; } } break; } return new; } /* Move over sentences. Bidirectional. */ DEF_CMD( "backward-sentence", Eos, NEGATE ); DEF_CMD( "forward-sentence", Eos, NO ) { register Buffer *cb = curbuf; register int num; register int dir = FORWARD; if ((num = exp) == 0) return; if (num < 0) dir = -dir; do { if (!to_sent(dir)) break; } while (num -= dir); } /*====================================================================== * $Log: move.c,v $ * Revision 14.30.0.10 1994/05/09 09:04:17 tom * ("sentence-end","sentence-sep"): new variables, replace * "sentence-format-string"; (to_sent): use them; (Eos): space-optimization. * * Revision 14.30.0.5 1993/09/26 23:44:36 tom * (ForChar): fix botch in OverWrite mode beyond EOL, introduced in 14.22. * * Revision 14.30 1993/01/27 01:33:21 tom * cleanup whitespace; parenthize || && expr to avoid compiler warnings. * * Revision 14.26 1992/08/26 23:56:56 tom * some optimizations; PRIVATE-ized some Variable defs; add RCS directives. * */