853 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			853 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* input.c */
 | 
						|
 | 
						|
/* Author:
 | 
						|
 *	Steve Kirkendall
 | 
						|
 *	14407 SW Teal Blvd. #C
 | 
						|
 *	Beaverton, OR 97005
 | 
						|
 *	kirkenda@cs.pdx.edu
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
/* This file contains the input() function, which implements vi's INPUT mode.
 | 
						|
 * It also contains the code that supports digraphs.
 | 
						|
 */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
#include "ctype.h"
 | 
						|
#include "vi.h"
 | 
						|
 | 
						|
 | 
						|
#ifndef NO_DIGRAPH
 | 
						|
static struct _DIG
 | 
						|
{
 | 
						|
	struct _DIG	*next;
 | 
						|
	char		key1;
 | 
						|
	char		key2;
 | 
						|
	char		dig;
 | 
						|
	char		save;
 | 
						|
} *digs;
 | 
						|
 | 
						|
char digraph(key1, key2)
 | 
						|
	char	key1;	/* the underlying character */
 | 
						|
	char	key2;	/* the second character */
 | 
						|
{
 | 
						|
	int		newkey;
 | 
						|
	REG struct _DIG	*dp;
 | 
						|
 | 
						|
	/* if digraphs are disabled, then just return the new char */
 | 
						|
	if (!*o_digraph)
 | 
						|
	{
 | 
						|
		return key2;
 | 
						|
	}
 | 
						|
 | 
						|
	/* remember the new key, so we can return it if this isn't a digraph */
 | 
						|
	newkey = key2;
 | 
						|
 | 
						|
	/* sort key1 and key2, so that their original order won't matter */
 | 
						|
	if (key1 > key2)
 | 
						|
	{
 | 
						|
		key2 = key1;
 | 
						|
		key1 = newkey;
 | 
						|
	}
 | 
						|
 | 
						|
	/* scan through the digraph chart */
 | 
						|
	for (dp = digs;
 | 
						|
	     dp && (dp->key1 != key1 || dp->key2 != key2);
 | 
						|
	     dp = dp->next)
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	/* if this combination isn't in there, just use the new key */
 | 
						|
	if (!dp)
 | 
						|
	{
 | 
						|
		return newkey;
 | 
						|
	}
 | 
						|
 | 
						|
	/* else use the digraph key */
 | 
						|
	return dp->dig;
 | 
						|
}
 | 
						|
 | 
						|
/* this function lists or defines digraphs */
 | 
						|
