Merge commit '9992e6a682b1c35b4385c3b512db329ec8ab9ede'
[unleashed.git] / lib / libedit / emacs.c
blob19503d6fb545d6fc1f298ddfbf6cf460783e9974
1 /* $OpenBSD: emacs.c,v 1.17 2016/05/06 13:12:52 schwarze Exp $ */
2 /* $NetBSD: emacs.c,v 1.35 2016/04/18 17:01:19 christos Exp $ */
4 /*-
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
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.
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.
36 #include "config.h"
39 * emacs.c: Emacs functions
41 #include <ctype.h>
43 #include "el.h"
44 #include "emacs.h"
45 #include "fcns.h"
47 /* em_delete_or_list():
48 * Delete character under cursor or list completions if at end of line
49 * [^D]
51 protected el_action_t
52 /*ARGSUSED*/
53 em_delete_or_list(EditLine *el, wint_t c)
56 if (el->el_line.cursor == el->el_line.lastchar) {
57 /* if I'm at the end */
58 if (el->el_line.cursor == el->el_line.buffer) {
59 /* and the beginning */
60 terminal_writec(el, c); /* then do an EOF */
61 return CC_EOF;
62 } else {
64 * Here we could list completions, but it is an
65 * error right now
67 terminal_beep(el);
68 return CC_ERROR;
70 } else {
71 if (el->el_state.doingarg)
72 c_delafter(el, el->el_state.argument);
73 else
74 c_delafter1(el);
75 if (el->el_line.cursor > el->el_line.lastchar)
76 el->el_line.cursor = el->el_line.lastchar;
77 /* bounds check */
78 return CC_REFRESH;
83 /* em_delete_next_word():
84 * Cut from cursor to end of current word
85 * [M-d]
87 protected el_action_t
88 /*ARGSUSED*/
89 em_delete_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
91 wchar_t *cp, *p, *kp;
93 if (el->el_line.cursor == el->el_line.lastchar)
94 return CC_ERROR;
96 cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
97 el->el_state.argument, ce__isword);
99 for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
100 /* save the text */
101 *kp++ = *p;
102 el->el_chared.c_kill.last = kp;
104 c_delafter(el, (int)(cp - el->el_line.cursor)); /* delete after dot */
105 if (el->el_line.cursor > el->el_line.lastchar)
106 el->el_line.cursor = el->el_line.lastchar;
107 /* bounds check */
108 return CC_REFRESH;
112 /* em_yank():
113 * Paste cut buffer at cursor position
114 * [^Y]
116 protected el_action_t
117 /*ARGSUSED*/
118 em_yank(EditLine *el, wint_t c __attribute__((__unused__)))
120 wchar_t *kp, *cp;
122 if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
123 return CC_NORM;
125 if (el->el_line.lastchar +
126 (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
127 el->el_line.limit)
128 return CC_ERROR;
130 el->el_chared.c_kill.mark = el->el_line.cursor;
131 cp = el->el_line.cursor;
133 /* open the space, */
134 c_insert(el,
135 (int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf));
136 /* copy the chars */
137 for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
138 *cp++ = *kp;
140 /* if an arg, cursor at beginning else cursor at end */
141 if (el->el_state.argument == 1)
142 el->el_line.cursor = cp;
144 return CC_REFRESH;
148 /* em_kill_line():
149 * Cut the entire line and save in cut buffer
150 * [^U]
152 protected el_action_t
153 /*ARGSUSED*/
154 em_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
156 wchar_t *kp, *cp;
158 cp = el->el_line.buffer;
159 kp = el->el_chared.c_kill.buf;
160 while (cp < el->el_line.lastchar)
161 *kp++ = *cp++; /* copy it */
162 el->el_chared.c_kill.last = kp;
163 /* zap! -- delete all of it */
164 el->el_line.lastchar = el->el_line.buffer;
165 el->el_line.cursor = el->el_line.buffer;
166 return CC_REFRESH;
170 /* em_kill_region():
171 * Cut area between mark and cursor and save in cut buffer
172 * [^W]
174 protected el_action_t
175 /*ARGSUSED*/
176 em_kill_region(EditLine *el, wint_t c __attribute__((__unused__)))
178 wchar_t *kp, *cp;
180 if (!el->el_chared.c_kill.mark)
181 return CC_ERROR;
183 if (el->el_chared.c_kill.mark > el->el_line.cursor) {
184 cp = el->el_line.cursor;
185 kp = el->el_chared.c_kill.buf;
186 while (cp < el->el_chared.c_kill.mark)
187 *kp++ = *cp++; /* copy it */
188 el->el_chared.c_kill.last = kp;
189 c_delafter(el, (int)(cp - el->el_line.cursor));
190 } else { /* mark is before cursor */
191 cp = el->el_chared.c_kill.mark;
192 kp = el->el_chared.c_kill.buf;
193 while (cp < el->el_line.cursor)
194 *kp++ = *cp++; /* copy it */
195 el->el_chared.c_kill.last = kp;
196 c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark));
197 el->el_line.cursor = el->el_chared.c_kill.mark;
199 return CC_REFRESH;
203 /* em_copy_region():
204 * Copy area between mark and cursor to cut buffer
205 * [M-W]
207 protected el_action_t
208 /*ARGSUSED*/
209 em_copy_region(EditLine *el, wint_t c __attribute__((__unused__)))
211 wchar_t *kp, *cp;
213 if (!el->el_chared.c_kill.mark)
214 return CC_ERROR;
216 if (el->el_chared.c_kill.mark > el->el_line.cursor) {
217 cp = el->el_line.cursor;
218 kp = el->el_chared.c_kill.buf;
219 while (cp < el->el_chared.c_kill.mark)
220 *kp++ = *cp++; /* copy it */
221 el->el_chared.c_kill.last = kp;
222 } else {
223 cp = el->el_chared.c_kill.mark;
224 kp = el->el_chared.c_kill.buf;
225 while (cp < el->el_line.cursor)
226 *kp++ = *cp++; /* copy it */
227 el->el_chared.c_kill.last = kp;
229 return CC_NORM;
233 /* em_gosmacs_transpose():
234 * Exchange the two characters before the cursor
235 * Gosling emacs transpose chars [^T]
237 protected el_action_t
238 em_gosmacs_transpose(EditLine *el, wint_t c)
241 if (el->el_line.cursor > &el->el_line.buffer[1]) {
242 /* must have at least two chars entered */
243 c = el->el_line.cursor[-2];
244 el->el_line.cursor[-2] = el->el_line.cursor[-1];
245 el->el_line.cursor[-1] = c;
246 return CC_REFRESH;
247 } else
248 return CC_ERROR;
252 /* em_next_word():
253 * Move next to end of current word
254 * [M-f]
256 protected el_action_t
257 /*ARGSUSED*/
258 em_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
260 if (el->el_line.cursor == el->el_line.lastchar)
261 return CC_ERROR;
263 el->el_line.cursor = c__next_word(el->el_line.cursor,
264 el->el_line.lastchar,
265 el->el_state.argument,
266 ce__isword);
268 if (el->el_map.type == MAP_VI)
269 if (el->el_chared.c_vcmd.action != NOP) {
270 cv_delfini(el);
271 return CC_REFRESH;
273 return CC_CURSOR;
277 /* em_upper_case():
278 * Uppercase the characters from cursor to end of current word
279 * [M-u]
281 protected el_action_t
282 /*ARGSUSED*/
283 em_upper_case(EditLine *el, wint_t c __attribute__((__unused__)))
285 wchar_t *cp, *ep;
287 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
288 el->el_state.argument, ce__isword);
290 for (cp = el->el_line.cursor; cp < ep; cp++)
291 if (iswlower(*cp))
292 *cp = towupper(*cp);
294 el->el_line.cursor = ep;
295 if (el->el_line.cursor > el->el_line.lastchar)
296 el->el_line.cursor = el->el_line.lastchar;
297 return CC_REFRESH;
301 /* em_capitol_case():
302 * Capitalize the characters from cursor to end of current word
303 * [M-c]
305 protected el_action_t
306 /*ARGSUSED*/
307 em_capitol_case(EditLine *el, wint_t c __attribute__((__unused__)))
309 wchar_t *cp, *ep;
311 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
312 el->el_state.argument, ce__isword);
314 for (cp = el->el_line.cursor; cp < ep; cp++) {
315 if (iswalpha(*cp)) {
316 if (iswlower(*cp))
317 *cp = towupper(*cp);
318 cp++;
319 break;
322 for (; cp < ep; cp++)
323 if (iswupper(*cp))
324 *cp = towlower(*cp);
326 el->el_line.cursor = ep;
327 if (el->el_line.cursor > el->el_line.lastchar)
328 el->el_line.cursor = el->el_line.lastchar;
329 return CC_REFRESH;
333 /* em_lower_case():
334 * Lowercase the characters from cursor to end of current word
335 * [M-l]
337 protected el_action_t
338 /*ARGSUSED*/
339 em_lower_case(EditLine *el, wint_t c __attribute__((__unused__)))
341 wchar_t *cp, *ep;
343 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
344 el->el_state.argument, ce__isword);
346 for (cp = el->el_line.cursor; cp < ep; cp++)
347 if (iswupper(*cp))
348 *cp = towlower(*cp);
350 el->el_line.cursor = ep;
351 if (el->el_line.cursor > el->el_line.lastchar)
352 el->el_line.cursor = el->el_line.lastchar;
353 return CC_REFRESH;
357 /* em_set_mark():
358 * Set the mark at cursor
359 * [^@]
361 protected el_action_t
362 /*ARGSUSED*/
363 em_set_mark(EditLine *el, wint_t c __attribute__((__unused__)))
366 el->el_chared.c_kill.mark = el->el_line.cursor;
367 return CC_NORM;
371 /* em_exchange_mark():
372 * Exchange the cursor and mark
373 * [^X^X]
375 protected el_action_t
376 /*ARGSUSED*/
377 em_exchange_mark(EditLine *el, wint_t c __attribute__((__unused__)))
379 wchar_t *cp;
381 cp = el->el_line.cursor;
382 el->el_line.cursor = el->el_chared.c_kill.mark;
383 el->el_chared.c_kill.mark = cp;
384 return CC_CURSOR;
388 /* em_universal_argument():
389 * Universal argument (argument times 4)
390 * [^U]
392 protected el_action_t
393 /*ARGSUSED*/
394 em_universal_argument(EditLine *el, wint_t c __attribute__((__unused__)))
395 { /* multiply current argument by 4 */
397 if (el->el_state.argument > 1000000)
398 return CC_ERROR;
399 el->el_state.doingarg = 1;
400 el->el_state.argument *= 4;
401 return CC_ARGHACK;
405 /* em_meta_next():
406 * Add 8th bit to next character typed
407 * [<ESC>]
409 protected el_action_t
410 /*ARGSUSED*/
411 em_meta_next(EditLine *el, wint_t c __attribute__((__unused__)))
414 el->el_state.metanext = 1;
415 return CC_ARGHACK;
419 /* em_toggle_overwrite():
420 * Switch from insert to overwrite mode or vice versa
422 protected el_action_t
423 /*ARGSUSED*/
424 em_toggle_overwrite(EditLine *el, wint_t c __attribute__((__unused__)))
427 el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
428 MODE_REPLACE : MODE_INSERT;
429 return CC_NORM;
433 /* em_copy_prev_word():
434 * Copy current word to cursor
436 protected el_action_t
437 /*ARGSUSED*/
438 em_copy_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
440 wchar_t *cp, *oldc, *dp;
442 if (el->el_line.cursor == el->el_line.buffer)
443 return CC_ERROR;
445 oldc = el->el_line.cursor;
446 /* does a bounds check */
447 cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
448 el->el_state.argument, ce__isword);
450 c_insert(el, (int)(oldc - cp));
451 for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
452 *dp++ = *cp;
454 el->el_line.cursor = dp;/* put cursor at end */
456 return CC_REFRESH;
460 /* em_inc_search_next():
461 * Emacs incremental next search
463 protected el_action_t
464 /*ARGSUSED*/
465 em_inc_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
468 el->el_search.patlen = 0;
469 return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
473 /* em_inc_search_prev():
474 * Emacs incremental reverse search
476 protected el_action_t
477 /*ARGSUSED*/
478 em_inc_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
481 el->el_search.patlen = 0;
482 return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
486 /* em_delete_prev_char():
487 * Delete the character to the left of the cursor
488 * [^?]
490 protected el_action_t
491 /*ARGSUSED*/
492 em_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
495 if (el->el_line.cursor <= el->el_line.buffer)
496 return CC_ERROR;
498 if (el->el_state.doingarg)
499 c_delbefore(el, el->el_state.argument);
500 else
501 c_delbefore1(el);
502 el->el_line.cursor -= el->el_state.argument;
503 if (el->el_line.cursor < el->el_line.buffer)
504 el->el_line.cursor = el->el_line.buffer;
505 return CC_REFRESH;