119304Speter/*-
219304Speter * Copyright (c) 1992, 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
1319304Speterstatic const char sccsid[] = "@(#)ex_visual.c	10.13 (Berkeley) 6/28/96";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
1819304Speter#include <sys/time.h>
1919304Speter
2019304Speter#include <bitstring.h>
2119304Speter#include <limits.h>
2219304Speter#include <stdio.h>
2319304Speter#include <stdlib.h>
2419304Speter#include <string.h>
2519304Speter#include <unistd.h>
2619304Speter
2719304Speter#include "../common/common.h"
2819304Speter#include "../vi/vi.h"
2919304Speter
3019304Speter/*
3119304Speter * ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags]
3219304Speter *	Switch to visual mode.
3319304Speter *
3419304Speter * PUBLIC: int ex_visual __P((SCR *, EXCMD *));
3519304Speter */
3619304Speterint
3719304Speterex_visual(sp, cmdp)
3819304Speter	SCR *sp;
3919304Speter	EXCMD *cmdp;
4019304Speter{
4119304Speter	SCR *tsp;
4219304Speter	size_t len;
4319304Speter	int pos;
4419304Speter	char buf[256];
4519304Speter
4619304Speter	/* If open option off, disallow visual command. */
4719304Speter	if (!O_ISSET(sp, O_OPEN)) {
4819304Speter		msgq(sp, M_ERR,
4919304Speter	    "175|The visual command requires that the open option be set");
5019304Speter		return (1);
5119304Speter	}
5219304Speter
5319304Speter	/* Move to the address. */
5419304Speter	sp->lno = cmdp->addr1.lno == 0 ? 1 : cmdp->addr1.lno;
5519304Speter
5619304Speter	/*
5719304Speter	 * Push a command based on the line position flags.  If no
5819304Speter	 * flag specified, the line goes at the top of the screen.
5919304Speter	 */
6019304Speter	switch (FL_ISSET(cmdp->iflags,
6119304Speter	    E_C_CARAT | E_C_DASH | E_C_DOT | E_C_PLUS)) {
6219304Speter	case E_C_CARAT:
6319304Speter		pos = '^';
6419304Speter		break;
6519304Speter	case E_C_DASH:
6619304Speter		pos = '-';
6719304Speter		break;
6819304Speter	case E_C_DOT:
6919304Speter		pos = '.';
7019304Speter		break;
7119304Speter	case E_C_PLUS:
7219304Speter		pos = '+';
7319304Speter		break;
7419304Speter	default:
7519304Speter		sp->frp->lno = sp->lno;
7619304Speter		sp->frp->cno = 0;
7719304Speter		(void)nonblank(sp, sp->lno, &sp->cno);
7819304Speter		F_SET(sp->frp, FR_CURSORSET);
7919304Speter		goto nopush;
8019304Speter	}
8119304Speter
8219304Speter	if (FL_ISSET(cmdp->iflags, E_C_COUNT))
8319304Speter		len = snprintf(buf, sizeof(buf),
8438022Sbde		     "%luz%c%lu", (u_long)sp->lno, pos, cmdp->count);
8519304Speter	else
8638022Sbde		len = snprintf(buf, sizeof(buf), "%luz%c",
8738022Sbde		    (u_long)sp->lno, pos);
8819304Speter	(void)v_event_push(sp, NULL, buf, len, CH_NOMAP | CH_QUOTED);
8919304Speter
9019304Speter	/*
9119304Speter	 * !!!
9219304Speter	 * Historically, if no line address was specified, the [p#l] flags
9319304Speter	 * caused the cursor to be moved to the last line of the file, which
9419304Speter	 * was then positioned as described above.  This seems useless, so
9519304Speter	 * I haven't implemented it.
9619304Speter	 */
9719304Speter	switch (FL_ISSET(cmdp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT)) {
9819304Speter	case E_C_HASH:
9919304Speter		O_SET(sp, O_NUMBER);
10019304Speter		break;
10119304Speter	case E_C_LIST:
10219304Speter		O_SET(sp, O_LIST);
10319304Speter		break;
10419304Speter	case E_C_PRINT:
10519304Speter		break;
10619304Speter	}
10719304Speter
10819304Speternopush:	/*
10919304Speter	 * !!!
11019304Speter	 * You can call the visual part of the editor from within an ex
11119304Speter	 * global command.
11219304Speter	 *
11319304Speter	 * XXX
11419304Speter	 * Historically, undoing a visual session was a single undo command,
11519304Speter	 * i.e. you could undo all of the changes you made in visual mode.
11619304Speter	 * We don't get this right; I'm waiting for the new logging code to
11719304Speter	 * be available.
11819304Speter	 *
11919304Speter	 * It's explicit, don't have to wait for the user, unless there's
12019304Speter	 * already a reason to wait.
12119304Speter	 */
12219304Speter	if (!F_ISSET(sp, SC_SCR_EXWROTE))
12319304Speter		F_SET(sp, SC_EX_WAIT_NO);
12419304Speter
12519304Speter	if (F_ISSET(sp, SC_EX_GLOBAL)) {
12619304Speter		/*
12719304Speter		 * When the vi screen(s) exit, we don't want to lose our hold
12819304Speter		 * on this screen or this file, otherwise we're going to fail
12919304Speter		 * fairly spectacularly.
13019304Speter		 */
13119304Speter		++sp->refcnt;
13219304Speter		++sp->ep->refcnt;
13319304Speter
13419304Speter		/*
13519304Speter		 * Fake up a screen pointer -- vi doesn't get to change our
13619304Speter		 * underlying file, regardless.
13719304Speter		 */
13819304Speter		tsp = sp;
13919304Speter		if (vi(&tsp))
14019304Speter			return (1);
14119304Speter
14219304Speter		/*
14319304Speter		 * !!!
14419304Speter		 * Historically, if the user exited the vi screen(s) using an
14519304Speter		 * ex quit command (e.g. :wq, :q) ex/vi exited, it was only if
14619304Speter		 * they exited vi using the Q command that ex continued.  Some
14719304Speter		 * early versions of nvi continued in ex regardless, but users
14819304Speter		 * didn't like the semantic.
14919304Speter		 *
15019304Speter		 * Reset the screen.
15119304Speter		 */
15219304Speter		if (ex_init(sp))
15319304Speter			return (1);
15419304Speter
15519304Speter		/* Move out of the vi screen. */
15619304Speter		(void)ex_puts(sp, "\n");
15719304Speter	} else {
15819304Speter		F_CLR(sp, SC_EX | SC_SCR_EX);
15919304Speter		F_SET(sp, SC_VI);
16019304Speter	}
16119304Speter	return (0);
16219304Speter}
163