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
14 static 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  */
41 static int
v_c_settop(SCR * sp,VICMD * vp)42 v_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  */
84 static int
v_edit(SCR * sp,VICMD * vp)85 v_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  */
98 static int
v_editopt(SCR * sp,VICMD * vp)99 v_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  */
120 static int
v_editsplit(SCR * sp,VICMD * vp)121 v_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  */
135 static int
v_tag(SCR * sp,VICMD * vp)136 v_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  */
152 static int
v_tagas(SCR * sp,VICMD * vp)153 v_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  */
166 static int
v_tagsplit(SCR * sp,VICMD * vp)167 v_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  */
184 static int
v_quit(SCR * sp,VICMD * vp)185 v_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  */
199 int
v_erepaint(SCR * sp,EVENT * evp)200 v_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  */
217 static int
v_sel_end(SCR * sp,EVENT * evp)218 v_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  */
240 static int
v_sel_start(SCR * sp,EVENT * evp)241 v_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  */
263 static int
v_wq(SCR * sp,VICMD * vp)264 v_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  */
280 static int
v_write(SCR * sp,VICMD * vp)281 v_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  */
297 static int
v_writeas(SCR * sp,VICMD * vp)298 v_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  */
317 int
v_event(SCR * sp,VICMD * vp)318 v_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