/* move1.c */ /* Author: * Steve Kirkendall * 16820 SW Tallac Way * Beaverton, OR 97006 * kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda */ /* This file contains most movement functions */ #include <ctype.h> #include "vi.h" #ifndef isascii # define isascii(c) !((c) & ~0x7f) #endif MARK moveup(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { DEFAULT(1); /* if at top already, don't move */ if (markline(m) - cnt < 1) { return MARK_UNSET; } /* else move up one line */ m -= MARK_AT_LINE(cnt); return m; } MARK movedown(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { DEFAULT(1); /* if at bottom already, don't move */ if (markline(m) + cnt > nlines) { return MARK_UNSET; } /* else move down one line */ m += MARK_AT_LINE(cnt); /* adjust column number */ if (markidx(m) >= plen) { m = (m & ~(BLKSIZE - 1)); if (plen > 0) { m += plen - 1; } } return m; } MARK moveright(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { int idx; /* index of the new cursor position */ DEFAULT(1); /* move to right, if that's OK */ pfetch(markline(m)); idx = markidx(m) + cnt; if (idx < plen) { m += cnt; } else { return MARK_UNSET; } return m; } MARK moveleft(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { DEFAULT(1); /* move to the left, if that's OK */ if (markidx(m) >= cnt) { m -= cnt; } else { return MARK_UNSET; } return m; } MARK movetoline(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric line number */ { /* if no number specified, assume last line */ DEFAULT(nlines); /* if invalid line number, don't move */ if (cnt > nlines) { msg("Line numbers range from 1 to %ld", nlines); return MARK_UNSET; } /* move to first character of the selected line */ m = MARK_AT_LINE(cnt); return m; } MARK movetocol(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { char *text; /* text of the line */ int col; /* column number */ int idx; /* index into the line */ DEFAULT(1); /* internally, columns are numbered 0..COLS-1, not 1..COLS */ cnt--; /* if 0, that's easy */ if (cnt == 0) { m &= ~(BLKSIZE - 1); return m; } /* find that column within the line */ pfetch(markline(m)); text = ptext; for (col = idx = 0; col < cnt && *text; text++, idx++) { if (*text == '\t') { col += *o_tabstop; col -= col % *o_tabstop; } else if (*text >= '\0' && *text < ' ' || *text == '\177') { col += 2; } #ifndef SET_NOCHARATTR else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr) { text += 2; /* plus one more as part of for loop */ } #endif else { col++; } } if (!*text) { return MARK_UNSET; } else { m = (m & ~(BLKSIZE - 1)) + idx; } return m; } MARK movefront(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument (ignored) */ { char *scan; /* move to the first non-whitespace character */ pfetch(markline(m)); scan = ptext; m &= ~(BLKSIZE - 1); while (*scan == ' ' || *scan == '\t') { scan++; m++; } return m; } MARK moverear(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument (ignored) */ { /* Try to move *EXTREMELY* far to the right. It is fervently hoped * that other code will convert this to a more reasonable MARK before * anything tries to actually use it. (See adjmove() in vi.c) */ return m | (BLKSIZE - 1); } MARK movefword(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { register long l; register char *text; register int i; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { i = *text++; /* if we hit the end of the line, continue with next line */ if (!isascii(i) || isalnum(i) || i == '_') { /* include an alphanumeric word */ while (i && (!isascii(i) || isalnum(i) || i == '_')) { i = *text++; } } else { /* include contiguous punctuation */ while (i && isascii(i) && !isalnum(i) && !isspace(i)) { i = *text++; } } /* include trailing whitespace */ while (!i || isascii(i) && isspace(i)) { /* did we hit the end of this line? */ if (!i) { /* move to next line, if there is one */ l++; if (l > nlines) { return MARK_UNSET; } pfetch(l); text = ptext; } i = *text++; } text--; } /* construct a MARK for this place */ m = buildmark(text); return m; } MARK movebword(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { register long l; register char *text; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { text--; /* include preceding whitespace */ while (text < ptext || isascii(*text) && isspace(*text)) { /* did we hit the end of this line? */ if (text < ptext) { /* move to preceding line, if there is one */ l--; if (l <= 0) { return MARK_UNSET; } pfetch(l); text = ptext + plen - 1; } else { text--; } } if (!isascii(*text) || isalnum(*text) || *text == '_') { /* include an alphanumeric word */ while (text >= ptext && (!isascii(*text) || isalnum(*text) || *text == '_')) { text--; } } else { /* include contiguous punctuation */ while (text >= ptext && isascii(*text) && !isalnum(*text) && !isspace(*text)) { text--; } } text++; } /* construct a MARK for this place */ m = buildmark(text); return m; } MARK moveeword(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { register long l; register char *text; register int i; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { text++; i = *text++; /* include preceding whitespace */ while (!i || isascii(i) && isspace(i)) { /* did we hit the end of this line? */ if (!i) { /* move to next line, if there is one */ l++; if (l > nlines) { return MARK_UNSET; } pfetch(l); text = ptext; } i = *text++; } if (!isascii(i) || isalnum(i) || i == '_') { /* include an alphanumeric word */ while (i && (!isascii(i) || isalnum(i) || i == '_')) { i = *text++; } } else { /* include contiguous punctuation */ while (i && isascii(i) && !isalnum(i) && !isspace(i)) { i = *text++; } } text -= 2; } /* construct a MARK for this place */ m = buildmark(text); return m; } MARK movefWord(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { register long l; register char *text; register int i; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { i = *text++; /* if we hit the end of the line, continue with next line */ /* include contiguous non-space characters */ while (i && !isspace(i)) { i = *text++; } /* include trailing whitespace */ while (!i || isascii(i) && isspace(i)) { /* did we hit the end of this line? */ if (!i) { /* move to next line, if there is one */ l++; if (l > nlines) { return MARK_UNSET; } pfetch(l); text = ptext; } i = *text++; } text--; } /* construct a MARK for this place */ m = buildmark(text); return m; } MARK movebWord(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { register long l; register char *text; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { text--; /* include trailing whitespace */ while (text < ptext || isascii(*text) && isspace(*text)) { /* did we hit the end of this line? */ if (text < ptext) { /* move to next line, if there is one */ l--; if (l <= 0) { return MARK_UNSET; } pfetch(l); text = ptext + plen - 1; } else { text--; } } /* include contiguous non-whitespace */ while (text >= ptext && (!isascii(*text) || !isspace(*text))) { text--; } text++; } /* construct a MARK for this place */ m = buildmark(text); return m; } MARK moveeWord(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { register long l; register char *text; register int i; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { text++; i = *text++; /* include preceding whitespace */ while (!i || isascii(i) && isspace(i)) { /* did we hit the end of this line? */ if (!i) { /* move to next line, if there is one */ l++; if (l > nlines) { return MARK_UNSET; } pfetch(l); text = ptext; } i = *text++; } /* include contiguous non-whitespace */ while (i && (!isascii(i) || !isspace(i))) { i = *text++; } text -= 2; } /* construct a MARK for this place */ m = buildmark(text); return m; } MARK movefsentence(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { register char *text; register long l; DEFAULT(1); /* get the current line */ l = markline(m); pfetch(l); text = ptext + markidx(m); /* for each requested sentence... */ while (cnt-- > 0) { /* search forward for one of [.?!] followed by spaces or EOL */ do { /* wrap at end of line */ if (!text[0]) { if (l >= nlines) { return MARK_UNSET; } l++; pfetch(l); text = ptext; } else { text++; } } while (text[0] != '.' && text[0] != '?' && text[0] != '!' || text[1] && (text[1] != ' ' || text[2] && text[2] != ' ')); } /* construct a mark for this location */ m = buildmark(text); /* move forward to the first word of the next sentence */ m = movefword(m, 1L); return m; } MARK movebsentence(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { register char *text; /* used to scan thru text */ register long l; /* current line number */ int flag; /* have we passed at least one word? */ DEFAULT(1); /* get the current line */ l = markline(m); pfetch(l); text = ptext + markidx(m); /* for each requested sentence... */ flag = TRUE; while (cnt-- > 0) { /* search backward for one of [.?!] followed by spaces or EOL */ do { /* wrap at beginning of line */ if (text == ptext) { do { if (l <= 1) { return MARK_UNSET; } l--; pfetch(l); } while (!*ptext); text = ptext + plen - 1; } else { text--; } /* are we moving past a "word"? */ if (text[0] >= '0') { flag = FALSE; } } while (flag || text[0] != '.' && text[0] != '?' && text[0] != '!' || text[1] && (text[1] != ' ' || text[2] && text[2] != ' ')); } /* construct a mark for this location */ m = buildmark(text); /* move to the front of the following sentence */ m = movefword(m, 1L); return m; } MARK movefparagraph(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { char *text; char *pscn; /* used to scan thru value of "paragraphs" option */ long l; DEFAULT(1); for (l = markline(m); cnt > 0 && l++ < nlines; ) { text = fetchline(l); if (!*text) { cnt--; } else if (*text == '.') { for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2) { if (pscn[0] == text[1] && pscn[1] == text[2]) { cnt--; break; } } } } if (l <= nlines) { m = MARK_AT_LINE(l); } else { m = MARK_LAST; } return m; } MARK movebparagraph(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { char *text; char *pscn; /* used to scan thru value of "paragraph" option */ long l; DEFAULT(1); for (l = markline(m); cnt > 0 && l-- > 1; ) { text = fetchline(l); if (!*text) { cnt--; } else if (*text == '.') { for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2) { if (pscn[0] == text[1] && pscn[1] == text[2]) { cnt--; break; } } } } if (l >= 1) { m = MARK_AT_LINE(l); } else { m = MARK_FIRST; } return m; } MARK movefsection(m, cnt, key) MARK m; /* movement is relative to this mark */ long cnt; /* (ignored) */ int key; /* second key stroke - must be ']' */ { char *text; char *sscn; /* used to scan thru value of "sections" option */ long l; /* make sure second key was ']' */ if (key != ']') { return MARK_UNSET; } for (l = markline(m); l++ < nlines; ) { text = fetchline(l); if (*text == '{') { break; } if (*text == '.') { for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2) { if (sscn[0] == text[1] && sscn[1] == text[2]) { goto BreakBreak; } } } } BreakBreak: if (l <= nlines) { m = MARK_AT_LINE(l); } else { m = MARK_LAST; } return m; } MARK movebsection(m, cnt, key) MARK m; /* movement is relative to this mark */ long cnt; /* (ignored) */ int key; /* second key stroke - must be '[' */ { char *text; char *sscn; /* used to scan thru value of "sections" option */ long l; /* make sure second key was '[' */ if (key != '[') { return MARK_UNSET; } for (l = markline(m); l-- > 1; ) { text = fetchline(l); if (*text == '{') { break; } if (*text == '.') { for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2) { if (sscn[0] == text[1] && sscn[1] == text[2]) { goto BreakBreak; } } } } BreakBreak: if (l >= 1) { m = MARK_AT_LINE(l); } else { m = MARK_FIRST; } return m; } MARK movematch(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { long l; register char *text; register char match; register char nest; register int count; /* get the current line */ l = markline(m); pfetch(l); text = ptext + markidx(m); /* search forward within line for one of "[](){}" */ for (match = '\0'; !match && *text; text++) { /* tricky way to recognize 'em in ASCII */ nest = *text; if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[') { match = nest ^ ('[' ^ ']'); } else if ((nest & 0xfe) == '(') { match = nest ^ ('(' ^ ')'); } else { match = 0; } } if (!match) { return MARK_UNSET; } text--; /* search forward or backward for match */ if (match == '(' || match == '[' || match == '{') { /* search backward */ for (count = 1; count > 0; ) { /* wrap at beginning of line */ if (text == ptext) { do { if (l <= 1L) { return MARK_UNSET; } l--; pfetch(l); } while (!*ptext); text = ptext + plen - 1; } else { text--; } /* check the char */ if (*text == match) count--; else if (*text == nest) count++; } } else { /* search forward */ for (count = 1; count > 0; ) { /* wrap at end of line */ if (!*text) { if (l >= nlines) { return MARK_UNSET; } l++; pfetch(l); text = ptext; } else { text++; } /* check the char */ if (*text == match) count--; else if (*text == nest) count++; } } /* construct a mark for this place */ m = buildmark(text); return m; } MARK movetomark(m, cnt, key) MARK m; /* movement is relative to this mark */ long cnt; /* (ignored) */ int key; /* keystroke - the mark to move to */ { /* mark '' is a special case */ if (key == '\'' || key == '`') { if (mark[26] == MARK_UNSET) { return MARK_FIRST; } else { return mark[26]; } } /* if not a valid mark number, don't move */ if (key < 'a' || key > 'z') { return MARK_UNSET; } /* return the selected mark -- may be MARK_UNSET */ if (!mark[key - 'a']) { msg("mark '%c is unset", key); } return mark[key - 'a']; }