void do_digraph(bang, extra)
 | 
						|
	int	bang;
 | 
						|
	char	extra[];
 | 
						|
{
 | 
						|
	int		dig;
 | 
						|
	REG struct _DIG	*dp;
 | 
						|
	struct _DIG	*prev;
 | 
						|
	static int	user_defined = FALSE; /* boolean: are all later digraphs user-defined? */
 | 
						|
	char		listbuf[8];
 | 
						|
 | 
						|
	/* if "extra" is NULL, then we've reached the end of the built-ins */
 | 
						|
	if (!extra)
 | 
						|
	{
 | 
						|
		user_defined = TRUE;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* if no args, then display the existing digraphs */
 | 
						|
	if (*extra < ' ')
 | 
						|
	{
 | 
						|
		listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
 | 
						|
		listbuf[7] = '\0';
 | 
						|
		for (dig = 0, dp = digs; dp; dp = dp->next)
 | 
						|
		{
 | 
						|
			if (dp->save || bang)
 | 
						|
			{
 | 
						|
				dig += 7;
 | 
						|
				if (dig >= COLS)
 | 
						|
				{
 | 
						|
					addch('\n');
 | 
						|
					exrefresh();
 | 
						|
					dig = 7;
 | 
						|
				}
 | 
						|
				listbuf[3] = dp->key1;
 | 
						|
				listbuf[4] = dp->key2;
 | 
						|
				listbuf[6] = dp->dig;
 | 
						|
				qaddstr(listbuf);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		addch('\n');
 | 
						|
		exrefresh();
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* make sure we have at least two characters */
 | 
						|
	if (!extra[1])
 | 
						|
	{
 | 
						|
		msg("Digraphs must be composed of two characters");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* sort key1 and key2, so that their original order won't matter */
 | 
						|
	if (extra[0] > extra[1])
 | 
						|
	{
 | 
						|
		dig = extra[0];
 | 
						|
		extra[0] = extra[1];
 | 
						|
		extra[1] = dig;
 | 
						|
	}
 | 
						|
 | 
						|
	/* locate the new digraph character */
 | 
						|
	for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
 | 
						|
	{
 | 
						|
	}
 | 
						|
	dig = extra[dig];
 | 
						|
	if (!bang && dig)
 | 
						|
	{
 | 
						|
		dig |= 0x80;
 | 
						|
	}
 | 
						|
 | 
						|
	/* search for the digraph */
 | 
						|
	for (prev = (struct _DIG *)0, dp = digs;
 | 
						|
	     dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
 | 
						|
	     prev = dp, dp = dp->next)
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	/* deleting the digraph? */
 | 
						|
	if (!dig)
 | 
						|
	{
 | 
						|
		if (!dp)
 | 
						|
		{
 | 
						|
#ifndef CRUNCH
 | 
						|
			msg("%c%c not a digraph", extra[0], extra[1]);
 | 
						|
#endif
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		if (prev)
 | 
						|
			prev->next = dp->next;
 | 
						|
		else
 | 
						|
			digs = dp->next;
 | 
						|
		free(dp);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* if necessary, create a new digraph struct for the new digraph */
 | 
						|
	if (dig && !dp)
 | 
						|
	{
 | 
						|
		dp = (struct _DIG *)malloc(sizeof *dp);
 | 
						|
		if (!dp)
 | 
						|
		{
 | 
						|
			msg("Out of space in the digraph table");
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		if (prev)
 | 
						|
			prev->next = dp;
 | 
						|
		else
 | 
						|
			digs = dp;
 | 
						|
		dp->next = (struct _DIG *)0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* assign it the new digraph value */
 | 
						|
	dp->key1 = extra[0];
 | 
						|
	dp->key2 = extra[1];
 | 
						|
	dp->dig = dig;
 | 
						|
	dp->save = user_defined;
 | 
						|
}
 | 
						|
 | 
						|
# ifndef NO_MKEXRC
 | 
						|
void savedigs(fd)
 | 
						|
	int		fd;
 | 
						|
{
 | 
						|
	static char	buf[] = "digraph! XX Y\n";
 | 
						|
	REG struct _DIG	*dp;
 | 
						|
 | 
						|
	for (dp = digs; dp; dp = dp->next)
 | 
						|
	{
 | 
						|
		if (dp->save)
 | 
						|
		{
 | 
						|
			buf[9] = dp->key1;
 | 
						|
			buf[10] = dp->key2;
 | 
						|
			buf[12] = dp->dig;
 | 
						|
			write(fd, buf, (unsigned)14);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* 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, above)
 | 
						|
	MARK	from;	/* where to start inserting text */
 | 
						|
	MARK	to;	/* extent of text to delete */
 | 
						|
	int	when;	/* either WHEN_VIINP or WHEN_VIREP */
 | 
						|
	int	above;	/* boolean: take indentation from lower line? */
 | 
						|
{
 | 
						|
	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;	/* some place in the text */
 | 
						|
#ifndef NO_EXTENSIONS
 | 
						|
	int	quit = FALSE;	/* boolean: are we exiting after this? */
 | 
						|
	int	inchg;	/* boolean: have we done a "beforedo()" yet? */
 | 
						|
#endif
 | 
						|
 | 
						|
#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);
 | 
						|
	}
 | 
						|
 | 
						|
	/* if doing a dot command, then reuse the previous text */
 | 
						|
	if (doingdot)
 | 
						|
	{
 | 
						|
		ChangeText
 | 
						|
		{
 | 
						|
			/* delete the text that's there now */
 | 
						|
			if (from != to)
 | 
						|
			{
 | 
						|
				delete(from, to);
 | 
						|
			}
 | 
						|
 | 
						|
			/* insert the previous text */
 | 
						|
			cutname('.');
 | 
						|
			cursor = paste(from, FALSE, TRUE) + 1L;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else /* interactive version */
 | 
						|
	{
 | 
						|
		/* assume that whoever called this already did a beforedo() */
 | 
						|
#ifndef NO_EXTENSIONS
 | 
						|
		inchg = TRUE;
 | 
						|
#endif
 | 
						|
 | 
						|
		/* 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;
 | 
						|
		m = (above ? (cursor + BLKSIZE) : (cursor - BLKSIZE));
 | 
						|
		if (*o_autoindent && markidx(m) == 0
 | 
						|
		 && markline(m) >= 1L && markline(m) <= nlines)
 | 
						|
		{
 | 
						|
			/* Only autoindent blank lines. */
 | 
						|
			pfetch(markline(cursor));
 | 
						|
			if (plen == 0)
 | 
						|
			{
 | 
						|
				/* Okay, we really want to autoindent */
 | 
						|
				pfetch(markline(m));
 | 
						|
				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);
 | 
						|
					if (cursor > to)
 | 
						|
						to = cursor;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* repeatedly add characters from the user */
 | 
						|
		for (;;)
 | 
						|
		{
 | 
						|
			/* Get a character */
 | 
						|
			redraw(cursor, TRUE);
 | 
						|
#ifdef DEBUG2
 | 
						|
			msg("cursor=%ld.%d, to=%ld.%d",
 | 
						|
				markline(cursor), markidx(cursor),
 | 
						|
				markline(to), markidx(to));
 | 
						|
#endif
 | 
						|
#ifndef NO_ABBR
 | 
						|
			pfetch(markline(cursor));
 | 
						|
			build = ptext;
 | 
						|
			if (pline == markline(from))
 | 
						|
				build += markidx(from);
 | 
						|
			for (scan = ptext + markidx(cursor); --scan >= build && isalnum(*scan); )
 | 
						|
			{
 | 
						|
			}
 | 
						|
			scan++;
 | 
						|
			key[0] = getabkey(when, scan, (int)(ptext + markidx(cursor) - scan));
 | 
						|
#else
 | 
						|
			key[0] = getkey(when);
 | 
						|
#endif
 | 
						|
#ifndef NO_VISIBLE
 | 
						|
			if (key[0] != '\0' && V_from != MARK_UNSET)
 | 
						|
			{
 | 
						|
				msg("Can't modify text during a selection");
 | 
						|
				beep();
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef NO_EXTENSIONS
 | 
						|
			if (key[0] == ctrl('O'))
 | 
						|
			{
 | 
						|
				if (inchg)
 | 
						|
				{
 | 
						|
					if (cursor < to)
 | 
						|
					{
 | 
						|
						delete(cursor, to);
 | 
						|
						redraw(cursor, TRUE);
 | 
						|
					}
 | 
						|
					afterdo();
 | 
						|
					inchg = FALSE;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else if (key[0] != ctrl('['))
 | 
						|
			{
 | 
						|
				if (!inchg)
 | 
						|
				{
 | 
						|
					beforedo(FALSE);
 | 
						|
					inchg = TRUE;
 | 
						|
				}
 | 
						|
			}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef CRUNCH
 | 
						|
			/* if wrapmargin is set & we're past the
 | 
						|
			 * warpmargin, then change the last whitespace
 | 
						|
			 * characters on line into a newline
 | 
						|
			 */
 | 
						|
			if (*o_wrapmargin != 0)
 | 
						|
			{
 | 
						|
				pfetch(markline(cursor));
 | 
						|
				if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
 | 
						|
				{
 | 
						|
					build = tmpblk.c;
 | 
						|
					*build++ = '\n';
 | 
						|
					if (*o_autoindent)
 | 
						|
					{
 | 
						|
						/* figure out indent for next line */
 | 
						|
						for (scan = ptext; *scan == ' ' || *scan == '\t'; )
 | 
						|
						{
 | 
						|
							*build++ = *scan++;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					*build = '\0';
 | 
						|
 | 
						|
					scan = ptext + plen;
 | 
						|
					m = cursor & ~(BLKSIZE - 1);
 | 
						|
					while (ptext < scan)
 | 
						|
					{
 | 
						|
						scan--;
 | 
						|
						if (*scan != ' ' && *scan != '\t')
 | 
						|
							continue;
 | 
						|
 | 
						|
						/*break up line, and we do autoindent if needed*/
 | 
						|
						change(m + (scan - ptext), m + (scan - ptext) + 1, tmpblk.c);
 | 
						|
						cursor = (cursor & ~(BLKSIZE - 1))
 | 
						|
							+ BLKSIZE
 | 
						|
							+ strlen(tmpblk.c) - 1
 | 
						|
							+ plen - (scan - ptext) - 1;
 | 
						|
 | 
						|
						/*remove trailing spaces on previous line*/
 | 
						|
						pfetch(markline(m));
 | 
						|
						scan = ptext + plen;
 | 
						|
						while (ptext < scan)
 | 
						|
						{
 | 
						|
							scan--;
 | 
						|
							if (*scan != ' ' && *scan != '\t')
 | 
						|
								break;
 | 
						|
						}
 | 
						|
						delete(m + (scan-ptext) + 1, m + plen);
 | 
						|
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
#endif /* !CRUNCH */
 | 
						|
 | 
						|
			/* process it */
 | 
						|
			switch (*key)
 | 
						|
			{
 | 
						|
#ifndef NO_EXTENSIONS
 | 
						|
			  case ctrl('O'): /* special movement mapped keys */
 | 
						|
				*key = getkey(0);
 | 
						|
				switch (*key)
 | 
						|
				{
 | 
						|
				  case 'h':	m = m_left(cursor, 0L);		break;
 | 
						|
				  case 'j':
 | 
						|
				  case 'k':	m = m_updnto(cursor, 0L, *key);	break;
 | 
						|
				  case 'l':	m = cursor + 1;			break;
 | 
						|
				  case 'B':
 | 
						|
				  case 'b':	m = m_bword(cursor, 0L, *key);	break;
 | 
						|
				  case 'W':
 | 
						|
				  case 'w':	m = m_fword(cursor, 0L, *key, '\0');	break;
 | 
						|
				  case '^':	m = m_front(cursor, 0L);	break;
 | 
						|
				  case '$':	m = m_rear(cursor, 0L);		break;
 | 
						|
				  case ctrl('B'):
 | 
						|
				  case ctrl('F'):
 | 
						|
						m = m_scroll(cursor, 0L, *key); break;
 | 
						|
				  case 'x':
 | 
						|
#ifndef NO_VISIBLE
 | 
						|
						if (V_from)
 | 
						|
							beep();
 | 
						|
						else
 | 
						|
#endif
 | 
						|
						ChangeText
 | 
						|
						{
 | 
						|
							m = v_xchar(cursor, 0L, 'x');
 | 
						|
						}
 | 
						|
						break;
 | 
						|
				  case 'i':	m = to = from = cursor;
 | 
						|
						when = WHEN_VIINP + WHEN_VIREP - when;
 | 
						|
										break;
 | 
						|
				  case 'K':
 | 
						|
					pfetch(markline(cursor));
 | 
						|
					changes++; /* <- after this, we can alter ptext */
 | 
						|
					ptext[markidx(cursor)] = 0;
 | 
						|
					for (scan = ptext + markidx(cursor) - 1;
 | 
						|
					     scan >= ptext && isalnum(*scan);
 | 
						|
					     scan--)
 | 
						|
					{
 | 
						|
					}
 | 
						|
					scan++;
 | 
						|
					m = (*scan ? v_keyword(scan, cursor, 0L) : cursor);
 | 
						|
					break;
 | 
						|
 | 
						|
# ifndef NO_VISIBLE
 | 
						|
				  case 'v':
 | 
						|
				  case 'V':
 | 
						|
					if (V_from)
 | 
						|
						V_from = MARK_UNSET;
 | 
						|
					else
 | 
						|
						V_from = cursor;
 | 
						|
					m = from = to = cursor;
 | 
						|
					V_linemd = (*key == 'V');
 | 
						|
					break;
 | 
						|
 | 
						|
				  case 'd':
 | 
						|
				  case 'y':
 | 
						|
				  case '\\':
 | 
						|
					/* do nothing if unmarked */
 | 
						|
					if (!V_from)
 | 
						|
					{
 | 
						|
						msg("You must mark the text first");
 | 
						|
						beep();
 | 
						|
						break;
 | 
						|
					}
 | 
						|
 | 
						|
					/* "from" must come before "to" */
 | 
						|
					if (V_from < cursor)
 | 
						|
					{
 | 
						|
						from = V_from;
 | 
						|
						to = cursor;
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						from = cursor;
 | 
						|
						to = V_from;
 | 
						|
					}
 | 
						|
 | 
						|
					/* we don't need V_from anymore */
 | 
						|
					V_from = MARK_UNSET;
 | 
						|
 | 
						|
					if (V_linemd)
 | 
						|
					{
 | 
						|
						/* adjust for line mode */
 | 
						|
						from &= ~(BLKSIZE - 1);
 | 
						|
						to |= (BLKSIZE - 1);
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						/* in character mode, we must
 | 
						|
						 * worry about deleting the newline
 | 
						|
						 * at the end of the last line
 | 
						|
						 */
 | 
						|
						pfetch(markline(to));
 | 
						|
						if (markidx(to) == plen)
 | 
						|
							to |= (BLKSIZE - 1);
 | 
						|
					}
 | 
						|
					to++;
 | 
						|
 | 
						|
					switch (*key)
 | 
						|
					{
 | 
						|
					  case 'y':
 | 
						|
						cut(from, to);
 | 
						|
						break;
 | 
						|
 | 
						|
					  case 'd':
 | 
						|
						ChangeText
 | 
						|
						{
 | 
						|
							cut(from, to);
 | 
						|
							delete(from, to);
 | 
						|
						}
 | 
						|
						cursor = from;
 | 
						|
						break;
 | 
						|
 | 
						|
#ifndef NO_POPUP
 | 
						|
					  case '\\':
 | 
						|
						ChangeText
 | 
						|
						{
 | 
						|
							cursor = v_popup(from, to);
 | 
						|
						}
 | 
						|
						break;
 | 
						|
#endif
 | 
						|
					}
 | 
						|
					m = from = to = cursor;
 | 
						|
					break;
 | 
						|
 | 
						|
				  case 'p':
 | 
						|
				  case 'P':
 | 
						|
					V_from = MARK_UNSET;
 | 
						|
					ChangeText
 | 
						|
					{
 | 
						|
						m = from = to = cursor = paste(cursor, (*key == 'p'), FALSE);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
# endif /* !NO_VISIBLE */
 | 
						|
				  default:	m = MARK_UNSET;
 | 
						|
				}
 | 
						|
 | 
						|
				/* adjust the moved cursor */
 | 
						|
				if (m != cursor)
 | 
						|
				{
 | 
						|
					m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0));
 | 
						|
					if (*key == '$' || (*key == 'l' && m <= cursor))
 | 
						|
					{
 | 
						|
						m++;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				/* if the cursor is reasonable, use it */
 | 
						|
				if (m == MARK_UNSET)
 | 
						|
				{
 | 
						|
					beep();
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					from = to = cursor = m;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			  case ctrl('Z'):
 | 
						|
				if (getkey(0) == ctrl('Z'))
 | 
						|
				{
 | 
						|
					quit = TRUE;
 | 
						|
					goto BreakBreak;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
#endif
 | 
						|
 | 
						|
			  case ctrl('['):
 | 
						|
				/* if last line contains only whitespace, then remove whitespace */
 | 
						|
				if (*o_autoindent)
 | 
						|
				{
 | 
						|
					pfetch(markline(cursor));
 | 
						|
					for (scan = ptext; isspace(*scan); scan++)
 | 
						|
					{
 | 
						|
					}
 | 
						|
					if (scan > ptext && !*scan)
 | 
						|
					{
 | 
						|
						cursor &= ~(BLKSIZE - 1L);
 | 
						|
						if (to < cursor + plen)
 | 
						|
						{
 | 
						|
							to = cursor + plen;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
				goto BreakBreak;
 | 
						|
 | 
						|
			  case ctrl('U'):
 | 
						|
				if (markline(cursor) == markline(from))
 | 
						|
				{
 | 
						|
					cursor = from;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					cursor &= ~(BLKSIZE - 1);
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			  case ctrl('D'):
 | 
						|
			  case ctrl('T'):
 | 
						|
				if (to > cursor)
 | 
						|
				{
 | 
						|
					delete(cursor, to);
 | 
						|
				}
 | 
						|
				mark[27] = cursor;
 | 
						|
				cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, "");
 | 
						|
				if (mark[27])
 | 
						|
				{
 | 
						|
					cursor = mark[27];
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					cursor = m_front(cursor, 0L);
 | 
						|
				}
 | 
						|
				to = cursor;
 | 
						|
				break;
 | 
						|
 | 
						|
			  case '\b':
 | 
						|
				if (cursor <= from)
 | 
						|
				{
 | 
						|
					beep();
 | 
						|
				}
 | 
						|
				else if (markidx(cursor) == 0)
 | 
						|
				{
 | 
						|
					cursor -= BLKSIZE;
 | 
						|
					pfetch(markline(cursor));
 | 
						|
					cursor += plen;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					cursor--;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			  case ctrl('W'):
 | 
						|
				m = m_bword(cursor, 1L, 'b');
 | 
						|
				if (markline(m) == markline(cursor) && m >= from)
 | 
						|
				{
 | 
						|
					cursor = m;
 | 
						|
					if (from > cursor)
 | 
						|
					{
 | 
						|
						from = cursor;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					beep();
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			  case '\n':
 | 
						|
#if OSK
 | 
						|
			  case '\l':
 | 
						|
#else				  
 | 
						|
			  case '\r':
 | 
						|
#endif
 | 
						|
				build = tmpblk.c;
 | 
						|
				*build++ = '\n';
 | 
						|
				if (*o_autoindent)
 | 
						|
				{
 | 
						|
					/* figure out indent for next line */
 | 
						|
					pfetch(markline(cursor));
 | 
						|
					for (scan = ptext; *scan == ' ' || *scan == '\t'; )
 | 
						|
					{
 | 
						|
						*build++ = *scan++;
 | 
						|
					}
 | 
						|
 | 
						|
					/* remove indent from this line, if blank */
 | 
						|
					if ((scan - ptext) >= markidx(cursor) && plen > 0)
 | 
						|
					{
 | 
						|
						to = cursor &= ~(BLKSIZE - 1);
 | 
						|
						delete(cursor, cursor + plen);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				*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'):
 | 
						|
			  case ctrl('P'):
 | 
						|
				if (cursor < to)
 | 
						|
				{
 | 
						|
					delete(cursor, to);
 | 
						|
				}
 | 
						|
				if (*key == ctrl('A'))
 | 
						|
				{
 | 
						|
					cutname('.');
 | 
						|
				}
 | 
						|
				to = cursor = paste(cursor, FALSE, TRUE) + 1L;
 | 
						|
				break;
 | 
						|
 | 
						|
			  case ctrl('V'):
 | 
						|
				if (cursor >= to && when != WHEN_VIREP)
 | 
						|
				{
 | 
						|
					add(cursor, "^");
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					change(cursor, to, "^");
 | 
						|
					to = cursor + 1;
 | 
						|
				}
 | 
						|
				redraw(cursor, TRUE);
 | 
						|
				*key = getkey(0);
 | 
						|
				if (*key == '\n')
 | 
						|
				{
 | 
						|
					/* '\n' too hard to handle */
 | 
						|
#if OSK
 | 
						|
					*key = '\l';
 | 
						|
#else
 | 
						|
					*key = '\r';
 | 
						|
#endif
 | 
						|
				}
 | 
						|
				change(cursor, cursor + 1, key);
 | 
						|
				cursor++;
 | 
						|
				if (cursor > to)
 | 
						|
				{
 | 
						|
					to = cursor;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			  case ctrl('L'):
 | 
						|
			  case ctrl('R'):
 | 
						|
				redraw(MARK_UNSET, FALSE);
 | 
						|
				break;
 | 
						|
 | 
						|
			  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
 | 
						|
					{
 | 
						|
#ifndef NO_DIGRAPH
 | 
						|
						*key = digraph(ptext[markidx(cursor)], *key);
 | 
						|
#endif
 | 
						|
						change(cursor, cursor + 1, key);
 | 
						|
					}
 | 
						|
					cursor++;
 | 
						|
				}
 | 
						|
#ifndef NO_SHOWMATCH
 | 
						|
				/* show matching "({[" if necessary */
 | 
						|
				if (*o_showmatch && strchr(")}]", *key))
 | 
						|
				{
 | 
						|
					redraw(cursor, TRUE);
 | 
						|
					m = m_match(cursor - 1, 0L);
 | 
						|
					if (markline(m) >= topline
 | 
						|
					 && markline(m) <= botline)
 | 
						|
					{
 | 
						|
						redraw(m, TRUE);
 | 
						|
						refresh();
 | 
						|
						sleep(1);
 | 
						|
					}
 | 
						|
				}
 | 
						|
#endif
 | 
						|
			} /* end switch(*key) */
 | 
						|
		} /* end for(;;) */
 | 
						|
BreakBreak:;
 | 
						|
		/* delete any excess characters */
 | 
						|
		if (cursor < to)
 | 
						|
		{
 | 
						|
#ifndef NO_EXTENSIONS
 | 
						|
			/* if we aren't in the middle of a change, start one! */
 | 
						|
			if (!inchg)
 | 
						|
			{
 | 
						|
				beforedo(FALSE);
 | 
						|
				inchg = TRUE;
 | 
						|
			}
 | 
						|
#endif
 | 
						|
			delete(cursor, to);
 | 
						|
		}
 | 
						|
 | 
						|
	} /* end if doingdot else */
 | 
						|
 | 
						|
	/* 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--;
 | 
						|
	}
 | 
						|
	redraw(cursor, FALSE);
 | 
						|
 | 
						|
#ifndef NO_EXTENSIONS
 | 
						|
	if (quit)
 | 
						|
	{
 | 
						|
		/* if this is a nested "do", then cut it short */
 | 
						|
		abortdo();
 | 
						|
 | 
						|
		/* exit, unless we can't write out the file */
 | 
						|
		cursor = v_xit(cursor, 0L, 'Z');
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	rptlines = 0L;
 | 
						|
	return cursor;
 | 
						|
}
 |