976 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			976 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* vcmd.c */
 | 
						|
 | 
						|
/* Author:
 | 
						|
 *	Steve Kirkendall
 | 
						|
 *	14407 SW Teal Blvd. #C
 | 
						|
 *	Beaverton, OR 97005
 | 
						|
 *	kirkenda@cs.pdx.edu
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
/* This file contains the functions that handle VI commands */
 | 
						|
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
#include "ctype.h"
 | 
						|
#include "vi.h"
 | 
						|
#if MSDOS
 | 
						|
# include <process.h>
 | 
						|
# include <string.h>
 | 
						|
#endif
 | 
						|
#if TOS
 | 
						|
# include <osbind.h>
 | 
						|
# include <string.h>
 | 
						|
#endif
 | 
						|
#if OSK
 | 
						|
# include <stdio.h>
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* This function puts the editor in EX mode */
 | 
						|
MARK v_quit()
 | 
						|
{
 | 
						|
	move(LINES - 1, 0);
 | 
						|
	mode = MODE_EX;
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
 | 
						|
/* This function causes the screen to be redrawn */
 | 
						|
MARK v_redraw()
 | 
						|
{
 | 
						|
	redraw(MARK_UNSET, FALSE);
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
 | 
						|
/* This function executes a string of EX commands, and waits for a user keystroke
 | 
						|
 * before returning to the VI screen.  If that keystroke is another ':', then
 | 
						|
 * another EX command is read and executed.
 | 
						|
 */
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_1ex(m, text)
 | 
						|
	MARK	m;	/* the current line */
 | 
						|
	char	*text;	/* the first command to execute */
 | 
						|
{
 | 
						|
	/* run the command.  be careful about modes & output */
 | 
						|
	exwrote = (mode == MODE_COLON);
 | 
						|
	doexcmd(text);
 | 
						|
	exrefresh();
 | 
						|
 | 
						|
	/* if mode is no longer MODE_VI, then we should quit right away! */
 | 
						|
	if (mode != MODE_VI && mode != MODE_COLON)
 | 
						|
		return cursor;
 | 
						|
 | 
						|
	/* The command did some output.  Wait for a keystoke. */
 | 
						|
	if (exwrote)
 | 
						|
	{
 | 
						|
		mode = MODE_VI;	
 | 
						|
		msg("[Hit <RETURN> to continue]");
 | 
						|
		if (getkey(0) == ':')
 | 
						|
		{	mode = MODE_COLON;
 | 
						|
			addch('\n');
 | 
						|
		}
 | 
						|
		else
 | 
						|
			redraw(MARK_UNSET, FALSE);
 | 
						|
	}
 | 
						|
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
 | 
						|
/* This function undoes the last change */
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_undo(m)
 | 
						|
	MARK	m;	/* (ignored) */
 | 
						|
{
 | 
						|
	if (undo())
 | 
						|
	{
 | 
						|
		redraw(MARK_UNSET, FALSE);
 | 
						|
	}
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
 | 
						|
/* This function deletes the character(s) that the cursor is on */
 | 
						|
MARK v_xchar(m, cnt, cmd)
 | 
						|
	MARK	m;	/* where to start deletions */
 | 
						|
	long	cnt;	/* number of chars to delete */
 | 
						|
	int	cmd;	/* either 'x' or 'X' */
 | 
						|
{
 | 
						|
	DEFAULT(1);
 | 
						|
 | 
						|
	/* for 'X', adjust so chars are deleted *BEFORE* cursor */
 | 
						|
	if (cmd == 'X')
 | 
						|
	{
 | 
						|
		if (markidx(m) < cnt)
 | 
						|
			return MARK_UNSET;
 | 
						|
		m -= cnt;
 | 
						|
	}
 | 
						|
 | 
						|
	/* make sure we don't try to delete more thars than there are */
 | 
						|
	pfetch(markline(m));
 | 
						|
	if (markidx(m + cnt) > plen)
 | 
						|
	{
 | 
						|
		cnt = plen - markidx(m);
 | 
						|
	}
 | 
						|
	if (cnt == 0L)
 | 
						|
	{
 | 
						|
		return MARK_UNSET;
 | 
						|
	}
 | 
						|
 | 
						|
	/* do it */
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		cut(m, m + cnt);
 | 
						|
		delete(m, m + cnt);
 | 
						|
	}
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This function defines a mark */
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_mark(m, count, key)
 | 
						|
	MARK	m;	/* where the mark will be */
 | 
						|
	long	count;	/* (ignored) */
 | 
						|
	int	key;	/* the ASCII label of the mark */
 | 
						|
{
 | 
						|
	if (key < 'a' || key > 'z')
 | 
						|
	{
 | 
						|
		msg("Marks must be from a to z");
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		mark[key - 'a'] = m;
 | 
						|
	}
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This function toggles upper & lower case letters */
 | 
						|
MARK v_ulcase(m, cnt)
 | 
						|
	MARK	m;	/* where to make the change */
 | 
						|
	long	cnt;	/* number of chars to flip */
 | 
						|
{
 | 
						|
	REG char 	*pos;
 | 
						|
	REG int		j;
 | 
						|
 | 
						|
	DEFAULT(1);
 | 
						|
 | 
						|
	/* fetch the current version of the line */
 | 
						|
	pfetch(markline(m));
 | 
						|
 | 
						|
	/* for each position in the line */
 | 
						|
	for (j = 0, pos = &ptext[markidx(m)]; j < cnt && *pos; j++, pos++)
 | 
						|
	{
 | 
						|
		if (isupper(*pos))
 | 
						|
		{
 | 
						|
			tmpblk.c[j] = tolower(*pos);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			tmpblk.c[j] = toupper(*pos);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* if the new text is different from the old, then change it */
 | 
						|
	if (strncmp(tmpblk.c, &ptext[markidx(m)], j))
 | 
						|
	{
 | 
						|
		ChangeText
 | 
						|
		{
 | 
						|
			tmpblk.c[j] = '\0';
 | 
						|
			change(m, m + j, tmpblk.c);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return m + j;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
MARK v_replace(m, cnt, key)
 | 
						|
	MARK	m;	/* first char to be replaced */
 | 
						|
	long	cnt;	/* number of chars to replace */
 | 
						|
	int	key;	/* what to replace them with */
 | 
						|
{
 | 
						|
	REG char	*text;
 | 
						|
	REG int		i;
 | 
						|
 | 
						|
	DEFAULT(1);
 | 
						|
 | 
						|
	/* map ^M to '\n' */
 | 
						|
	if (key == '\r')
 | 
						|
	{
 | 
						|
		key = '\n';
 | 
						|
	}
 | 
						|
 | 
						|
	/* make sure the resulting line isn't too long */
 | 
						|
	if (cnt > BLKSIZE - 2 - markidx(m))
 | 
						|
	{
 | 
						|
		cnt = BLKSIZE - 2 - markidx(m);
 | 
						|
	}
 | 
						|
 | 
						|
	/* build a string of the desired character with the desired length */
 | 
						|
	for (text = tmpblk.c, i = cnt; i > 0; i--)
 | 
						|
	{
 | 
						|
		*text++ = key;
 | 
						|
	}
 | 
						|
	*text = '\0';
 | 
						|
 | 
						|
	/* make sure cnt doesn't extend past EOL */
 | 
						|
	pfetch(markline(m));
 | 
						|
	key = markidx(m);
 | 
						|
	if (key + cnt > plen)
 | 
						|
	{
 | 
						|
		cnt = plen - key;
 | 
						|
	}
 | 
						|
 | 
						|
	/* do the replacement */
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		change(m, m + cnt, tmpblk.c);
 | 
						|
	}
 | 
						|
 | 
						|
	if (*tmpblk.c == '\n')
 | 
						|
	{
 | 
						|
		return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		return m + cnt - 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
MARK v_overtype(m)
 | 
						|
	MARK		m;	/* where to start overtyping */
 | 
						|
{
 | 
						|
	MARK		end;	/* end of a substitution */
 | 
						|
	static long	width;	/* width of a single-line replace */
 | 
						|
 | 
						|
	/* the "doingdot" version of replace is really a substitution */
 | 
						|
	if (doingdot)
 | 
						|
	{
 | 
						|
		/* was the last one really repeatable? */
 | 
						|
		if (width < 0)
 | 
						|
		{
 | 
						|
			msg("Can't repeat a multi-line overtype command");
 | 
						|
			return MARK_UNSET;
 | 
						|
		}
 | 
						|
 | 
						|
		/* replacing nothing by nothing?  Don't bother */
 | 
						|
		if (width == 0)
 | 
						|
		{
 | 
						|
			return m;
 | 
						|
		}
 | 
						|
 | 
						|
		/* replace some chars by repeated text */
 | 
						|
		return v_subst(m, width);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Normally, we input starting here, in replace mode */
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		end = input(m, m, WHEN_VIREP, FALSE);
 | 
						|
	}
 | 
						|
 | 
						|
	/* if we ended on the same line we started on, then this
 | 
						|
	 * overtype is repeatable via the dot key.
 | 
						|
	 */
 | 
						|
	if (markline(end) == markline(m) && end >= m - 1L)
 | 
						|
	{
 | 
						|
		width = end - m + 1L;
 | 
						|
	}
 | 
						|
	else /* it isn't repeatable */
 | 
						|
	{
 | 
						|
		width = -1L;
 | 
						|
	}
 | 
						|
 | 
						|
	return end;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This function selects which cut buffer to use */
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_selcut(m, cnt, key)
 | 
						|
	MARK	m;
 | 
						|
	long	cnt;
 | 
						|
	int	key;
 | 
						|
{
 | 
						|
	cutname(key);
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This function pastes text from a cut buffer */
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_paste(m, cnt, cmd)
 | 
						|
	MARK	m;	/* where to paste the text */
 | 
						|
	long	cnt;	/* (ignored) */
 | 
						|
	int	cmd;	/* either 'p' or 'P' */
 | 
						|
{
 | 
						|
	MARK	dest;
 | 
						|
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		/* paste the text, and find out where it ends */
 | 
						|
		dest = paste(m, cmd == 'p', TRUE);
 | 
						|
 | 
						|
		/* was that a line-mode paste? */
 | 
						|
		if (dest && markline(dest) != markline(m))
 | 
						|
		{
 | 
						|
			/* line-mode pastes leave the cursor at the front
 | 
						|
			 * of the first pasted line.
 | 
						|
			 */
 | 
						|
			dest = m;
 | 
						|
			if (cmd == 'p')
 | 
						|
			{
 | 
						|
				dest += BLKSIZE;
 | 
						|
			}
 | 
						|
			force_flags |= FRNT;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return dest;
 | 
						|
}
 | 
						|
 | 
						|
/* This function yanks text into a cut buffer */
 | 
						|
MARK v_yank(m, n)
 | 
						|
	MARK	m, n;	/* range of text to yank */
 | 
						|
{
 | 
						|
	cut(m, n);
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This function deletes a range of text */
 | 
						|
MARK v_delete(m, n)
 | 
						|
	MARK	m, n;	/* range of text to delete */
 | 
						|
{
 | 
						|
	/* illegal to try and delete nothing */
 | 
						|
	if (n <= m)
 | 
						|
	{
 | 
						|
		return MARK_UNSET;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Do it */
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		cut(m, n);
 | 
						|
		delete(m, n);
 | 
						|
	}
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This starts input mode without deleting anything */
 | 
						|
MARK v_insert(m, cnt, key)
 | 
						|
	MARK	m;	/* where to start (sort of) */
 | 
						|
	long	cnt;	/* repeat how many times? */
 | 
						|
	int	key;	/* what command is this for? {a,A,i,I,o,O} */
 | 
						|
{
 | 
						|
	int	wasdot;
 | 
						|
	long	reps;
 | 
						|
	int	above;	/* boolean: new line going above old line? */
 | 
						|
 | 
						|
	DEFAULT(1);
 | 
						|
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		/* tweak the insertion point, based on command key */
 | 
						|
		above = FALSE;
 | 
						|
		switch (key)
 | 
						|
		{
 | 
						|
		  case 'i':
 | 
						|
			break;
 | 
						|
 | 
						|
		  case 'a':
 | 
						|
			pfetch(markline(m));
 | 
						|
			if (plen > 0)
 | 
						|
			{
 | 
						|
				m++;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
 | 
						|
		  case 'I':
 | 
						|
			m = m_front(m, 1L);
 | 
						|
			break;
 | 
						|
 | 
						|
		  case 'A':
 | 
						|
			pfetch(markline(m));
 | 
						|
			m = (m & ~(BLKSIZE - 1)) + plen;
 | 
						|
			break;
 | 
						|
 | 
						|
		  case 'O':
 | 
						|
			m &= ~(BLKSIZE - 1);
 | 
						|
			add(m, "\n");
 | 
						|
			above = TRUE;
 | 
						|
			break;
 | 
						|
 | 
						|
		  case 'o':
 | 
						|
			m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
 | 
						|
			add(m, "\n");
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		/* insert the same text once or more */
 | 
						|
		for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
 | 
						|
		{
 | 
						|
			m = input(m, m, WHEN_VIINP, above) + 1;
 | 
						|
		}
 | 
						|
		if (markidx(m) > 0)
 | 
						|
		{
 | 
						|
			m--;
 | 
						|
		}
 | 
						|
 | 
						|
		doingdot = wasdot;
 | 
						|
	}
 | 
						|
 | 
						|
#ifndef CRUNCH
 | 
						|
# ifndef NO_EXTENSIONS
 | 
						|
	if (key == 'i' && *o_inputmode && mode == MODE_VI)
 | 
						|
	{
 | 
						|
		msg("Now in command mode!  To return to input mode, hit <i>");
 | 
						|
	}
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This starts input mode with some text deleted */
 | 
						|
MARK v_change(m, n)
 | 
						|
	MARK	m, n;	/* the range of text to change */
 | 
						|
{
 | 
						|
	int	lnmode;	/* is this a line-mode change? */
 | 
						|
 | 
						|
	/* swap them if they're in reverse order */
 | 
						|
	if (m > n)
 | 
						|
	{
 | 
						|
		MARK	tmp;
 | 
						|
		tmp = m;
 | 
						|
		m = n;
 | 
						|
		n = tmp;
 | 
						|
	}
 | 
						|
 | 
						|
	/* for line mode, retain the last newline char */
 | 
						|
	lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n);
 | 
						|
	if (lnmode)
 | 
						|
	{
 | 
						|
		n -= BLKSIZE;
 | 
						|
		pfetch(markline(n));
 | 
						|
		n = (n & ~(BLKSIZE - 1)) + plen;
 | 
						|
	}
 | 
						|
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		cut(m, n);
 | 
						|
		m = input(m, n, WHEN_VIINP, FALSE);
 | 
						|
	}
 | 
						|
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This function replaces a given number of characters with input */
 | 
						|
MARK v_subst(m, cnt)
 | 
						|
	MARK	m;	/* where substitutions start */
 | 
						|
	long	cnt;	/* number of chars to replace */
 | 
						|
{
 | 
						|
	DEFAULT(1);
 | 
						|
 | 
						|
	/* make sure we don't try replacing past EOL */
 | 
						|
	pfetch(markline(m));
 | 
						|
	if (markidx(m) + cnt > plen)
 | 
						|
	{
 | 
						|
		cnt = plen - markidx(m);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Go for it! */
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		cut(m, m + cnt);
 | 
						|
		m = input(m, m + cnt, WHEN_VIINP, FALSE);
 | 
						|
	}
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This calls the ex "join" command to join some lines together */
 | 
						|
MARK v_join(m, cnt)
 | 
						|
	MARK	m;	/* the first line to be joined */
 | 
						|
	long	cnt;	/* number of other lines to join */
 | 
						|
{
 | 
						|
	MARK	joint;	/* where the lines were joined */
 | 
						|
 | 
						|
	DEFAULT(1);
 | 
						|
 | 
						|
	/* figure out where the joint will be */
 | 
						|
	pfetch(markline(m));
 | 
						|
	joint = (m & ~(BLKSIZE - 1)) + plen;
 | 
						|
 | 
						|
	/* join the lines */
 | 
						|
	cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, "");
 | 
						|
 | 
						|
	/* the cursor should be left at the joint */
 | 
						|
	return joint;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This calls the ex "<" command to shift some lines left */
 | 
						|
MARK v_lshift(m, n)
 | 
						|
	MARK	m, n;	/* range of lines to shift */
 | 
						|
{
 | 
						|
	/* adjust for inclusive endmarks in ex */
 | 
						|
	n -= BLKSIZE;
 | 
						|
 | 
						|
	cmd_shift(m, n, CMD_SHIFTL, FALSE, (char *)0);
 | 
						|
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This calls the ex ">" command to shift some lines right */
 | 
						|
MARK v_rshift(m, n)
 | 
						|
	MARK	m, n;	/* range of lines to shift */
 | 
						|
{
 | 
						|
	/* adjust for inclusive endmarks in ex */
 | 
						|
	n -= BLKSIZE;
 | 
						|
 | 
						|
	cmd_shift(m, n, CMD_SHIFTR, FALSE, (char *)0);
 | 
						|
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
/* This filters some lines through a preset program, to reformat them */
 | 
						|
MARK v_reformat(m, n)
 | 
						|
	MARK	m, n;	/* range of lines to shift */
 | 
						|
{
 | 
						|
	/* adjust for inclusive endmarks in ex */
 | 
						|
	n -= BLKSIZE;
 | 
						|
 | 
						|
	/* run the filter command */
 | 
						|
	filter(m, n, o_equalprg, TRUE);
 | 
						|
 | 
						|
	redraw(MARK_UNSET, FALSE);
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This runs some lines through a filter program */
 | 
						|
MARK v_filter(m, n)
 | 
						|
	MARK	m, n;	/* range of lines to shift */
 | 
						|
{
 | 
						|
	char	cmdln[150];	/* a shell command line */
 | 
						|
 | 
						|
	/* adjust for inclusive endmarks in ex */
 | 
						|
	n -= BLKSIZE;
 | 
						|
 | 
						|
	if (vgets('!', cmdln, sizeof(cmdln)) > 0)
 | 
						|
	{
 | 
						|
		filter(m, n, cmdln, TRUE);
 | 
						|
	}
 | 
						|
 | 
						|
	redraw(MARK_UNSET, FALSE);
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This function runs the ex "file" command to show the file's status */
 | 
						|
MARK v_status()
 | 
						|
{
 | 
						|
	cmd_file(cursor, cursor, CMD_FILE, 0, "");
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This function runs the ":&" command to repeat the previous :s// */
 | 
						|
MARK v_again(m, n)
 | 
						|
	MARK	m, n;
 | 
						|
{
 | 
						|
	cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, "");
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* This function switches to the previous file, if possible */
 | 
						|
MARK v_switch()
 | 
						|
{
 | 
						|
	if (!*prevorig)
 | 
						|
		msg("No previous file");
 | 
						|
	else
 | 
						|
	{	strcpy(tmpblk.c, prevorig);
 | 
						|
		cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c);
 | 
						|
	}
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
 | 
						|
/* This function does a tag search on a keyword */
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_tag(keyword, m, cnt)
 | 
						|
	char	*keyword;
 | 
						|
	MARK	m;
 | 
						|
	long	cnt;
 | 
						|
{
 | 
						|
	/* move the cursor to the start of the tag name, where m is */
 | 
						|
	cursor = m;
 | 
						|
 | 
						|
	/* perform the tag search */
 | 
						|
	cmd_tag(cursor, cursor, CMD_TAG, 0, keyword);
 | 
						|
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
 | 
						|
#ifndef NO_EXTENSIONS
 | 
						|
/* This function looks up a keyword by calling the helpprog program */
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_keyword(keyword, m, cnt)
 | 
						|
	char	*keyword;
 | 
						|
	MARK	m;
 | 
						|
	long	cnt;
 | 
						|
{
 | 
						|
	int	waswarn;
 | 
						|
	char	cmdline[130];
 | 
						|
 | 
						|
	move(LINES - 1, 0);
 | 
						|
	addstr("---------------------------------------------------------\n");
 | 
						|
	clrtoeol();
 | 
						|
	refresh();
 | 
						|
	sprintf(cmdline, "%s %s", o_keywordprg, keyword);
 | 
						|
	waswarn = *o_warn;
 | 
						|
	*o_warn = FALSE;
 | 
						|
	suspend_curses();
 | 
						|
	if (system(cmdline))
 | 
						|
	{
 | 
						|
		addstr("<<< failed >>>\n");
 | 
						|
	}
 | 
						|
	resume_curses(FALSE);
 | 
						|
	mode = MODE_VI;
 | 
						|
	redraw(MARK_UNSET, FALSE);
 | 
						|
	*o_warn = waswarn;
 | 
						|
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
MARK v_increment(keyword, m, cnt)
 | 
						|
	char	*keyword;
 | 
						|
	MARK	m;
 | 
						|
	long	cnt;
 | 
						|
{
 | 
						|
	static	sign;
 | 
						|
	char	newval[12];
 | 
						|
	long	atol();
 | 
						|
 | 
						|
	DEFAULT(1);
 | 
						|
 | 
						|
	/* get one more keystroke, unless doingdot */
 | 
						|
	if (!doingdot)
 | 
						|
	{
 | 
						|
		sign = getkey(0);
 | 
						|
	}
 | 
						|
 | 
						|
	/* adjust the number, based on that second keystroke */
 | 
						|
	switch (sign)
 | 
						|
	{
 | 
						|
	  case '+':
 | 
						|
	  case '#':
 | 
						|
		cnt = atol(keyword) + cnt;
 | 
						|
		break;
 | 
						|
 | 
						|
	  case '-':
 | 
						|
		cnt = atol(keyword) - cnt;
 | 
						|
		break;
 | 
						|
 | 
						|
	  case '=':
 | 
						|
		break;
 | 
						|
 | 
						|
	  default:
 | 
						|
		return MARK_UNSET;
 | 
						|
	}
 | 
						|
	sprintf(newval, "%ld", cnt);
 | 
						|
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		change(m, m + strlen(keyword), newval);
 | 
						|
	}
 | 
						|
 | 
						|
	return m;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* This function acts like the EX command "xit" */
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_xit(m, cnt, key)
 | 
						|
	MARK	m;	/* ignored */
 | 
						|
	long	cnt;	/* ignored */
 | 
						|
	int	key;	/* must be a second 'Z' */
 | 
						|
{
 | 
						|
	/* if second char wasn't 'Z', fail */
 | 
						|
	if (key != 'Z')
 | 
						|
	{
 | 
						|
		return MARK_UNSET;
 | 
						|
	}
 | 
						|
 | 
						|
	/* move the cursor to the bottom of the screen */
 | 
						|
	move(LINES - 1, 0);
 | 
						|
	clrtoeol();
 | 
						|
 | 
						|
	/* do the xit command */
 | 
						|
	cmd_xit(m, m, CMD_XIT, FALSE, "");
 | 
						|
 | 
						|
	/* return the cursor */
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This function undoes changes to a single line, if possible */
 | 
						|
MARK v_undoline(m)
 | 
						|
	MARK	m;	/* where we hope to undo the change */
 | 
						|
{
 | 
						|
	/* make sure we have the right line in the buffer */
 | 
						|
	if (markline(m) != U_line)
 | 
						|
	{
 | 
						|
		return MARK_UNSET;
 | 
						|
	}
 | 
						|
 | 
						|
	/* fix it */
 | 
						|
	ChangeText
 | 
						|
	{
 | 
						|
		strcat(U_text, "\n");
 | 
						|
		change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text);
 | 
						|
	}
 | 
						|
 | 
						|
	/* nothing in the buffer anymore */
 | 
						|
	U_line = -1L;
 | 
						|
 | 
						|
	/* return, with the cursor at the front of the line */
 | 
						|
	return m & ~(BLKSIZE - 1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifndef NO_ERRLIST
 | 
						|
MARK v_errlist(m)
 | 
						|
	MARK	m;
 | 
						|
{
 | 
						|
	cmd_errlist(m, m, CMD_ERRLIST, FALSE, "");
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#ifndef NO_AT
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_at(m, cnt, key)
 | 
						|
	MARK	m;
 | 
						|
	long	cnt;
 | 
						|
	int	key;
 | 
						|
{
 | 
						|
	int	size;
 | 
						|
 | 
						|
	size = cb2str(key, tmpblk.c, BLKSIZE);
 | 
						|
	if (size <= 0 || size == BLKSIZE)
 | 
						|
	{
 | 
						|
		return MARK_UNSET;
 | 
						|
	}
 | 
						|
 | 
						|
	execmap(0, tmpblk.c, FALSE);
 | 
						|
	return cursor;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#ifdef SIGTSTP
 | 
						|
MARK v_suspend()
 | 
						|
{
 | 
						|
	cmd_suspend(MARK_UNSET, MARK_UNSET, CMD_SUSPEND, FALSE, "");
 | 
						|
	return MARK_UNSET;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#ifndef NO_VISIBLE
 | 
						|
/*ARGSUSED*/
 | 
						|
MARK v_start(m, cnt, cmd)
 | 
						|
	MARK	m;	/* starting point for a v or V command */
 | 
						|
	long	cnt;	/* ignored */
 | 
						|
	int	cmd;	/* either 'v' or 'V' */
 | 
						|
{
 | 
						|
	if (V_from)
 | 
						|
	{
 | 
						|
		V_from = MARK_UNSET;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		V_from = m;
 | 
						|
		V_linemd = isupper(cmd);
 | 
						|
	}
 | 
						|
	return m;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef NO_POPUP
 | 
						|
# define MENU_HEIGHT 11
 | 
						|
# define MENU_WIDTH  23
 | 
						|
MARK v_popup(m, n)
 | 
						|
	MARK		m, n;	/* the range of text to change */
 | 
						|
{
 | 
						|
	int		i;
 | 
						|
	int		y, x;	/* position where the window will pop up at */
 | 
						|
	int		key;	/* keystroke from the user */
 | 
						|
	int		sel;	/* index of the selected operation */
 | 
						|
	static int	dfltsel;/* default value of sel */
 | 
						|
	static char	*labels[11] =
 | 
						|
	{
 | 
						|
		"ESC cancel!         ",
 | 
						|
		" d  delete (cut)    ",
 | 
						|
		" y  yank (copy)     ",
 | 
						|
		" p  paste after     ",
 | 
						|
		" P  paste before    ",
 | 
						|
		" >  more indented   ",
 | 
						|
		" <  less indented   ",
 | 
						|
		" =  reformat        ",
 | 
						|
		" !  external filter ",
 | 
						|
		" ZZ save & exit     ",
 | 
						|
		" u  undo previous   "
 | 
						|
	};
 | 
						|
 | 
						|
	/* try to position the menu near the cursor */
 | 
						|
	x = physcol - (MENU_WIDTH / 2);
 | 
						|
	if (x < 0)
 | 
						|
		x = 0;
 | 
						|
	else if (x + MENU_WIDTH + 2 > COLS)
 | 
						|
		x = COLS - MENU_WIDTH - 2;
 | 
						|
	if (markline(cursor) < topline || markline(cursor) > botline)
 | 
						|
		y = 0;
 | 
						|
	else if (markline(cursor) + 1L + MENU_HEIGHT > botline)
 | 
						|
		y = (int)(markline(cursor) - topline) - MENU_HEIGHT;
 | 
						|
	else
 | 
						|
		y = (int)(markline(cursor) - topline) + 1L;
 | 
						|
 | 
						|
	/* draw the menu */
 | 
						|
	for (sel = 0; sel < MENU_HEIGHT; sel++)
 | 
						|
	{
 | 
						|
		move(y + sel, x);
 | 
						|
		do_POPUP();
 | 
						|
		if (sel == dfltsel)
 | 
						|
			qaddstr("-->");
 | 
						|
		else
 | 
						|
			qaddstr("   ");
 | 
						|
		qaddstr(labels[sel]);
 | 
						|
		do_SE();
 | 
						|
	}
 | 
						|
 | 
						|
	/* get a selection */
 | 
						|
	move(y + dfltsel, x + 4);
 | 
						|
	for (sel = dfltsel; (key = getkey(WHEN_POPUP)) != '\\' && key != '\r'; )
 | 
						|
	{
 | 
						|
		/* erase the selection arrow */
 | 
						|
		move(y + sel, x);
 | 
						|
		do_POPUP();
 | 
						|
		qaddstr("   ");
 | 
						|
		qaddstr(labels[sel]);
 | 
						|
		do_SE();
 | 
						|
 | 
						|
		/* process the user's keystroke */
 | 
						|
		if (key == 'j' && sel < MENU_HEIGHT - 1)
 | 
						|
		{
 | 
						|
			sel++;
 | 
						|
		}
 | 
						|
		else if (key == 'k' && sel > 0)
 | 
						|
		{
 | 
						|
			sel--;
 | 
						|
		}
 | 
						|
		else if (key == '\033')
 | 
						|
		{
 | 
						|
			sel = 0;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			for (i = 1; i < MENU_HEIGHT && labels[i][1] != key; i++)
 | 
						|
			{
 | 
						|
			}
 | 
						|
			if (i < MENU_HEIGHT)
 | 
						|
			{
 | 
						|
				sel = i;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* redraw the arrow, possibly in a new place */
 | 
						|
		move(y + sel, x);
 | 
						|
		do_POPUP();
 | 
						|
		qaddstr("-->");
 | 
						|
		qaddstr(labels[sel]);
 | 
						|
		do_SE();
 | 
						|
		move(y + sel, x + 4);
 | 
						|
	}
 | 
						|
 | 
						|
	/* in most cases, the default selection is "paste after" */
 | 
						|
	dfltsel = 3;
 | 
						|
 | 
						|
	/* perform the appropriate action */
 | 
						|
	switch (sel)
 | 
						|
	{
 | 
						|
	  case 0:
 | 
						|
		m = cursor;
 | 
						|
		dfltsel = 0;
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 1: /* delete (cut) */
 | 
						|
		m = v_delete(m, n);
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 2: /* yank (copy) */
 | 
						|
		m = v_yank(m, n);
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 3: /* paste after */
 | 
						|
		m = v_paste(n, 1L, 'P');
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 4: /* paste before */
 | 
						|
		m = v_paste(m, 1L, 'P');
 | 
						|
		dfltsel = 4;
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 5: /* more indented */
 | 
						|
		m = v_rshift(m, n);
 | 
						|
		dfltsel = 5;
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 6: /* less indented */
 | 
						|
		m = v_lshift(m, n);
 | 
						|
		dfltsel = 6;
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 7: /* reformat */
 | 
						|
		m = v_reformat(m, n);
 | 
						|
		dfltsel = 7;
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 8: /* external filter */
 | 
						|
		m = v_filter(m, n);
 | 
						|
		dfltsel = 0;
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 9: /* save & exit */
 | 
						|
		/* get confirmation first */
 | 
						|
		do
 | 
						|
		{
 | 
						|
			key = getkey(0);
 | 
						|
		} while (key != '\\' && key != 'Z' && key != '\r'    /* good */
 | 
						|
		      && key != '\033');			     /* bad  */
 | 
						|
		if (key != '\033')
 | 
						|
		{
 | 
						|
			m = v_xit(m, 0L, 'Z');
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
	  case 10: /* undo previous */
 | 
						|
		m = v_undo(m);
 | 
						|
		dfltsel = 9;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* arrange for the menu to be erased (except that "chg from kbd"
 | 
						|
	 * already erased it, and "save & exit" doesn't care)
 | 
						|
	 */
 | 
						|
	if (sel != 5 && sel != 9)
 | 
						|
		redraw(MARK_UNSET, FALSE);
 | 
						|
 | 
						|
	return m;
 | 
						|
}
 | 
						|
#endif /* undef NO_POPUP */
 |