diff options
Diffstat (limited to 'move1.c')
-rw-r--r-- | move1.c | 623 |
1 files changed, 623 insertions, 0 deletions
@@ -0,0 +1,623 @@ +/* move1.c */ + +/* Author: + * Steve Kirkendall + * 14407 SW Teal Blvd. #C + * Beaverton, OR 97005 + * kirkenda@cs.pdx.edu + */ + + +/* This file contains most movement functions */ + +#include "config.h" +#include <ctype.h> +#include "vi.h" + +#ifndef isascii +# define isascii(c) !((c) & ~0x7f) +#endif + +MARK m_updnto(m, cnt, cmd) + MARK m; /* movement is relative to this mark */ + long cnt; /* a numeric argument */ +{ + DEFAULT(cmd == 'G' ? nlines : 1L); + + /* move up or down 'cnt' lines */ + switch (cmd) + { + case ('P'&0x1f): + case '-': + case 'k': + m -= MARK_AT_LINE(cnt); + break; + + case 'G': + if (cnt < 1L || cnt > nlines) + { + msg("Only %ld lines", nlines); + return MARK_UNSET; + } + m = MARK_AT_LINE(cnt); + break; + + default: + m += MARK_AT_LINE(cnt); + } + + /* if that left us screwed up, then fail */ + if (m < MARK_FIRST || markline(m) > nlines) + { + return MARK_UNSET; + } + + return m; +} + +/*ARGSUSED*/ +MARK m_right(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; +} + +/*ARGSUSED*/ +MARK m_left(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; +} + +/*ARGSUSED*/ +MARK m_tocol(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' && !*o_list) + { + col += *o_tabstop; + col -= col % *o_tabstop; + } + else if (UCHAR(*text) < ' ' || *text == '\177') + { + col += 2; + } +#ifndef NO_CHARATTR + 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; +} + +/*ARGSUSED*/ +MARK m_front(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; +} + +/*ARGSUSED*/ +MARK m_rear(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); +} + +#ifndef NO_SENTENCE +/*ARGSUSED*/ +MARK m_fsentence(m, cnt) + MARK m; /* movement is relative to this mark */ + long cnt; /* a numeric argument */ +{ + REG char *text; + REG 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 = m_fword(m, 1L); + + return m; +} + +/*ARGSUSED*/ +MARK m_bsentence(m, cnt) + MARK m; /* movement is relative to this mark */ + long cnt; /* a numeric argument */ +{ + REG char *text; /* used to scan thru text */ + REG 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 = m_fword(m, 1L); + + return m; +} +#endif + +/*ARGSUSED*/ +MARK m_fparagraph(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--; + } +#ifndef NO_SENTENCE + else if (*text == '.') + { + for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2) + { + if (pscn[0] == text[1] && pscn[1] == text[2]) + { + cnt--; + break; + } + } + } +#endif + } + if (l <= nlines) + { + m = MARK_AT_LINE(l); + } + else + { + m = MARK_LAST; + } + return m; +} + +/*ARGSUSED*/ +MARK m_bparagraph(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--; + } +#ifndef NO_SENTENCE + else if (*text == '.') + { + for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2) + { + if (pscn[0] == text[1] && pscn[1] == text[2]) + { + cnt--; + break; + } + } + } +#endif + } + if (l >= 1) + { + m = MARK_AT_LINE(l); + } + else + { + m = MARK_FIRST; + } + return m; +} + +/*ARGSUSED*/ +MARK m_fsection(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; + } +#ifndef NO_SENTENCE + else if (*text == '.') + { + for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2) + { + if (sscn[0] == text[1] && sscn[1] == text[2]) + { + goto BreakBreak; + } + } + } +#endif + } +BreakBreak: + if (l <= nlines) + { + m = MARK_AT_LINE(l); + } + else + { + m = MARK_LAST; + } + return m; +} + +/*ARGSUSED*/ +MARK m_bsection(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; + } +#ifndef NO_SENTENCE + else if (*text == '.') + { + for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2) + { + if (sscn[0] == text[1] && sscn[1] == text[2]) + { + goto BreakBreak; + } + } + } +#endif + } +BreakBreak: + if (l >= 1) + { + m = MARK_AT_LINE(l); + } + else + { + m = MARK_FIRST; + } + return m; +} + + +/*ARGSUSED*/ +MARK m_match(m, cnt) + MARK m; /* movement is relative to this mark */ + long cnt; /* a numeric argument (ignored) */ +{ + long l; + REG char *text; + REG char match; + REG char nest; + REG 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; +} + +/*ARGSUSED*/ +MARK m_tomark(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']; +} + |