299 lines
5.7 KiB
C
299 lines
5.7 KiB
C
/* 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) > COLS - (*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
|
|
+ (int)(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;
|
|
}
|