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