summaryrefslogtreecommitdiff
path: root/move1.c
diff options
context:
space:
mode:
Diffstat (limited to 'move1.c')
-rw-r--r--move1.c623
1 files changed, 623 insertions, 0 deletions
diff --git a/move1.c b/move1.c
new file mode 100644
index 0000000..63c98be
--- /dev/null
+++ b/move1.c
@@ -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'];
+}
+