1/*	$NetBSD: v_event.c,v 1.3 2009/01/18 03:45:50 lukem Exp $ */
2
3/*-
4 * Copyright (c) 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: v_event.c,v 8.21 2001/06/25 15:19:31 skimo Exp (Berkeley) Date: 2001/06/25 15:19:31";
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 <ctype.h>
22#include <errno.h>
23#include <limits.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include "../common/common.h"
30#include "../ipc/ip.h"
31#include "vi.h"
32
33/*
34 * v_c_settop --
35 *	Scrollbar position.
36 */
37static int
38v_c_settop(SCR *sp, VICMD *vp)
39{
40	SMAP *smp;
41	size_t x = 0, y = LASTLINE(sp); /* Future: change to -1 to not
42					 * display the cursor
43					 */
44	size_t tx, ty = -1;
45
46	/*
47	 * We want to scroll the screen, without changing the cursor position.
48	 * So, we fill the screen map and then flush it to the screen.  Then,
49	 * set the VIP_S_REFRESH flag so the main vi loop doesn't update the
50	 * screen.  When the next real command happens, the refresh code will
51	 * notice that the screen map is way wrong and fix it.
52	 *
53	 * XXX
54	 * There may be a serious performance problem here -- we're doing no
55	 * optimization whatsoever, which means that we're copying the entire
56	 * screen out to the X11 screen code on each change.
57	 */
58	if (vs_sm_fill(sp, vp->ev.e_lno, P_TOP))
59		return (1);
60	for (smp = HMAP; smp <= TMAP; ++smp) {
61                SMAP_FLUSH(smp);
62		if (vs_line(sp, smp, &ty, &tx))
63			return (1);
64		if (ty != (size_t)-1) {
65			y = ty;
66			x = tx;
67		}
68        }
69	(void)sp->gp->scr_move(sp, y, x);
70
71	F_SET(VIP(sp), VIP_S_REFRESH);
72
73	return (sp->gp->scr_refresh(sp, 0));
74}
75
76/*
77 * v_edit --
78 *	Edit command.
79 */
80static int
81v_edit(SCR *sp, VICMD *vp)
82{
83	EXCMD cmd;
84
85	ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
86	argv_exp0(sp, &cmd, vp->ev.e_csp, vp->ev.e_len);
87	return (v_exec_ex(sp, vp, &cmd));
88}
89
90/*
91 * v_editopt --
92 *	Set an option value.
93 */
94static int
95v_editopt(SCR *sp, VICMD *vp)
96{
97	int rval;
98	const char *np;
99	size_t nlen;
100	char *p2;
101
102	INT2CHAR(sp, vp->ev.e_str2, STRLEN(vp->ev.e_str2)+1, np, nlen);
103	p2 = strdup(np);
104	rval = api_opts_set(sp, vp->ev.e_str1, p2,
105			    vp->ev.e_val1, vp->ev.e_val1);
106	if (sp->gp->scr_reply != NULL)
107		(void)sp->gp->scr_reply(sp, rval, NULL);
108	free(p2);
109	return (rval);
110}
111
112/*
113 * v_editsplit --
114 *	Edit in a split screen.
115 */
116static int
117v_editsplit(SCR *sp, VICMD *vp)
118{
119	EXCMD cmd;
120
121	ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
122	F_SET(&cmd, E_NEWSCREEN);
123	argv_exp0(sp, &cmd, vp->ev.e_csp, vp->ev.e_len);
124	return (v_exec_ex(sp, vp, &cmd));
125}
126
127/*
128 * v_tag --
129 *	Tag command.
130 */
131static int
132v_tag(SCR *sp, VICMD *vp)
133{
134	EXCMD cmd;
135
136	if (v_curword(sp))
137		return (1);
138
139	ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, OOBLNO, 0);
140	argv_exp0(sp, &cmd, VIP(sp)->keyw, STRLEN(VIP(sp)->keyw));
141	return (v_exec_ex(sp, vp, &cmd));
142}
143
144/*
145 * v_tagas --
146 *	Tag on the supplied string.
147 */
148static int
149v_tagas(SCR *sp, VICMD *vp)
150{
151	EXCMD cmd;
152
153	ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, OOBLNO, 0);
154	argv_exp0(sp, &cmd, vp->ev.e_csp, vp->ev.e_len);
155	return (v_exec_ex(sp, vp, &cmd));
156}
157
158/*
159 * v_tagsplit --
160 *	Tag in a split screen.
161 */
162static int
163v_tagsplit(SCR *sp, VICMD *vp)
164{
165	EXCMD cmd;
166
167	if (v_curword(sp))
168		return (1);
169
170	ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, OOBLNO, 0);
171	F_SET(&cmd, E_NEWSCREEN);
172	argv_exp0(sp, &cmd, VIP(sp)->keyw, STRLEN(VIP(sp)->keyw));
173	return (v_exec_ex(sp, vp, &cmd));
174}
175
176/*
177 * v_quit --
178 *	Quit command.
179 */
180static int
181v_quit(SCR *sp, VICMD *vp)
182{
183	EXCMD cmd;
184
185	ex_cinit(sp, &cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0);
186	return (v_exec_ex(sp, vp, &cmd));
187}
188
189/*
190 * v_erepaint --
191 *	Repaint selected lines from the screen.
192 *
193 * PUBLIC: int v_erepaint __P((SCR *, EVENT *));
194 */
195int
196v_erepaint(SCR *sp, EVENT *evp)
197{
198	SMAP *smp;
199
200	for (; evp->e_flno <= evp->e_tlno; ++evp->e_flno) {
201		smp = HMAP + evp->e_flno - 1;
202		SMAP_FLUSH(smp);
203		if (vs_line(sp, smp, NULL, NULL))
204			return (1);
205	}
206	return (0);
207}
208
209/*
210 * v_sel_end --
211 *	End selection.
212 */
213static int
214v_sel_end(SCR *sp, EVENT *evp)
215{
216	SMAP *smp;
217	VI_PRIVATE *vip;
218
219	smp = HMAP + evp->e_lno;
220	if (smp > TMAP) {
221		/* XXX */
222		return (1);
223	}
224
225	vip = VIP(sp);
226	vip->sel.lno = smp->lno;
227	vip->sel.cno =
228	    vs_colpos(sp, smp->lno, evp->e_cno + (smp->soff - 1) * sp->cols);
229	return (0);
230}
231
232/*
233 * v_sel_start --
234 *	Start selection.
235 */
236static int
237v_sel_start(SCR *sp, EVENT *evp)
238{
239	SMAP *smp;
240	VI_PRIVATE *vip;
241
242	smp = HMAP + evp->e_lno;
243	if (smp > TMAP) {
244		/* XXX */
245		return (1);
246	}
247
248	vip = VIP(sp);
249	vip->sel.lno = smp->lno;
250	vip->sel.cno =
251	    vs_colpos(sp, smp->lno, evp->e_cno + (smp->soff - 1) * sp->cols);
252	return (0);
253}
254
255/*
256 * v_wq --
257 *	Write and quit command.
258 */
259static int
260v_wq(SCR *sp, VICMD *vp)
261{
262	EXCMD cmd;
263
264	ex_cinit(sp, &cmd, C_WQ, 0, OOBLNO, OOBLNO, 0);
265
266	cmd.addr1.lno = 1;
267	if (db_last(sp, &cmd.addr2.lno))
268		return (1);
269	return (v_exec_ex(sp, vp, &cmd));
270}
271
272/*
273 * v_write --
274 *	Write command.
275 */
276static int
277v_write(SCR *sp, VICMD *vp)
278{
279	EXCMD cmd;
280
281	ex_cinit(sp, &cmd, C_WRITE, 0, OOBLNO, OOBLNO, 0);
282
283	cmd.addr1.lno = 1;
284	if (db_last(sp, &cmd.addr2.lno))
285		return (1);
286	return (v_exec_ex(sp, vp, &cmd));
287}
288
289/*
290 * v_writeas --
291 *	Write command.
292 */
293static int
294v_writeas(SCR *sp, VICMD *vp)
295{
296	EXCMD cmd;
297
298	ex_cinit(sp, &cmd, C_WRITE, 0, OOBLNO, OOBLNO, 0);
299	argv_exp0(sp, &cmd, vp->ev.e_csp, vp->ev.e_len);
300
301	cmd.addr1.lno = 1;
302	if (db_last(sp, &cmd.addr2.lno))
303		return (1);
304	return (v_exec_ex(sp, vp, &cmd));
305}
306
307/*
308 * v_event --
309 *	Find the event associated with a function.
310 *
311 * PUBLIC: int v_event __P((SCR *, VICMD *));
312 */
313int
314v_event(SCR *sp, VICMD *vp)
315{
316	/* This array maps events to vi command functions. */
317#define VIKEYDEF(a, b) { a, b, NULL, NULL }
318	static VIKEYS const vievents[] = {
319#define	V_C_SETTOP	 0				/* VI_C_SETTOP */
320		VIKEYDEF(v_c_settop,	0),
321#define	V_EDIT		 1				/* VI_EDIT */
322		VIKEYDEF(v_edit,	0),
323#define	V_EDITOPT	 2				/* VI_EDITOPT */
324		VIKEYDEF(v_editopt,	0),
325#define	V_EDITSPLIT	 3				/* VI_EDITSPLIT */
326		VIKEYDEF(v_editsplit,	0),
327#define	V_EMARK		 4				/* VI_MOUSE_MOVE */
328		VIKEYDEF(v_emark,	V_ABS_L|V_MOVE),
329#define	V_QUIT		 5				/* VI_QUIT */
330		VIKEYDEF(v_quit,	0),
331#define	V_SEARCH	 6				/* VI_SEARCH */
332		VIKEYDEF(v_esearch,	V_ABS_L|V_MOVE),
333#define	V_TAG		 7				/* VI_TAG */
334		VIKEYDEF(v_tag,	0),
335#define	V_TAGAS	 8					/* VI_TAGAS */
336		VIKEYDEF(v_tagas,	0),
337#define	V_TAGSPLIT	 9				/* VI_TAGSPLIT */
338		VIKEYDEF(v_tagsplit,	0),
339#define	V_WQ		10				/* VI_WQ */
340		VIKEYDEF(v_wq,		0),
341#define	V_WRITE	11					/* VI_WRITE */
342		VIKEYDEF(v_write,	0),
343#define	V_WRITEAS	12				/* VI_WRITEAS */
344		VIKEYDEF(v_writeas,	0),
345	};
346
347	switch (vp->ev.e_ipcom) {
348	case VI_C_BOL:
349		vp->kp = &vikeys['0'];
350		break;
351	case VI_C_BOTTOM:
352		vp->kp = &vikeys['G'];
353		break;
354	case VI_C_DEL:
355		vp->kp = &vikeys['x'];
356		break;
357	case VI_C_DOWN:
358		F_SET(vp, VC_C1SET);
359		vp->count = vp->ev.e_lno;
360		vp->kp = &vikeys['\012'];
361		break;
362	case VI_C_EOL:
363		vp->kp = &vikeys['$'];
364		break;
365	case VI_C_INSERT:
366		vp->kp = &vikeys['i'];
367		break;
368	case VI_C_LEFT:
369		vp->kp = &vikeys['\010'];
370		break;
371	case VI_C_PGDOWN:
372		F_SET(vp, VC_C1SET);
373		vp->count = vp->ev.e_lno;
374		vp->kp = &vikeys['\006'];
375		break;
376	case VI_C_PGUP:
377		F_SET(vp, VC_C1SET);
378		vp->count = vp->ev.e_lno;
379		vp->kp = &vikeys['\002'];
380		break;
381	case VI_C_RIGHT:
382		vp->kp = &vikeys['\040'];
383		break;
384	case VI_C_SEARCH:
385		vp->kp = &vievents[V_SEARCH];
386		break;
387	case VI_C_SETTOP:
388		vp->kp = &vievents[V_C_SETTOP];
389		break;
390	case VI_C_TOP:
391		F_SET(vp, VC_C1SET);
392		vp->count = 1;
393		vp->kp = &vikeys['G'];
394		break;
395	case VI_C_UP:
396		F_SET(vp, VC_C1SET);
397		vp->count = vp->ev.e_lno;
398		vp->kp = &vikeys['\020'];
399		break;
400	case VI_EDIT:
401		vp->kp = &vievents[V_EDIT];
402		break;
403	case VI_EDITOPT:
404		vp->kp = &vievents[V_EDITOPT];
405		break;
406	case VI_EDITSPLIT:
407		vp->kp = &vievents[V_EDITSPLIT];
408		break;
409	case VI_MOUSE_MOVE:
410		vp->kp = &vievents[V_EMARK];
411		break;
412	case VI_SEL_END:
413		v_sel_end(sp, &vp->ev);
414		/* XXX RETURN IGNORE */
415		break;
416	case VI_SEL_START:
417		v_sel_start(sp, &vp->ev);
418		/* XXX RETURN IGNORE */
419		break;
420	case VI_QUIT:
421		vp->kp = &vievents[V_QUIT];
422		break;
423	case VI_TAG:
424		vp->kp = &vievents[V_TAG];
425		break;
426	case VI_TAGAS:
427		vp->kp = &vievents[V_TAGAS];
428		break;
429	case VI_TAGSPLIT:
430		vp->kp = &vievents[V_TAGSPLIT];
431		break;
432	case VI_UNDO:
433		vp->kp = &vikeys['u'];
434		break;
435	case VI_WQ:
436		vp->kp = &vievents[V_WQ];
437		break;
438	case VI_WRITE:
439		vp->kp = &vievents[V_WRITE];
440		break;
441	case VI_WRITEAS:
442		vp->kp = &vievents[V_WRITEAS];
443		break;
444	default:
445		return (1);
446	}
447	return (0);
448}
449