home *** CD-ROM | disk | FTP | other *** search
- /* input.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 the input() function, which implements vi's INPUT mode */
-
- #include "vi.h"
-
-
- /* This function allows the user to replace an existing (possibly zero-length)
- * chunk of text with typed-in text. It returns the MARK of the last character
- * that the user typed in.
- */
- MARK input(from, to, when)
- MARK from; /* where to start inserting text */
- MARK to; /* extent of text to delete */
- int when; /* either WHEN_VIINP or WHEN_VIREP */
- {
- char key[2]; /* key char followed by '\0' char */
- char *build; /* used in building a newline+indent string */
- char *scan; /* used while looking at the indent chars of a line */
- MARK m;
-
- #ifdef DEBUG
- /* if "from" and "to" are reversed, complain */
- if (from > to)
- {
- msg("ERROR: input(%ld:%d, %ld:%d)",
- markline(from), markidx(from),
- markline(to), markidx(to));
- return MARK_UNSET;
- }
- #endif
-
- key[1] = 0;
-
- /* if we're replacing text with new text, save the old stuff */
- /* (Alas, there is no easy way to save text for replace mode) */
- if (from != to)
- {
- cut(from, to);
- }
-
- ChangeText
- {
- /* if doing a dot command, then reuse the previous text */
- if (doingdot)
- {
- /* delete the text thats there now */
- if (from != to)
- {
- delete(from, to);
- }
-
- cutname('.');
- cursor = paste(from, FALSE, TRUE) + 1L;
- }
- else
- {
- /* if doing a change within the line... */
- if (from != to && markline(from) == markline(to))
- {
- /* mark the end of the text with a "$" */
- change(to - 1, to, "$");
- }
- else
- {
- /* delete the old text right off */
- if (from != to)
- {
- delete(from, to);
- }
- to = from;
- }
-
- /* handle autoindent of the first line, maybe */
- cursor = from;
- if (*o_autoindent && markline(cursor) > 1L && markidx(cursor) == 0)
- {
- /* Only autoindent blank lines. */
- pfetch(markline(cursor));
- if (plen == 0)
- {
- /* Okay, we really want to autoindent */
- pfetch(markline(cursor) - 1L);
- for (scan = ptext, build = tmpblk.c;
- *scan == ' ' || *scan == '\t';
- )
- {
- *build++ = *scan++;
- }
- if (build > tmpblk.c)
- {
- *build = '\0';
- add(cursor, tmpblk.c);
- cursor += (build - tmpblk.c);
- }
- }
- }
-
- /* repeatedly add characters from the user */
- for (;;)
- {
- /* Get a character */
- redraw(cursor, TRUE);
- key[0] = getkey(when);
-
- /* if whitespace & wrapmargin is set & we're
- /* past the warpmargin, then change the
- /* whitespace character into a newline
- */
- if ((*key == ' ' || *key == '\t')
- && *o_wrapmargin != 0)
- {
- pfetch(markline(cursor));
- if (idx2col(cursor, ptext, TRUE) > (*o_wrapmargin & 0xff))
- {
- *key = '\n';
- }
- }
-
- /* process it */
- switch (*key)
- {
- case ctrl('['):
- goto BreakBreak;
-
- case ctrl('U'):
- if (markline(cursor) == markline(from))
- {
- cursor == from;
- }
- else
- {
- cursor &= ~(BLKSIZE - 1);
- }
- break;
-
- case '\b':
- case ctrl('D'):
- if (cursor <= from)
- {
- beep();
- }
- else if (markidx(cursor) == 0)
- {
- cursor -= BLKSIZE;
- pfetch(markline(cursor));
- cursor += plen;
- }
- else
- {
- cursor--;
- }
- break;
-
- case ctrl('W'):
- m = movebword(cursor, 1L);
- if (markline(m) == markline(cursor) && m >= from)
- {
- cursor = m;
- if (from > cursor)
- {
- from = cursor;
- }
- }
- else
- {
- beep();
- }
- break;
-
- case '\n':
- case '\r':
- build = tmpblk.c;
- *build++ = '\n';
- if (*o_autoindent)
- {
- pfetch(markline(cursor));
- for (scan = ptext; *scan == ' ' || *scan == '\t'; )
- {
- *build++ = *scan++;
- }
- }
- *build = 0;
- if (cursor >= to && when != WHEN_VIREP)
- {
- add(cursor, tmpblk.c);
- }
- else
- {
- change(cursor, to, tmpblk.c);
- }
- redraw(cursor, TRUE);
- to = cursor = (cursor & ~(BLKSIZE - 1))
- + BLKSIZE
- + (build - tmpblk.c) - 1;
- break;
-
- case ctrl('A'):
- if (cursor < to)
- {
- delete(cursor, to);
- }
- cutname('.');
- to = cursor = paste(cursor, FALSE, TRUE) + 1L;
- break;
-
- case ctrl('V'):
- if (cursor >= to && when != WHEN_VIREP)
- {
- add(cursor, "^");
- }
- else
- {
- change(cursor, to, "^");
- }
- redraw(cursor, TRUE);
- *key = getkey(0);
- if (*key == '\n')
- {
- /* '\n' too hard to handle */
- *key = '\r';
- }
- change(cursor, cursor + 1, key);
- cursor++;
- if (cursor > to)
- {
- to = cursor;
- }
- break;
-
- case ctrl('L'):
- case ctrl('R'):
- redraw(MARK_UNSET, FALSE);
- break;
-
- case ctrl('T'):
- *key = '\t';
- /* fall through to default case... */
-
- default:
- if (cursor >= to && when != WHEN_VIREP)
- {
- add(cursor, key);
- cursor++;
- to = cursor;
- }
- else
- {
- pfetch(markline(cursor));
- if (markidx(cursor) == plen)
- {
- add(cursor, key);
- }
- else
- {
- change(cursor, cursor + 1, key);
- }
- cursor++;
- }
- } /* end switch(*key) */
- } /* end for(;;) */
- BreakBreak:;
-
- /* delete any excess characters */
- if (cursor < to)
- {
- delete(cursor, to);
- }
-
- } /* end if doingdot else */
-
- } /* end ChangeText */
-
- /* put the new text into a cut buffer for possible reuse */
- if (!doingdot)
- {
- blksync();
- cutname('.');
- cut(from, cursor);
- }
-
- /* move to last char that we inputted, unless it was newline */
- if (markidx(cursor) != 0)
- {
- cursor--;
- }
-
- rptlines = 0L;
- return cursor;
- }
-