1 |
|
|
/* $OpenBSD: vi.c,v 1.25 2016/05/06 13:12:52 schwarze Exp $ */ |
2 |
|
|
/* $NetBSD: vi.c,v 1.33 2011/02/17 16:44:48 joerg Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (c) 1992, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* This code is derived from software contributed to Berkeley by |
9 |
|
|
* Christos Zoulas of Cornell University. |
10 |
|
|
* |
11 |
|
|
* Redistribution and use in source and binary forms, with or without |
12 |
|
|
* modification, are permitted provided that the following conditions |
13 |
|
|
* are met: |
14 |
|
|
* 1. Redistributions of source code must retain the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer. |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer in the |
18 |
|
|
* documentation and/or other materials provided with the distribution. |
19 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
20 |
|
|
* may be used to endorse or promote products derived from this software |
21 |
|
|
* without specific prior written permission. |
22 |
|
|
* |
23 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
24 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
27 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
29 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
30 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
33 |
|
|
* SUCH DAMAGE. |
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
#include "config.h" |
37 |
|
|
|
38 |
|
|
/* |
39 |
|
|
* vi.c: Vi mode commands. |
40 |
|
|
*/ |
41 |
|
|
#include <sys/wait.h> |
42 |
|
|
#include <ctype.h> |
43 |
|
|
#include <limits.h> |
44 |
|
|
#include <stdlib.h> |
45 |
|
|
#include <string.h> |
46 |
|
|
#include <unistd.h> |
47 |
|
|
|
48 |
|
|
#include "el.h" |
49 |
|
|
#include "common.h" |
50 |
|
|
#include "emacs.h" |
51 |
|
|
#include "fcns.h" |
52 |
|
|
#include "vi.h" |
53 |
|
|
|
54 |
|
|
static el_action_t cv_action(EditLine *, wint_t); |
55 |
|
|
static el_action_t cv_paste(EditLine *, wint_t); |
56 |
|
|
|
57 |
|
|
/* cv_action(): |
58 |
|
|
* Handle vi actions. |
59 |
|
|
*/ |
60 |
|
|
static el_action_t |
61 |
|
|
cv_action(EditLine *el, wint_t c) |
62 |
|
|
{ |
63 |
|
|
|
64 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
65 |
|
|
/* 'cc', 'dd' and (possibly) friends */ |
66 |
|
|
if (c != (wint_t)el->el_chared.c_vcmd.action) |
67 |
|
|
return CC_ERROR; |
68 |
|
|
|
69 |
|
|
if (!(c & YANK)) |
70 |
|
|
cv_undo(el); |
71 |
|
|
cv_yank(el, el->el_line.buffer, |
72 |
|
|
(int)(el->el_line.lastchar - el->el_line.buffer)); |
73 |
|
|
el->el_chared.c_vcmd.action = NOP; |
74 |
|
|
el->el_chared.c_vcmd.pos = 0; |
75 |
|
|
if (!(c & YANK)) { |
76 |
|
|
el->el_line.lastchar = el->el_line.buffer; |
77 |
|
|
el->el_line.cursor = el->el_line.buffer; |
78 |
|
|
} |
79 |
|
|
if (c & INSERT) |
80 |
|
|
el->el_map.current = el->el_map.key; |
81 |
|
|
|
82 |
|
|
return CC_REFRESH; |
83 |
|
|
} |
84 |
|
|
el->el_chared.c_vcmd.pos = el->el_line.cursor; |
85 |
|
|
el->el_chared.c_vcmd.action = c; |
86 |
|
|
return CC_ARGHACK; |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
/* cv_paste(): |
90 |
|
|
* Paste previous deletion before or after the cursor |
91 |
|
|
*/ |
92 |
|
|
static el_action_t |
93 |
|
|
cv_paste(EditLine *el, wint_t c) |
94 |
|
|
{ |
95 |
|
|
c_kill_t *k = &el->el_chared.c_kill; |
96 |
|
|
size_t len = (size_t)(k->last - k->buf); |
97 |
|
|
|
98 |
|
|
if (k->buf == NULL || len == 0) |
99 |
|
|
return CC_ERROR; |
100 |
|
|
#ifdef DEBUG_PASTE |
101 |
|
|
(void) fprintf(el->el_errfile, "Paste: \"%.*ls\"\n", (int)len, |
102 |
|
|
k->buf); |
103 |
|
|
#endif |
104 |
|
|
|
105 |
|
|
cv_undo(el); |
106 |
|
|
|
107 |
|
|
if (!c && el->el_line.cursor < el->el_line.lastchar) |
108 |
|
|
el->el_line.cursor++; |
109 |
|
|
|
110 |
|
|
c_insert(el, (int)len); |
111 |
|
|
if (el->el_line.cursor + len > el->el_line.lastchar) |
112 |
|
|
return CC_ERROR; |
113 |
|
|
(void) memcpy(el->el_line.cursor, k->buf, len * |
114 |
|
|
sizeof(*el->el_line.cursor)); |
115 |
|
|
|
116 |
|
|
return CC_REFRESH; |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
|
120 |
|
|
/* vi_paste_next(): |
121 |
|
|
* Vi paste previous deletion to the right of the cursor |
122 |
|
|
* [p] |
123 |
|
|
*/ |
124 |
|
|
protected el_action_t |
125 |
|
|
/*ARGSUSED*/ |
126 |
|
|
vi_paste_next(EditLine *el, wint_t c __attribute__((__unused__))) |
127 |
|
|
{ |
128 |
|
|
|
129 |
|
|
return cv_paste(el, 0); |
130 |
|
|
} |
131 |
|
|
|
132 |
|
|
|
133 |
|
|
/* vi_paste_prev(): |
134 |
|
|
* Vi paste previous deletion to the left of the cursor |
135 |
|
|
* [P] |
136 |
|
|
*/ |
137 |
|
|
protected el_action_t |
138 |
|
|
/*ARGSUSED*/ |
139 |
|
|
vi_paste_prev(EditLine *el, wint_t c __attribute__((__unused__))) |
140 |
|
|
{ |
141 |
|
|
|
142 |
|
|
return cv_paste(el, 1); |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
|
146 |
|
|
/* vi_prev_big_word(): |
147 |
|
|
* Vi move to the previous space delimited word |
148 |
|
|
* [B] |
149 |
|
|
*/ |
150 |
|
|
protected el_action_t |
151 |
|
|
/*ARGSUSED*/ |
152 |
|
|
vi_prev_big_word(EditLine *el, wint_t c __attribute__((__unused__))) |
153 |
|
|
{ |
154 |
|
|
|
155 |
|
|
if (el->el_line.cursor == el->el_line.buffer) |
156 |
|
|
return CC_ERROR; |
157 |
|
|
|
158 |
|
|
el->el_line.cursor = cv_prev_word(el->el_line.cursor, |
159 |
|
|
el->el_line.buffer, |
160 |
|
|
el->el_state.argument, |
161 |
|
|
cv__isWord); |
162 |
|
|
|
163 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
164 |
|
|
cv_delfini(el); |
165 |
|
|
return CC_REFRESH; |
166 |
|
|
} |
167 |
|
|
return CC_CURSOR; |
168 |
|
|
} |
169 |
|
|
|
170 |
|
|
|
171 |
|
|
/* vi_prev_word(): |
172 |
|
|
* Vi move to the previous word |
173 |
|
|
* [b] |
174 |
|
|
*/ |
175 |
|
|
protected el_action_t |
176 |
|
|
/*ARGSUSED*/ |
177 |
|
|
vi_prev_word(EditLine *el, wint_t c __attribute__((__unused__))) |
178 |
|
|
{ |
179 |
|
|
|
180 |
|
|
if (el->el_line.cursor == el->el_line.buffer) |
181 |
|
|
return CC_ERROR; |
182 |
|
|
|
183 |
|
|
el->el_line.cursor = cv_prev_word(el->el_line.cursor, |
184 |
|
|
el->el_line.buffer, |
185 |
|
|
el->el_state.argument, |
186 |
|
|
cv__isword); |
187 |
|
|
|
188 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
189 |
|
|
cv_delfini(el); |
190 |
|
|
return CC_REFRESH; |
191 |
|
|
} |
192 |
|
|
return CC_CURSOR; |
193 |
|
|
} |
194 |
|
|
|
195 |
|
|
|
196 |
|
|
/* vi_next_big_word(): |
197 |
|
|
* Vi move to the next space delimited word |
198 |
|
|
* [W] |
199 |
|
|
*/ |
200 |
|
|
protected el_action_t |
201 |
|
|
/*ARGSUSED*/ |
202 |
|
|
vi_next_big_word(EditLine *el, wint_t c __attribute__((__unused__))) |
203 |
|
|
{ |
204 |
|
|
|
205 |
|
|
if (el->el_line.cursor >= el->el_line.lastchar - 1) |
206 |
|
|
return CC_ERROR; |
207 |
|
|
|
208 |
|
|
el->el_line.cursor = cv_next_word(el, el->el_line.cursor, |
209 |
|
|
el->el_line.lastchar, el->el_state.argument, cv__isWord); |
210 |
|
|
|
211 |
|
|
if (el->el_map.type == MAP_VI) |
212 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
213 |
|
|
cv_delfini(el); |
214 |
|
|
return CC_REFRESH; |
215 |
|
|
} |
216 |
|
|
return CC_CURSOR; |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
|
220 |
|
|
/* vi_next_word(): |
221 |
|
|
* Vi move to the next word |
222 |
|
|
* [w] |
223 |
|
|
*/ |
224 |
|
|
protected el_action_t |
225 |
|
|
/*ARGSUSED*/ |
226 |
|
|
vi_next_word(EditLine *el, wint_t c __attribute__((__unused__))) |
227 |
|
|
{ |
228 |
|
|
|
229 |
|
|
if (el->el_line.cursor >= el->el_line.lastchar - 1) |
230 |
|
|
return CC_ERROR; |
231 |
|
|
|
232 |
|
|
el->el_line.cursor = cv_next_word(el, el->el_line.cursor, |
233 |
|
|
el->el_line.lastchar, el->el_state.argument, cv__isword); |
234 |
|
|
|
235 |
|
|
if (el->el_map.type == MAP_VI) |
236 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
237 |
|
|
cv_delfini(el); |
238 |
|
|
return CC_REFRESH; |
239 |
|
|
} |
240 |
|
|
return CC_CURSOR; |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
|
244 |
|
|
/* vi_change_case(): |
245 |
|
|
* Vi change case of character under the cursor and advance one character |
246 |
|
|
* [~] |
247 |
|
|
*/ |
248 |
|
|
protected el_action_t |
249 |
|
|
vi_change_case(EditLine *el, wint_t c) |
250 |
|
|
{ |
251 |
|
|
int i; |
252 |
|
|
|
253 |
|
|
if (el->el_line.cursor >= el->el_line.lastchar) |
254 |
|
|
return CC_ERROR; |
255 |
|
|
cv_undo(el); |
256 |
|
|
for (i = 0; i < el->el_state.argument; i++) { |
257 |
|
|
|
258 |
|
|
c = *el->el_line.cursor; |
259 |
|
|
if (iswupper(c)) |
260 |
|
|
*el->el_line.cursor = towlower(c); |
261 |
|
|
else if (iswlower(c)) |
262 |
|
|
*el->el_line.cursor = towupper(c); |
263 |
|
|
|
264 |
|
|
if (++el->el_line.cursor >= el->el_line.lastchar) { |
265 |
|
|
el->el_line.cursor--; |
266 |
|
|
re_fastaddc(el); |
267 |
|
|
break; |
268 |
|
|
} |
269 |
|
|
re_fastaddc(el); |
270 |
|
|
} |
271 |
|
|
return CC_NORM; |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
|
275 |
|
|
/* vi_change_meta(): |
276 |
|
|
* Vi change prefix command |
277 |
|
|
* [c] |
278 |
|
|
*/ |
279 |
|
|
protected el_action_t |
280 |
|
|
/*ARGSUSED*/ |
281 |
|
|
vi_change_meta(EditLine *el, wint_t c __attribute__((__unused__))) |
282 |
|
|
{ |
283 |
|
|
|
284 |
|
|
/* |
285 |
|
|
* Delete with insert == change: first we delete and then we leave in |
286 |
|
|
* insert mode. |
287 |
|
|
*/ |
288 |
|
|
return cv_action(el, DELETE | INSERT); |
289 |
|
|
} |
290 |
|
|
|
291 |
|
|
|
292 |
|
|
/* vi_insert_at_bol(): |
293 |
|
|
* Vi enter insert mode at the beginning of line |
294 |
|
|
* [I] |
295 |
|
|
*/ |
296 |
|
|
protected el_action_t |
297 |
|
|
/*ARGSUSED*/ |
298 |
|
|
vi_insert_at_bol(EditLine *el, wint_t c __attribute__((__unused__))) |
299 |
|
|
{ |
300 |
|
|
|
301 |
|
|
el->el_line.cursor = el->el_line.buffer; |
302 |
|
|
cv_undo(el); |
303 |
|
|
el->el_map.current = el->el_map.key; |
304 |
|
|
return CC_CURSOR; |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
|
308 |
|
|
/* vi_replace_char(): |
309 |
|
|
* Vi replace character under the cursor with the next character typed |
310 |
|
|
* [r] |
311 |
|
|
*/ |
312 |
|
|
protected el_action_t |
313 |
|
|
/*ARGSUSED*/ |
314 |
|
|
vi_replace_char(EditLine *el, wint_t c __attribute__((__unused__))) |
315 |
|
|
{ |
316 |
|
|
|
317 |
|
|
if (el->el_line.cursor >= el->el_line.lastchar) |
318 |
|
|
return CC_ERROR; |
319 |
|
|
|
320 |
|
|
el->el_map.current = el->el_map.key; |
321 |
|
|
el->el_state.inputmode = MODE_REPLACE_1; |
322 |
|
|
cv_undo(el); |
323 |
|
|
return CC_ARGHACK; |
324 |
|
|
} |
325 |
|
|
|
326 |
|
|
|
327 |
|
|
/* vi_replace_mode(): |
328 |
|
|
* Vi enter replace mode |
329 |
|
|
* [R] |
330 |
|
|
*/ |
331 |
|
|
protected el_action_t |
332 |
|
|
/*ARGSUSED*/ |
333 |
|
|
vi_replace_mode(EditLine *el, wint_t c __attribute__((__unused__))) |
334 |
|
|
{ |
335 |
|
|
|
336 |
|
|
el->el_map.current = el->el_map.key; |
337 |
|
|
el->el_state.inputmode = MODE_REPLACE; |
338 |
|
|
cv_undo(el); |
339 |
|
|
return CC_NORM; |
340 |
|
|
} |
341 |
|
|
|
342 |
|
|
|
343 |
|
|
/* vi_substitute_char(): |
344 |
|
|
* Vi replace character under the cursor and enter insert mode |
345 |
|
|
* [s] |
346 |
|
|
*/ |
347 |
|
|
protected el_action_t |
348 |
|
|
/*ARGSUSED*/ |
349 |
|
|
vi_substitute_char(EditLine *el, wint_t c __attribute__((__unused__))) |
350 |
|
|
{ |
351 |
|
|
|
352 |
|
|
c_delafter(el, el->el_state.argument); |
353 |
|
|
el->el_map.current = el->el_map.key; |
354 |
|
|
return CC_REFRESH; |
355 |
|
|
} |
356 |
|
|
|
357 |
|
|
|
358 |
|
|
/* vi_substitute_line(): |
359 |
|
|
* Vi substitute entire line |
360 |
|
|
* [S] |
361 |
|
|
*/ |
362 |
|
|
protected el_action_t |
363 |
|
|
/*ARGSUSED*/ |
364 |
|
|
vi_substitute_line(EditLine *el, wint_t c __attribute__((__unused__))) |
365 |
|
|
{ |
366 |
|
|
|
367 |
|
|
cv_undo(el); |
368 |
|
|
cv_yank(el, el->el_line.buffer, |
369 |
|
|
(int)(el->el_line.lastchar - el->el_line.buffer)); |
370 |
|
|
(void) em_kill_line(el, 0); |
371 |
|
|
el->el_map.current = el->el_map.key; |
372 |
|
|
return CC_REFRESH; |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
|
376 |
|
|
/* vi_change_to_eol(): |
377 |
|
|
* Vi change to end of line |
378 |
|
|
* [C] |
379 |
|
|
*/ |
380 |
|
|
protected el_action_t |
381 |
|
|
/*ARGSUSED*/ |
382 |
|
|
vi_change_to_eol(EditLine *el, wint_t c __attribute__((__unused__))) |
383 |
|
|
{ |
384 |
|
|
|
385 |
|
|
cv_undo(el); |
386 |
|
|
cv_yank(el, el->el_line.cursor, |
387 |
|
|
(int)(el->el_line.lastchar - el->el_line.cursor)); |
388 |
|
|
(void) ed_kill_line(el, 0); |
389 |
|
|
el->el_map.current = el->el_map.key; |
390 |
|
|
return CC_REFRESH; |
391 |
|
|
} |
392 |
|
|
|
393 |
|
|
|
394 |
|
|
/* vi_insert(): |
395 |
|
|
* Vi enter insert mode |
396 |
|
|
* [i] |
397 |
|
|
*/ |
398 |
|
|
protected el_action_t |
399 |
|
|
/*ARGSUSED*/ |
400 |
|
|
vi_insert(EditLine *el, wint_t c __attribute__((__unused__))) |
401 |
|
|
{ |
402 |
|
|
|
403 |
|
|
el->el_map.current = el->el_map.key; |
404 |
|
|
cv_undo(el); |
405 |
|
|
return CC_NORM; |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
|
409 |
|
|
/* vi_add(): |
410 |
|
|
* Vi enter insert mode after the cursor |
411 |
|
|
* [a] |
412 |
|
|
*/ |
413 |
|
|
protected el_action_t |
414 |
|
|
/*ARGSUSED*/ |
415 |
|
|
vi_add(EditLine *el, wint_t c __attribute__((__unused__))) |
416 |
|
|
{ |
417 |
|
|
int ret; |
418 |
|
|
|
419 |
|
|
el->el_map.current = el->el_map.key; |
420 |
|
|
if (el->el_line.cursor < el->el_line.lastchar) { |
421 |
|
|
el->el_line.cursor++; |
422 |
|
|
if (el->el_line.cursor > el->el_line.lastchar) |
423 |
|
|
el->el_line.cursor = el->el_line.lastchar; |
424 |
|
|
ret = CC_CURSOR; |
425 |
|
|
} else |
426 |
|
|
ret = CC_NORM; |
427 |
|
|
|
428 |
|
|
cv_undo(el); |
429 |
|
|
|
430 |
|
|
return ret; |
431 |
|
|
} |
432 |
|
|
|
433 |
|
|
|
434 |
|
|
/* vi_add_at_eol(): |
435 |
|
|
* Vi enter insert mode at end of line |
436 |
|
|
* [A] |
437 |
|
|
*/ |
438 |
|
|
protected el_action_t |
439 |
|
|
/*ARGSUSED*/ |
440 |
|
|
vi_add_at_eol(EditLine *el, wint_t c __attribute__((__unused__))) |
441 |
|
|
{ |
442 |
|
|
|
443 |
|
|
el->el_map.current = el->el_map.key; |
444 |
|
|
el->el_line.cursor = el->el_line.lastchar; |
445 |
|
|
cv_undo(el); |
446 |
|
|
return CC_CURSOR; |
447 |
|
|
} |
448 |
|
|
|
449 |
|
|
|
450 |
|
|
/* vi_delete_meta(): |
451 |
|
|
* Vi delete prefix command |
452 |
|
|
* [d] |
453 |
|
|
*/ |
454 |
|
|
protected el_action_t |
455 |
|
|
/*ARGSUSED*/ |
456 |
|
|
vi_delete_meta(EditLine *el, wint_t c __attribute__((__unused__))) |
457 |
|
|
{ |
458 |
|
|
|
459 |
|
|
return cv_action(el, DELETE); |
460 |
|
|
} |
461 |
|
|
|
462 |
|
|
|
463 |
|
|
/* vi_end_big_word(): |
464 |
|
|
* Vi move to the end of the current space delimited word |
465 |
|
|
* [E] |
466 |
|
|
*/ |
467 |
|
|
protected el_action_t |
468 |
|
|
/*ARGSUSED*/ |
469 |
|
|
vi_end_big_word(EditLine *el, wint_t c __attribute__((__unused__))) |
470 |
|
|
{ |
471 |
|
|
|
472 |
|
|
if (el->el_line.cursor == el->el_line.lastchar) |
473 |
|
|
return CC_ERROR; |
474 |
|
|
|
475 |
|
|
el->el_line.cursor = cv__endword(el->el_line.cursor, |
476 |
|
|
el->el_line.lastchar, el->el_state.argument, cv__isWord); |
477 |
|
|
|
478 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
479 |
|
|
el->el_line.cursor++; |
480 |
|
|
cv_delfini(el); |
481 |
|
|
return CC_REFRESH; |
482 |
|
|
} |
483 |
|
|
return CC_CURSOR; |
484 |
|
|
} |
485 |
|
|
|
486 |
|
|
|
487 |
|
|
/* vi_end_word(): |
488 |
|
|
* Vi move to the end of the current word |
489 |
|
|
* [e] |
490 |
|
|
*/ |
491 |
|
|
protected el_action_t |
492 |
|
|
/*ARGSUSED*/ |
493 |
|
|
vi_end_word(EditLine *el, wint_t c __attribute__((__unused__))) |
494 |
|
|
{ |
495 |
|
|
|
496 |
|
|
if (el->el_line.cursor == el->el_line.lastchar) |
497 |
|
|
return CC_ERROR; |
498 |
|
|
|
499 |
|
|
el->el_line.cursor = cv__endword(el->el_line.cursor, |
500 |
|
|
el->el_line.lastchar, el->el_state.argument, cv__isword); |
501 |
|
|
|
502 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
503 |
|
|
el->el_line.cursor++; |
504 |
|
|
cv_delfini(el); |
505 |
|
|
return CC_REFRESH; |
506 |
|
|
} |
507 |
|
|
return CC_CURSOR; |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
|
511 |
|
|
/* vi_undo(): |
512 |
|
|
* Vi undo last change |
513 |
|
|
* [u] |
514 |
|
|
*/ |
515 |
|
|
protected el_action_t |
516 |
|
|
/*ARGSUSED*/ |
517 |
|
|
vi_undo(EditLine *el, wint_t c __attribute__((__unused__))) |
518 |
|
|
{ |
519 |
|
|
c_undo_t un = el->el_chared.c_undo; |
520 |
|
|
|
521 |
|
|
if (un.len == -1) |
522 |
|
|
return CC_ERROR; |
523 |
|
|
|
524 |
|
|
/* switch line buffer and undo buffer */ |
525 |
|
|
el->el_chared.c_undo.buf = el->el_line.buffer; |
526 |
|
|
el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer; |
527 |
|
|
el->el_chared.c_undo.cursor = |
528 |
|
|
(int)(el->el_line.cursor - el->el_line.buffer); |
529 |
|
|
el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); |
530 |
|
|
el->el_line.buffer = un.buf; |
531 |
|
|
el->el_line.cursor = un.buf + un.cursor; |
532 |
|
|
el->el_line.lastchar = un.buf + un.len; |
533 |
|
|
|
534 |
|
|
return CC_REFRESH; |
535 |
|
|
} |
536 |
|
|
|
537 |
|
|
|
538 |
|
|
/* vi_command_mode(): |
539 |
|
|
* Vi enter command mode (use alternative key bindings) |
540 |
|
|
* [<ESC>] |
541 |
|
|
*/ |
542 |
|
|
protected el_action_t |
543 |
|
|
/*ARGSUSED*/ |
544 |
|
|
vi_command_mode(EditLine *el, wint_t c __attribute__((__unused__))) |
545 |
|
|
{ |
546 |
|
|
|
547 |
|
|
/* [Esc] cancels pending action */ |
548 |
|
|
el->el_chared.c_vcmd.action = NOP; |
549 |
|
|
el->el_chared.c_vcmd.pos = 0; |
550 |
|
|
|
551 |
|
|
el->el_state.doingarg = 0; |
552 |
|
|
|
553 |
|
|
el->el_state.inputmode = MODE_INSERT; |
554 |
|
|
el->el_map.current = el->el_map.alt; |
555 |
|
|
#ifdef VI_MOVE |
556 |
|
|
if (el->el_line.cursor > el->el_line.buffer) |
557 |
|
|
el->el_line.cursor--; |
558 |
|
|
#endif |
559 |
|
|
return CC_CURSOR; |
560 |
|
|
} |
561 |
|
|
|
562 |
|
|
|
563 |
|
|
/* vi_zero(): |
564 |
|
|
* Vi move to the beginning of line |
565 |
|
|
* [0] |
566 |
|
|
*/ |
567 |
|
|
protected el_action_t |
568 |
|
|
vi_zero(EditLine *el, wint_t c) |
569 |
|
|
{ |
570 |
|
|
|
571 |
|
|
if (el->el_state.doingarg) |
572 |
|
|
return ed_argument_digit(el, c); |
573 |
|
|
|
574 |
|
|
el->el_line.cursor = el->el_line.buffer; |
575 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
576 |
|
|
cv_delfini(el); |
577 |
|
|
return CC_REFRESH; |
578 |
|
|
} |
579 |
|
|
return CC_CURSOR; |
580 |
|
|
} |
581 |
|
|
|
582 |
|
|
|
583 |
|
|
/* vi_delete_prev_char(): |
584 |
|
|
* Vi move to previous character (backspace) |
585 |
|
|
* [^H] in insert mode only |
586 |
|
|
*/ |
587 |
|
|
protected el_action_t |
588 |
|
|
/*ARGSUSED*/ |
589 |
|
|
vi_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) |
590 |
|
|
{ |
591 |
|
|
|
592 |
|
|
if (el->el_line.cursor <= el->el_line.buffer) |
593 |
|
|
return CC_ERROR; |
594 |
|
|
|
595 |
|
|
c_delbefore1(el); |
596 |
|
|
el->el_line.cursor--; |
597 |
|
|
return CC_REFRESH; |
598 |
|
|
} |
599 |
|
|
|
600 |
|
|
|
601 |
|
|
/* vi_list_or_eof(): |
602 |
|
|
* Vi list choices for completion or indicate end of file if empty line |
603 |
|
|
* [^D] |
604 |
|
|
*/ |
605 |
|
|
protected el_action_t |
606 |
|
|
/*ARGSUSED*/ |
607 |
|
|
vi_list_or_eof(EditLine *el, wint_t c) |
608 |
|
|
{ |
609 |
|
|
|
610 |
|
|
if (el->el_line.cursor == el->el_line.lastchar) { |
611 |
|
|
if (el->el_line.cursor == el->el_line.buffer) { |
612 |
|
|
terminal_writec(el, c); /* then do a EOF */ |
613 |
|
|
return CC_EOF; |
614 |
|
|
} else { |
615 |
|
|
/* |
616 |
|
|
* Here we could list completions, but it is an |
617 |
|
|
* error right now |
618 |
|
|
*/ |
619 |
|
|
terminal_beep(el); |
620 |
|
|
return CC_ERROR; |
621 |
|
|
} |
622 |
|
|
} else { |
623 |
|
|
#ifdef notyet |
624 |
|
|
re_goto_bottom(el); |
625 |
|
|
*el->el_line.lastchar = '\0'; /* just in case */ |
626 |
|
|
return CC_LIST_CHOICES; |
627 |
|
|
#else |
628 |
|
|
/* |
629 |
|
|
* Just complain for now. |
630 |
|
|
*/ |
631 |
|
|
terminal_beep(el); |
632 |
|
|
return CC_ERROR; |
633 |
|
|
#endif |
634 |
|
|
} |
635 |
|
|
} |
636 |
|
|
|
637 |
|
|
|
638 |
|
|
/* vi_kill_line_prev(): |
639 |
|
|
* Vi cut from beginning of line to cursor |
640 |
|
|
* [^U] |
641 |
|
|
*/ |
642 |
|
|
protected el_action_t |
643 |
|
|
/*ARGSUSED*/ |
644 |
|
|
vi_kill_line_prev(EditLine *el, wint_t c __attribute__((__unused__))) |
645 |
|
|
{ |
646 |
|
|
wchar_t *kp, *cp; |
647 |
|
|
|
648 |
|
|
cp = el->el_line.buffer; |
649 |
|
|
kp = el->el_chared.c_kill.buf; |
650 |
|
|
while (cp < el->el_line.cursor) |
651 |
|
|
*kp++ = *cp++; /* copy it */ |
652 |
|
|
el->el_chared.c_kill.last = kp; |
653 |
|
|
c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer)); |
654 |
|
|
el->el_line.cursor = el->el_line.buffer; /* zap! */ |
655 |
|
|
return CC_REFRESH; |
656 |
|
|
} |
657 |
|
|
|
658 |
|
|
|
659 |
|
|
/* vi_search_prev(): |
660 |
|
|
* Vi search history previous |
661 |
|
|
* [?] |
662 |
|
|
*/ |
663 |
|
|
protected el_action_t |
664 |
|
|
/*ARGSUSED*/ |
665 |
|
|
vi_search_prev(EditLine *el, wint_t c __attribute__((__unused__))) |
666 |
|
|
{ |
667 |
|
|
|
668 |
|
|
return cv_search(el, ED_SEARCH_PREV_HISTORY); |
669 |
|
|
} |
670 |
|
|
|
671 |
|
|
|
672 |
|
|
/* vi_search_next(): |
673 |
|
|
* Vi search history next |
674 |
|
|
* [/] |
675 |
|
|
*/ |
676 |
|
|
protected el_action_t |
677 |
|
|
/*ARGSUSED*/ |
678 |
|
|
vi_search_next(EditLine *el, wint_t c __attribute__((__unused__))) |
679 |
|
|
{ |
680 |
|
|
|
681 |
|
|
return cv_search(el, ED_SEARCH_NEXT_HISTORY); |
682 |
|
|
} |
683 |
|
|
|
684 |
|
|
|
685 |
|
|
/* vi_repeat_search_next(): |
686 |
|
|
* Vi repeat current search in the same search direction |
687 |
|
|
* [n] |
688 |
|
|
*/ |
689 |
|
|
protected el_action_t |
690 |
|
|
/*ARGSUSED*/ |
691 |
|
|
vi_repeat_search_next(EditLine *el, wint_t c __attribute__((__unused__))) |
692 |
|
|
{ |
693 |
|
|
|
694 |
|
|
if (el->el_search.patlen == 0) |
695 |
|
|
return CC_ERROR; |
696 |
|
|
else |
697 |
|
|
return cv_repeat_srch(el, el->el_search.patdir); |
698 |
|
|
} |
699 |
|
|
|
700 |
|
|
|
701 |
|
|
/* vi_repeat_search_prev(): |
702 |
|
|
* Vi repeat current search in the opposite search direction |
703 |
|
|
* [N] |
704 |
|
|
*/ |
705 |
|
|
/*ARGSUSED*/ |
706 |
|
|
protected el_action_t |
707 |
|
|
vi_repeat_search_prev(EditLine *el, wint_t c __attribute__((__unused__))) |
708 |
|
|
{ |
709 |
|
|
|
710 |
|
|
if (el->el_search.patlen == 0) |
711 |
|
|
return CC_ERROR; |
712 |
|
|
else |
713 |
|
|
return (cv_repeat_srch(el, |
714 |
|
|
el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? |
715 |
|
|
ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY)); |
716 |
|
|
} |
717 |
|
|
|
718 |
|
|
|
719 |
|
|
/* vi_next_char(): |
720 |
|
|
* Vi move to the character specified next |
721 |
|
|
* [f] |
722 |
|
|
*/ |
723 |
|
|
protected el_action_t |
724 |
|
|
/*ARGSUSED*/ |
725 |
|
|
vi_next_char(EditLine *el, wint_t c __attribute__((__unused__))) |
726 |
|
|
{ |
727 |
|
|
return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); |
728 |
|
|
} |
729 |
|
|
|
730 |
|
|
|
731 |
|
|
/* vi_prev_char(): |
732 |
|
|
* Vi move to the character specified previous |
733 |
|
|
* [F] |
734 |
|
|
*/ |
735 |
|
|
protected el_action_t |
736 |
|
|
/*ARGSUSED*/ |
737 |
|
|
vi_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) |
738 |
|
|
{ |
739 |
|
|
return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); |
740 |
|
|
} |
741 |
|
|
|
742 |
|
|
|
743 |
|
|
/* vi_to_next_char(): |
744 |
|
|
* Vi move up to the character specified next |
745 |
|
|
* [t] |
746 |
|
|
*/ |
747 |
|
|
protected el_action_t |
748 |
|
|
/*ARGSUSED*/ |
749 |
|
|
vi_to_next_char(EditLine *el, wint_t c __attribute__((__unused__))) |
750 |
|
|
{ |
751 |
|
|
return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); |
752 |
|
|
} |
753 |
|
|
|
754 |
|
|
|
755 |
|
|
/* vi_to_prev_char(): |
756 |
|
|
* Vi move up to the character specified previous |
757 |
|
|
* [T] |
758 |
|
|
*/ |
759 |
|
|
protected el_action_t |
760 |
|
|
/*ARGSUSED*/ |
761 |
|
|
vi_to_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) |
762 |
|
|
{ |
763 |
|
|
return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); |
764 |
|
|
} |
765 |
|
|
|
766 |
|
|
|
767 |
|
|
/* vi_repeat_next_char(): |
768 |
|
|
* Vi repeat current character search in the same search direction |
769 |
|
|
* [;] |
770 |
|
|
*/ |
771 |
|
|
protected el_action_t |
772 |
|
|
/*ARGSUSED*/ |
773 |
|
|
vi_repeat_next_char(EditLine *el, wint_t c __attribute__((__unused__))) |
774 |
|
|
{ |
775 |
|
|
|
776 |
|
|
return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, |
777 |
|
|
el->el_state.argument, el->el_search.chatflg); |
778 |
|
|
} |
779 |
|
|
|
780 |
|
|
|
781 |
|
|
/* vi_repeat_prev_char(): |
782 |
|
|
* Vi repeat current character search in the opposite search direction |
783 |
|
|
* [,] |
784 |
|
|
*/ |
785 |
|
|
protected el_action_t |
786 |
|
|
/*ARGSUSED*/ |
787 |
|
|
vi_repeat_prev_char(EditLine *el, wint_t c __attribute__((__unused__))) |
788 |
|
|
{ |
789 |
|
|
el_action_t r; |
790 |
|
|
int dir = el->el_search.chadir; |
791 |
|
|
|
792 |
|
|
r = cv_csearch(el, -dir, el->el_search.chacha, |
793 |
|
|
el->el_state.argument, el->el_search.chatflg); |
794 |
|
|
el->el_search.chadir = dir; |
795 |
|
|
return r; |
796 |
|
|
} |
797 |
|
|
|
798 |
|
|
|
799 |
|
|
/* vi_match(): |
800 |
|
|
* Vi go to matching () {} or [] |
801 |
|
|
* [%] |
802 |
|
|
*/ |
803 |
|
|
protected el_action_t |
804 |
|
|
/*ARGSUSED*/ |
805 |
|
|
vi_match(EditLine *el, wint_t c __attribute__((__unused__))) |
806 |
|
|
{ |
807 |
|
|
const wchar_t match_chars[] = L"()[]{}"; |
808 |
|
|
wchar_t *cp; |
809 |
|
|
size_t delta, i, count; |
810 |
|
|
wchar_t o_ch, c_ch; |
811 |
|
|
|
812 |
|
|
*el->el_line.lastchar = '\0'; /* just in case */ |
813 |
|
|
|
814 |
|
|
i = wcscspn(el->el_line.cursor, match_chars); |
815 |
|
|
o_ch = el->el_line.cursor[i]; |
816 |
|
|
if (o_ch == 0) |
817 |
|
|
return CC_ERROR; |
818 |
|
|
delta = wcschr(match_chars, o_ch) - match_chars; |
819 |
|
|
c_ch = match_chars[delta ^ 1]; |
820 |
|
|
count = 1; |
821 |
|
|
delta = 1 - (delta & 1) * 2; |
822 |
|
|
|
823 |
|
|
for (cp = &el->el_line.cursor[i]; count; ) { |
824 |
|
|
cp += delta; |
825 |
|
|
if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) |
826 |
|
|
return CC_ERROR; |
827 |
|
|
if (*cp == o_ch) |
828 |
|
|
count++; |
829 |
|
|
else if (*cp == c_ch) |
830 |
|
|
count--; |
831 |
|
|
} |
832 |
|
|
|
833 |
|
|
el->el_line.cursor = cp; |
834 |
|
|
|
835 |
|
|
if (el->el_chared.c_vcmd.action != NOP) { |
836 |
|
|
/* NB posix says char under cursor should NOT be deleted |
837 |
|
|
for -ve delta - this is different to netbsd vi. */ |
838 |
|
|
if (delta > 0) |
839 |
|
|
el->el_line.cursor++; |
840 |
|
|
cv_delfini(el); |
841 |
|
|
return CC_REFRESH; |
842 |
|
|
} |
843 |
|
|
return CC_CURSOR; |
844 |
|
|
} |
845 |
|
|
|
846 |
|
|
/* vi_undo_line(): |
847 |
|
|
* Vi undo all changes to line |
848 |
|
|
* [U] |
849 |
|
|
*/ |
850 |
|
|
protected el_action_t |
851 |
|
|
/*ARGSUSED*/ |
852 |
|
|
vi_undo_line(EditLine *el, wint_t c __attribute__((__unused__))) |
853 |
|
|
{ |
854 |
|
|
|
855 |
|
|
cv_undo(el); |
856 |
|
|
return hist_get(el); |
857 |
|
|
} |
858 |
|
|
|
859 |
|
|
/* vi_to_column(): |
860 |
|
|
* Vi go to specified column |
861 |
|
|
* [|] |
862 |
|
|
* NB netbsd vi goes to screen column 'n', posix says nth character |
863 |
|
|
*/ |
864 |
|
|
protected el_action_t |
865 |
|
|
/*ARGSUSED*/ |
866 |
|
|
vi_to_column(EditLine *el, wint_t c __attribute__((__unused__))) |
867 |
|
|
{ |
868 |
|
|
|
869 |
|
|
el->el_line.cursor = el->el_line.buffer; |
870 |
|
|
el->el_state.argument--; |
871 |
|
|
return ed_next_char(el, 0); |
872 |
|
|
} |
873 |
|
|
|
874 |
|
|
/* vi_yank_end(): |
875 |
|
|
* Vi yank to end of line |
876 |
|
|
* [Y] |
877 |
|
|
*/ |
878 |
|
|
protected el_action_t |
879 |
|
|
/*ARGSUSED*/ |
880 |
|
|
vi_yank_end(EditLine *el, wint_t c __attribute__((__unused__))) |
881 |
|
|
{ |
882 |
|
|
|
883 |
|
|
cv_yank(el, el->el_line.cursor, |
884 |
|
|
(int)(el->el_line.lastchar - el->el_line.cursor)); |
885 |
|
|
return CC_REFRESH; |
886 |
|
|
} |
887 |
|
|
|
888 |
|
|
/* vi_yank(): |
889 |
|
|
* Vi yank |
890 |
|
|
* [y] |
891 |
|
|
*/ |
892 |
|
|
protected el_action_t |
893 |
|
|
/*ARGSUSED*/ |
894 |
|
|
vi_yank(EditLine *el, wint_t c __attribute__((__unused__))) |
895 |
|
|
{ |
896 |
|
|
|
897 |
|
|
return cv_action(el, YANK); |
898 |
|
|
} |
899 |
|
|
|
900 |
|
|
/* vi_comment_out(): |
901 |
|
|
* Vi comment out current command |
902 |
|
|
* [#] |
903 |
|
|
*/ |
904 |
|
|
protected el_action_t |
905 |
|
|
/*ARGSUSED*/ |
906 |
|
|
vi_comment_out(EditLine *el, wint_t c __attribute__((__unused__))) |
907 |
|
|
{ |
908 |
|
|
|
909 |
|
|
el->el_line.cursor = el->el_line.buffer; |
910 |
|
|
c_insert(el, 1); |
911 |
|
|
*el->el_line.cursor = '#'; |
912 |
|
|
re_refresh(el); |
913 |
|
|
return ed_newline(el, 0); |
914 |
|
|
} |
915 |
|
|
|
916 |
|
|
/* vi_alias(): |
917 |
|
|
* Vi include shell alias |
918 |
|
|
* [@] |
919 |
|
|
* NB: posix implies that we should enter insert mode, however |
920 |
|
|
* this is against historical precedent... |
921 |
|
|
*/ |
922 |
|
|
#ifdef __weak_reference |
923 |
|
|
__weakref_visible char *my_get_alias_text(const char *) |
924 |
|
|
__weak_reference(get_alias_text); |
925 |
|
|
#endif |
926 |
|
|
protected el_action_t |
927 |
|
|
/*ARGSUSED*/ |
928 |
|
|
vi_alias(EditLine *el, wint_t c __attribute__((__unused__))) |
929 |
|
|
{ |
930 |
|
|
#ifdef __weak_reference |
931 |
|
|
char alias_name[3]; |
932 |
|
|
char *alias_text; |
933 |
|
|
|
934 |
|
|
if (my_get_alias_text == 0) { |
935 |
|
|
return CC_ERROR; |
936 |
|
|
} |
937 |
|
|
|
938 |
|
|
alias_name[0] = '_'; |
939 |
|
|
alias_name[2] = 0; |
940 |
|
|
if (el_getc(el, &alias_name[1]) != 1) |
941 |
|
|
return CC_ERROR; |
942 |
|
|
|
943 |
|
|
alias_text = my_get_alias_text(alias_name); |
944 |
|
|
if (alias_text != NULL) |
945 |
|
|
el_wpush(el, ct_decode_string(alias_text, &el->el_scratch)); |
946 |
|
|
return CC_NORM; |
947 |
|
|
#else |
948 |
|
|
return CC_ERROR; |
949 |
|
|
#endif |
950 |
|
|
} |
951 |
|
|
|
952 |
|
|
/* vi_to_history_line(): |
953 |
|
|
* Vi go to specified history file line. |
954 |
|
|
* [G] |
955 |
|
|
*/ |
956 |
|
|
protected el_action_t |
957 |
|
|
/*ARGSUSED*/ |
958 |
|
|
vi_to_history_line(EditLine *el, wint_t c __attribute__((__unused__))) |
959 |
|
|
{ |
960 |
|
|
int sv_event_no = el->el_history.eventno; |
961 |
|
|
el_action_t rval; |
962 |
|
|
|
963 |
|
|
|
964 |
|
|
if (el->el_history.eventno == 0) { |
965 |
|
|
(void) wcsncpy(el->el_history.buf, el->el_line.buffer, |
966 |
|
|
EL_BUFSIZ); |
967 |
|
|
el->el_history.last = el->el_history.buf + |
968 |
|
|
(el->el_line.lastchar - el->el_line.buffer); |
969 |
|
|
} |
970 |
|
|
|
971 |
|
|
/* Lack of a 'count' means oldest, not 1 */ |
972 |
|
|
if (!el->el_state.doingarg) { |
973 |
|
|
el->el_history.eventno = 0x7fffffff; |
974 |
|
|
hist_get(el); |
975 |
|
|
} else { |
976 |
|
|
/* This is brain dead, all the rest of this code counts |
977 |
|
|
* upwards going into the past. Here we need count in the |
978 |
|
|
* other direction (to match the output of fc -l). |
979 |
|
|
* I could change the world, but this seems to suffice. |
980 |
|
|
*/ |
981 |
|
|
el->el_history.eventno = 1; |
982 |
|
|
if (hist_get(el) == CC_ERROR) |
983 |
|
|
return CC_ERROR; |
984 |
|
|
el->el_history.eventno = 1 + el->el_history.ev.num |
985 |
|
|
- el->el_state.argument; |
986 |
|
|
if (el->el_history.eventno < 0) { |
987 |
|
|
el->el_history.eventno = sv_event_no; |
988 |
|
|
return CC_ERROR; |
989 |
|
|
} |
990 |
|
|
} |
991 |
|
|
rval = hist_get(el); |
992 |
|
|
if (rval == CC_ERROR) |
993 |
|
|
el->el_history.eventno = sv_event_no; |
994 |
|
|
return rval; |
995 |
|
|
} |
996 |
|
|
|
997 |
|
|
/* vi_histedit(): |
998 |
|
|
* Vi edit history line with vi |
999 |
|
|
* [v] |
1000 |
|
|
*/ |
1001 |
|
|
protected el_action_t |
1002 |
|
|
/*ARGSUSED*/ |
1003 |
|
|
vi_histedit(EditLine *el, wint_t c __attribute__((__unused__))) |
1004 |
|
|
{ |
1005 |
|
|
int fd; |
1006 |
|
|
pid_t pid; |
1007 |
|
|
ssize_t st; |
1008 |
|
|
int status; |
1009 |
|
|
char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; |
1010 |
|
|
char *cp; |
1011 |
|
|
size_t len; |
1012 |
|
|
wchar_t *line; |
1013 |
|
|
|
1014 |
|
|
if (el->el_state.doingarg) { |
1015 |
|
|
if (vi_to_history_line(el, 0) == CC_ERROR) |
1016 |
|
|
return CC_ERROR; |
1017 |
|
|
} |
1018 |
|
|
|
1019 |
|
|
fd = mkstemp(tempfile); |
1020 |
|
|
if (fd < 0) |
1021 |
|
|
return CC_ERROR; |
1022 |
|
|
len = (size_t)(el->el_line.lastchar - el->el_line.buffer); |
1023 |
|
|
#define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) |
1024 |
|
|
cp = malloc(TMP_BUFSIZ); |
1025 |
|
|
if (cp == NULL) { |
1026 |
|
|
close(fd); |
1027 |
|
|
unlink(tempfile); |
1028 |
|
|
return CC_ERROR; |
1029 |
|
|
} |
1030 |
|
|
line = reallocarray(NULL, len, sizeof(*line)); |
1031 |
|
|
if (line == NULL) { |
1032 |
|
|
close(fd); |
1033 |
|
|
unlink(tempfile); |
1034 |
|
|
free(cp); |
1035 |
|
|
return CC_ERROR; |
1036 |
|
|
} |
1037 |
|
|
wcsncpy(line, el->el_line.buffer, len); |
1038 |
|
|
line[len] = '\0'; |
1039 |
|
|
wcstombs(cp, line, TMP_BUFSIZ - 1); |
1040 |
|
|
cp[TMP_BUFSIZ - 1] = '\0'; |
1041 |
|
|
len = strlen(cp); |
1042 |
|
|
write(fd, cp, len); |
1043 |
|
|
write(fd, "\n", 1); |
1044 |
|
|
pid = fork(); |
1045 |
|
|
switch (pid) { |
1046 |
|
|
case -1: |
1047 |
|
|
close(fd); |
1048 |
|
|
unlink(tempfile); |
1049 |
|
|
free(cp); |
1050 |
|
|
free(line); |
1051 |
|
|
return CC_ERROR; |
1052 |
|
|
case 0: |
1053 |
|
|
close(fd); |
1054 |
|
|
execlp("vi", "vi", tempfile, (char *)NULL); |
1055 |
|
|
exit(0); |
1056 |
|
|
/*NOTREACHED*/ |
1057 |
|
|
default: |
1058 |
|
|
while (waitpid(pid, &status, 0) != pid) |
1059 |
|
|
continue; |
1060 |
|
|
lseek(fd, (off_t)0, SEEK_SET); |
1061 |
|
|
st = read(fd, cp, TMP_BUFSIZ); |
1062 |
|
|
if (st > 0) { |
1063 |
|
|
len = (size_t)(el->el_line.lastchar - |
1064 |
|
|
el->el_line.buffer); |
1065 |
|
|
len = mbstowcs(el->el_line.buffer, cp, len); |
1066 |
|
|
if (len > 0 && el->el_line.buffer[len -1] == '\n') |
1067 |
|
|
--len; |
1068 |
|
|
} |
1069 |
|
|
else |
1070 |
|
|
len = 0; |
1071 |
|
|
el->el_line.cursor = el->el_line.buffer; |
1072 |
|
|
el->el_line.lastchar = el->el_line.buffer + len; |
1073 |
|
|
free(cp); |
1074 |
|
|
free(line); |
1075 |
|
|
break; |
1076 |
|
|
} |
1077 |
|
|
|
1078 |
|
|
close(fd); |
1079 |
|
|
unlink(tempfile); |
1080 |
|
|
/* return CC_REFRESH; */ |
1081 |
|
|
return ed_newline(el, 0); |
1082 |
|
|
} |
1083 |
|
|
|
1084 |
|
|
/* vi_history_word(): |
1085 |
|
|
* Vi append word from previous input line |
1086 |
|
|
* [_] |
1087 |
|
|
* Who knows where this one came from! |
1088 |
|
|
* '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' |
1089 |
|
|
*/ |
1090 |
|
|
protected el_action_t |
1091 |
|
|
/*ARGSUSED*/ |
1092 |
|
|
vi_history_word(EditLine *el, wint_t c __attribute__((__unused__))) |
1093 |
|
|
{ |
1094 |
|
|
const wchar_t *wp = HIST_FIRST(el); |
1095 |
|
|
const wchar_t *wep, *wsp; |
1096 |
|
|
int len; |
1097 |
|
|
wchar_t *cp; |
1098 |
|
|
const wchar_t *lim; |
1099 |
|
|
|
1100 |
|
|
if (wp == NULL) |
1101 |
|
|
return CC_ERROR; |
1102 |
|
|
|
1103 |
|
|
wep = wsp = NULL; |
1104 |
|
|
do { |
1105 |
|
|
while (iswspace(*wp)) |
1106 |
|
|
wp++; |
1107 |
|
|
if (*wp == 0) |
1108 |
|
|
break; |
1109 |
|
|
wsp = wp; |
1110 |
|
|
while (*wp && !iswspace(*wp)) |
1111 |
|
|
wp++; |
1112 |
|
|
wep = wp; |
1113 |
|
|
} while ((!el->el_state.doingarg || --el->el_state.argument > 0) |
1114 |
|
|
&& *wp != 0); |
1115 |
|
|
|
1116 |
|
|
if (wsp == NULL || (el->el_state.doingarg && el->el_state.argument != 0)) |
1117 |
|
|
return CC_ERROR; |
1118 |
|
|
|
1119 |
|
|
cv_undo(el); |
1120 |
|
|
len = (int)(wep - wsp); |
1121 |
|
|
if (el->el_line.cursor < el->el_line.lastchar) |
1122 |
|
|
el->el_line.cursor++; |
1123 |
|
|
c_insert(el, len + 1); |
1124 |
|
|
cp = el->el_line.cursor; |
1125 |
|
|
lim = el->el_line.limit; |
1126 |
|
|
if (cp < lim) |
1127 |
|
|
*cp++ = ' '; |
1128 |
|
|
while (wsp < wep && cp < lim) |
1129 |
|
|
*cp++ = *wsp++; |
1130 |
|
|
el->el_line.cursor = cp; |
1131 |
|
|
|
1132 |
|
|
el->el_map.current = el->el_map.key; |
1133 |
|
|
return CC_REFRESH; |
1134 |
|
|
} |
1135 |
|
|
|
1136 |
|
|
/* vi_redo(): |
1137 |
|
|
* Vi redo last non-motion command |
1138 |
|
|
* [.] |
1139 |
|
|
*/ |
1140 |
|
|
protected el_action_t |
1141 |
|
|
/*ARGSUSED*/ |
1142 |
|
|
vi_redo(EditLine *el, wint_t c __attribute__((__unused__))) |
1143 |
|
|
{ |
1144 |
|
|
c_redo_t *r = &el->el_chared.c_redo; |
1145 |
|
|
|
1146 |
|
|
if (!el->el_state.doingarg && r->count) { |
1147 |
|
|
el->el_state.doingarg = 1; |
1148 |
|
|
el->el_state.argument = r->count; |
1149 |
|
|
} |
1150 |
|
|
|
1151 |
|
|
el->el_chared.c_vcmd.pos = el->el_line.cursor; |
1152 |
|
|
el->el_chared.c_vcmd.action = r->action; |
1153 |
|
|
if (r->pos != r->buf) { |
1154 |
|
|
if (r->pos + 1 > r->lim) |
1155 |
|
|
/* sanity */ |
1156 |
|
|
r->pos = r->lim - 1; |
1157 |
|
|
r->pos[0] = 0; |
1158 |
|
|
el_wpush(el, r->buf); |
1159 |
|
|
} |
1160 |
|
|
|
1161 |
|
|
el->el_state.thiscmd = r->cmd; |
1162 |
|
|
el->el_state.thisch = r->ch; |
1163 |
|
|
return (*el->el_map.func[r->cmd])(el, r->ch); |
1164 |
|
|
} |