1 /* $NetBSD: emacs.c,v 1.36 2016/05/09 21:46:56 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: emacs.c,v 1.36 2016/05/09 21:46:56 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43
44 /*
45 * emacs.c: Emacs functions
46 */
47 #include <ctype.h>
48
49 #include "el.h"
50 #include "emacs.h"
51 #include "fcns.h"
52
53 /* em_delete_or_list():
54 * Delete character under cursor or list completions if at end of line
55 * [^D]
56 */
57 libedit_private el_action_t
58 /*ARGSUSED*/
em_delete_or_list(EditLine * el,wint_t c)59 em_delete_or_list(EditLine *el, wint_t c)
60 {
61
62 if (el->el_line.cursor == el->el_line.lastchar) {
63 /* if I'm at the end */
64 if (el->el_line.cursor == el->el_line.buffer) {
65 /* and the beginning */
66 terminal_writec(el, c); /* then do an EOF */
67 return CC_EOF;
68 } else {
69 /*
70 * Here we could list completions, but it is an
71 * error right now
72 */
73 terminal_beep(el);
74 return CC_ERROR;
75 }
76 } else {
77 if (el->el_state.doingarg)
78 c_delafter(el, el->el_state.argument);
79 else
80 c_delafter1(el);
81 if (el->el_line.cursor > el->el_line.lastchar)
82 el->el_line.cursor = el->el_line.lastchar;
83 /* bounds check */
84 return CC_REFRESH;
85 }
86 }
87
88
89 /* em_delete_next_word():
90 * Cut from cursor to end of current word
91 * [M-d]
92 */
93 libedit_private el_action_t
94 /*ARGSUSED*/
em_delete_next_word(EditLine * el,wint_t c)95 em_delete_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
96 {
97 wchar_t *cp, *p, *kp;
98
99 if (el->el_line.cursor == el->el_line.lastchar)
100 return CC_ERROR;
101
102 cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
103 el->el_state.argument, ce__isword);
104
105 for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
106 /* save the text */
107 *kp++ = *p;
108 el->el_chared.c_kill.last = kp;
109
110 c_delafter(el, (int)(cp - el->el_line.cursor)); /* delete after dot */
111 if (el->el_line.cursor > el->el_line.lastchar)
112 el->el_line.cursor = el->el_line.lastchar;
113 /* bounds check */
114 return CC_REFRESH;
115 }
116
117
118 /* em_yank():
119 * Paste cut buffer at cursor position
120 * [^Y]
121 */
122 libedit_private el_action_t
123 /*ARGSUSED*/
em_yank(EditLine * el,wint_t c)124 em_yank(EditLine *el, wint_t c __attribute__((__unused__)))
125 {
126 wchar_t *kp, *cp;
127
128 if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
129 return CC_NORM;
130
131 if (el->el_line.lastchar +
132 (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
133 el->el_line.limit)
134 return CC_ERROR;
135
136 el->el_chared.c_kill.mark = el->el_line.cursor;
137 cp = el->el_line.cursor;
138
139 /* open the space, */
140 c_insert(el,
141 (int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf));
142 /* copy the chars */
143 for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
144 *cp++ = *kp;
145
146 /* if an arg, cursor at beginning else cursor at end */
147 if (el->el_state.argument == 1)
148 el->el_line.cursor = cp;
149
150 return CC_REFRESH;
151 }
152
153
154 /* em_kill_line():
155 * Cut the entire line and save in cut buffer
156 * [^U]
157 */
158 libedit_private el_action_t
159 /*ARGSUSED*/
em_kill_line(EditLine * el,wint_t c)160 em_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
161 {
162 wchar_t *kp, *cp;
163
164 cp = el->el_line.buffer;
165 kp = el->el_chared.c_kill.buf;
166 while (cp < el->el_line.lastchar)
167 *kp++ = *cp++; /* copy it */
168 el->el_chared.c_kill.last = kp;
169 /* zap! -- delete all of it */
170 el->el_line.lastchar = el->el_line.buffer;
171 el->el_line.cursor = el->el_line.buffer;
172 return CC_REFRESH;
173 }
174
175
176 /* em_kill_region():
177 * Cut area between mark and cursor and save in cut buffer
178 * [^W]
179 */
180 libedit_private el_action_t
181 /*ARGSUSED*/
em_kill_region(EditLine * el,wint_t c)182 em_kill_region(EditLine *el, wint_t c __attribute__((__unused__)))
183 {
184 wchar_t *kp, *cp;
185
186 if (!el->el_chared.c_kill.mark)
187 return CC_ERROR;
188
189 if (el->el_chared.c_kill.mark > el->el_line.cursor) {
190 cp = el->el_line.cursor;
191 kp = el->el_chared.c_kill.buf;
192 while (cp < el->el_chared.c_kill.mark)
193 *kp++ = *cp++; /* copy it */
194 el->el_chared.c_kill.last = kp;
195 c_delafter(el, (int)(cp - el->el_line.cursor));
196 } else { /* mark is before cursor */
197 cp = el->el_chared.c_kill.mark;
198 kp = el->el_chared.c_kill.buf;
199 while (cp < el->el_line.cursor)
200 *kp++ = *cp++; /* copy it */
201 el->el_chared.c_kill.last = kp;
202 c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark));
203 el->el_line.cursor = el->el_chared.c_kill.mark;
204 }
205 return CC_REFRESH;
206 }
207
208
209 /* em_copy_region():
210 * Copy area between mark and cursor to cut buffer
211 * [M-W]
212 */
213 libedit_private el_action_t
214 /*ARGSUSED*/
em_copy_region(EditLine * el,wint_t c)215 em_copy_region(EditLine *el, wint_t c __attribute__((__unused__)))
216 {
217 wchar_t *kp, *cp;
218
219 if (!el->el_chared.c_kill.mark)
220 return CC_ERROR;
221
222 if (el->el_chared.c_kill.mark > el->el_line.cursor) {
223 cp = el->el_line.cursor;
224 kp = el->el_chared.c_kill.buf;
225 while (cp < el->el_chared.c_kill.mark)
226 *kp++ = *cp++; /* copy it */
227 el->el_chared.c_kill.last = kp;
228 } else {
229 cp = el->el_chared.c_kill.mark;
230 kp = el->el_chared.c_kill.buf;
231 while (cp < el->el_line.cursor)
232 *kp++ = *cp++; /* copy it */
233 el->el_chared.c_kill.last = kp;
234 }
235 return CC_NORM;
236 }
237
238
239 /* em_gosmacs_transpose():
240 * Exchange the two characters before the cursor
241 * Gosling emacs transpose chars [^T]
242 */
243 libedit_private el_action_t
em_gosmacs_transpose(EditLine * el,wint_t c)244 em_gosmacs_transpose(EditLine *el, wint_t c)
245 {
246
247 if (el->el_line.cursor > &el->el_line.buffer[1]) {
248 /* must have at least two chars entered */
249 c = el->el_line.cursor[-2];
250 el->el_line.cursor[-2] = el->el_line.cursor[-1];
251 el->el_line.cursor[-1] = c;
252 return CC_REFRESH;
253 } else
254 return CC_ERROR;
255 }
256
257
258 /* em_next_word():
259 * Move next to end of current word
260 * [M-f]
261 */
262 libedit_private el_action_t
263 /*ARGSUSED*/
em_next_word(EditLine * el,wint_t c)264 em_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
265 {
266 if (el->el_line.cursor == el->el_line.lastchar)
267 return CC_ERROR;
268
269 el->el_line.cursor = c__next_word(el->el_line.cursor,
270 el->el_line.lastchar,
271 el->el_state.argument,
272 ce__isword);
273
274 if (el->el_map.type == MAP_VI)
275 if (el->el_chared.c_vcmd.action != NOP) {
276 cv_delfini(el);
277 return CC_REFRESH;
278 }
279 return CC_CURSOR;
280 }
281
282
283 /* em_upper_case():
284 * Uppercase the characters from cursor to end of current word
285 * [M-u]
286 */
287 libedit_private el_action_t
288 /*ARGSUSED*/
em_upper_case(EditLine * el,wint_t c)289 em_upper_case(EditLine *el, wint_t c __attribute__((__unused__)))
290 {
291 wchar_t *cp, *ep;
292
293 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
294 el->el_state.argument, ce__isword);
295
296 for (cp = el->el_line.cursor; cp < ep; cp++)
297 if (iswlower(*cp))
298 *cp = towupper(*cp);
299
300 el->el_line.cursor = ep;
301 if (el->el_line.cursor > el->el_line.lastchar)
302 el->el_line.cursor = el->el_line.lastchar;
303 return CC_REFRESH;
304 }
305
306
307 /* em_capitol_case():
308 * Capitalize the characters from cursor to end of current word
309 * [M-c]
310 */
311 libedit_private el_action_t
312 /*ARGSUSED*/
em_capitol_case(EditLine * el,wint_t c)313 em_capitol_case(EditLine *el, wint_t c __attribute__((__unused__)))
314 {
315 wchar_t *cp, *ep;
316
317 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
318 el->el_state.argument, ce__isword);
319
320 for (cp = el->el_line.cursor; cp < ep; cp++) {
321 if (iswalpha(*cp)) {
322 if (iswlower(*cp))
323 *cp = towupper(*cp);
324 cp++;
325 break;
326 }
327 }
328 for (; cp < ep; cp++)
329 if (iswupper(*cp))
330 *cp = towlower(*cp);
331
332 el->el_line.cursor = ep;
333 if (el->el_line.cursor > el->el_line.lastchar)
334 el->el_line.cursor = el->el_line.lastchar;
335 return CC_REFRESH;
336 }
337
338
339 /* em_lower_case():
340 * Lowercase the characters from cursor to end of current word
341 * [M-l]
342 */
343 libedit_private el_action_t
344 /*ARGSUSED*/
em_lower_case(EditLine * el,wint_t c)345 em_lower_case(EditLine *el, wint_t c __attribute__((__unused__)))
346 {
347 wchar_t *cp, *ep;
348
349 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
350 el->el_state.argument, ce__isword);
351
352 for (cp = el->el_line.cursor; cp < ep; cp++)
353 if (iswupper(*cp))
354 *cp = towlower(*cp);
355
356 el->el_line.cursor = ep;
357 if (el->el_line.cursor > el->el_line.lastchar)
358 el->el_line.cursor = el->el_line.lastchar;
359 return CC_REFRESH;
360 }
361
362
363 /* em_set_mark():
364 * Set the mark at cursor
365 * [^@]
366 */
367 libedit_private el_action_t
368 /*ARGSUSED*/
em_set_mark(EditLine * el,wint_t c)369 em_set_mark(EditLine *el, wint_t c __attribute__((__unused__)))
370 {
371
372 el->el_chared.c_kill.mark = el->el_line.cursor;
373 return CC_NORM;
374 }
375
376
377 /* em_exchange_mark():
378 * Exchange the cursor and mark
379 * [^X^X]
380 */
381 libedit_private el_action_t
382 /*ARGSUSED*/
em_exchange_mark(EditLine * el,wint_t c)383 em_exchange_mark(EditLine *el, wint_t c __attribute__((__unused__)))
384 {
385 wchar_t *cp;
386
387 cp = el->el_line.cursor;
388 el->el_line.cursor = el->el_chared.c_kill.mark;
389 el->el_chared.c_kill.mark = cp;
390 return CC_CURSOR;
391 }
392
393
394 /* em_universal_argument():
395 * Universal argument (argument times 4)
396 * [^U]
397 */
398 libedit_private el_action_t
399 /*ARGSUSED*/
em_universal_argument(EditLine * el,wint_t c)400 em_universal_argument(EditLine *el, wint_t c __attribute__((__unused__)))
401 { /* multiply current argument by 4 */
402
403 if (el->el_state.argument > 1000000)
404 return CC_ERROR;
405 el->el_state.doingarg = 1;
406 el->el_state.argument *= 4;
407 return CC_ARGHACK;
408 }
409
410
411 /* em_meta_next():
412 * Add 8th bit to next character typed
413 * [<ESC>]
414 */
415 libedit_private el_action_t
416 /*ARGSUSED*/
em_meta_next(EditLine * el,wint_t c)417 em_meta_next(EditLine *el, wint_t c __attribute__((__unused__)))
418 {
419
420 el->el_state.metanext = 1;
421 return CC_ARGHACK;
422 }
423
424
425 /* em_toggle_overwrite():
426 * Switch from insert to overwrite mode or vice versa
427 */
428 libedit_private el_action_t
429 /*ARGSUSED*/
em_toggle_overwrite(EditLine * el,wint_t c)430 em_toggle_overwrite(EditLine *el, wint_t c __attribute__((__unused__)))
431 {
432
433 el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
434 MODE_REPLACE : MODE_INSERT;
435 return CC_NORM;
436 }
437
438
439 /* em_copy_prev_word():
440 * Copy current word to cursor
441 */
442 libedit_private el_action_t
443 /*ARGSUSED*/
em_copy_prev_word(EditLine * el,wint_t c)444 em_copy_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
445 {
446 wchar_t *cp, *oldc, *dp;
447
448 if (el->el_line.cursor == el->el_line.buffer)
449 return CC_ERROR;
450
451 oldc = el->el_line.cursor;
452 /* does a bounds check */
453 cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
454 el->el_state.argument, ce__isword);
455
456 c_insert(el, (int)(oldc - cp));
457 for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
458 *dp++ = *cp;
459
460 el->el_line.cursor = dp;/* put cursor at end */
461
462 return CC_REFRESH;
463 }
464
465
466 /* em_inc_search_next():
467 * Emacs incremental next search
468 */
469 libedit_private el_action_t
470 /*ARGSUSED*/
em_inc_search_next(EditLine * el,wint_t c)471 em_inc_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
472 {
473
474 el->el_search.patlen = 0;
475 return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
476 }
477
478
479 /* em_inc_search_prev():
480 * Emacs incremental reverse search
481 */
482 libedit_private el_action_t
483 /*ARGSUSED*/
em_inc_search_prev(EditLine * el,wint_t c)484 em_inc_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
485 {
486
487 el->el_search.patlen = 0;
488 return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
489 }
490
491
492 /* em_delete_prev_char():
493 * Delete the character to the left of the cursor
494 * [^?]
495 */
496 libedit_private el_action_t
497 /*ARGSUSED*/
em_delete_prev_char(EditLine * el,wint_t c)498 em_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
499 {
500
501 if (el->el_line.cursor <= el->el_line.buffer)
502 return CC_ERROR;
503
504 if (el->el_state.doingarg)
505 c_delbefore(el, el->el_state.argument);
506 else
507 c_delbefore1(el);
508 el->el_line.cursor -= el->el_state.argument;
509 if (el->el_line.cursor < el->el_line.buffer)
510 el->el_line.cursor = el->el_line.buffer;
511 return CC_REFRESH;
512 }
513