1/*-
2 * Copyright (c) 1992, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 *	Keith Bostic.  All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#ifndef lint
13static const char sccsid[] = "$Id: ex_visual.c,v 10.16 2001/08/29 11:04:13 skimo Exp $";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/time.h>
19
20#include <bitstring.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26
27#include "../common/common.h"
28#include "../vi/vi.h"
29
30/*
31 * ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags]
32 *	Switch to visual mode.
33 *
34 * PUBLIC: int ex_visual __P((SCR *, EXCMD *));
35 */
36int
37ex_visual(SCR *sp, EXCMD *cmdp)
38{
39	SCR *tsp;
40	size_t len;
41	int pos;
42	char buf[256];
43	size_t wlen;
44	CHAR_T *wp;
45
46	/* If open option off, disallow visual command. */
47	if (!O_ISSET(sp, O_OPEN)) {
48		msgq(sp, M_ERR,
49	    "175|The visual command requires that the open option be set");
50		return (1);
51	}
52
53	/* Move to the address. */
54	sp->lno = cmdp->addr1.lno == 0 ? 1 : cmdp->addr1.lno;
55
56	/*
57	 * Push a command based on the line position flags.  If no
58	 * flag specified, the line goes at the top of the screen.
59	 */
60	switch (FL_ISSET(cmdp->iflags,
61	    E_C_CARAT | E_C_DASH | E_C_DOT | E_C_PLUS)) {
62	case E_C_CARAT:
63		pos = '^';
64		break;
65	case E_C_DASH:
66		pos = '-';
67		break;
68	case E_C_DOT:
69		pos = '.';
70		break;
71	case E_C_PLUS:
72		pos = '+';
73		break;
74	default:
75		sp->frp->lno = sp->lno;
76		sp->frp->cno = 0;
77		(void)nonblank(sp, sp->lno, &sp->cno);
78		F_SET(sp->frp, FR_CURSORSET);
79		goto nopush;
80	}
81
82	if (FL_ISSET(cmdp->iflags, E_C_COUNT))
83		len = snprintf(buf, sizeof(buf),
84		     "%luz%c%lu", (u_long)sp->lno, pos, cmdp->count);
85	else
86		len = snprintf(buf, sizeof(buf), "%luz%c", (u_long)sp->lno, pos);
87	CHAR2INT(sp, buf, len, wp, wlen);
88	(void)v_event_push(sp, NULL, wp, wlen, CH_NOMAP | CH_QUOTED);
89
90	/*
91	 * !!!
92	 * Historically, if no line address was specified, the [p#l] flags
93	 * caused the cursor to be moved to the last line of the file, which
94	 * was then positioned as described above.  This seems useless, so
95	 * I haven't implemented it.
96	 */
97	switch (FL_ISSET(cmdp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT)) {
98	case E_C_HASH:
99		O_SET(sp, O_NUMBER);
100		break;
101	case E_C_LIST:
102		O_SET(sp, O_LIST);
103		break;
104	case E_C_PRINT:
105		break;
106	}
107
108nopush:	/*
109	 * !!!
110	 * You can call the visual part of the editor from within an ex
111	 * global command.
112	 *
113	 * XXX
114	 * Historically, undoing a visual session was a single undo command,
115	 * i.e. you could undo all of the changes you made in visual mode.
116	 * We don't get this right; I'm waiting for the new logging code to
117	 * be available.
118	 *
119	 * It's explicit, don't have to wait for the user, unless there's
120	 * already a reason to wait.
121	 */
122	if (!F_ISSET(sp, SC_SCR_EXWROTE))
123		F_SET(sp, SC_EX_WAIT_NO);
124
125	if (F_ISSET(sp, SC_EX_GLOBAL)) {
126		/*
127		 * When the vi screen(s) exit, we don't want to lose our hold
128		 * on this screen or this file, otherwise we're going to fail
129		 * fairly spectacularly.
130		 */
131		++sp->refcnt;
132		++sp->ep->refcnt;
133		/* XXXX where is this decremented ? */
134
135		/*
136		 * Fake up a screen pointer -- vi doesn't get to change our
137		 * underlying file, regardless.
138		 */
139		tsp = sp;
140		if (vi(&tsp))
141			return (1);
142
143		/*
144		 * !!!
145		 * Historically, if the user exited the vi screen(s) using an
146		 * ex quit command (e.g. :wq, :q) ex/vi exited, it was only if
147		 * they exited vi using the Q command that ex continued.  Some
148		 * early versions of nvi continued in ex regardless, but users
149		 * didn't like the semantic.
150		 *
151		 * Reset the screen.
152		 */
153		if (ex_init(sp))
154			return (1);
155
156		/* Move out of the vi screen. */
157		(void)ex_puts(sp, "\n");
158	} else {
159		F_CLR(sp, SC_EX | SC_SCR_EX);
160		F_SET(sp, SC_VI);
161	}
162	return (0);
163}
164