1 /* $NetBSD: emacs.c,v 1.32 2016/02/16 22:53:14 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.32 2016/02/16 22:53:14 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 /*
47 * emacs.c: Emacs functions
48 */
49 #include <ctype.h>
50
51 #include "el.h"
52 #include "emacs.h"
53
54 /* em_delete_or_list():
55 * Delete character under cursor or list completions if at end of line
56 * [^D]
57 */
58 protected el_action_t
59 /*ARGSUSED*/
em_delete_or_list(EditLine * el,wint_t c)60 em_delete_or_list(EditLine *el, wint_t c)
61 {
62
63 if (el->el_line.cursor == el->el_line.lastchar) {
64 /* if I'm at the end */
65 if (el->el_line.cursor == el->el_line.buffer) {
66 /* and the beginning */
67 terminal_writec(el, c); /* then do an EOF */
68 return CC_EOF;
69 } else {
70 /*
71 * Here we could list completions, but it is an
72 * error right now
73 */
74 terminal_beep(el);
75 return CC_ERROR;
76 }
77 } else {
78 if (el->el_state.doingarg)
79 c_delafter(el, el->el_state.argument);
80 else
81 c_delafter1(el);
82 if (el->el_line.cursor > el->el_line.lastchar)
83 el->el_line.cursor = el->el_line.lastchar;
84 /* bounds check */
85 return CC_REFRESH;
86 }
87 }
88
89
90 /* em_delete_next_word():
91 * Cut from cursor to end of current word
92 * [M-d]
93 */
94 protected el_action_t
95 /*ARGSUSED*/
em_delete_next_word(EditLine * el,wint_t c)96 em_delete_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
97 {
98 Char *cp, *p, *kp;
99
100 if (el->el_line.cursor == el->el_line.lastchar)
101 return CC_ERROR;
102
103 cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
104 el->el_state.argument, ce__isword);
105
106 for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
107 /* save the text */
108 *kp++ = *p;
109 el->el_chared.c_kill.last = kp;
110
111 c_delafter(el, (int)(cp - el->el_line.cursor)); /* delete after dot */
112 if (el->el_line.cursor > el->el_line.lastchar)
113 el->el_line.cursor = el->el_line.lastchar;
114 /* bounds check */
115 return CC_REFRESH;
116 }
117
118
119 /* em_yank():
120 * Paste cut buffer at cursor position
121 * [^Y]
122 */
123 protected el_action_t
124 /*ARGSUSED*/
em_yank(EditLine * el,wint_t c)125 em_yank(EditLine *el, wint_t c __attribute__((__unused__)))
126 {
127 Char *kp, *cp;
128
129 if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
130 return CC_NORM;
131
132 if (el->el_line.lastchar +
133 (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
134 el->el_line.limit)
135 return CC_ERROR;
136
137 el->el_chared.c_kill.mark = el->el_line.cursor;
138 cp = el->el_line.cursor;
139
140 /* open the space, */
141 c_insert(el,
142 (int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf));
143 /* copy the chars */
144 for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
145 *cp++ = *kp;
146
147 /* if an arg, cursor at beginning else cursor at end */
148 if (el->el_state.argument == 1)
149 el->el_line.cursor = cp;
150
151 return CC_REFRESH;
152 }
153
154
155 /* em_kill_line():
156 * Cut the entire line and save in cut buffer
157 * [^U]
158 */
159 protected el_action_t
160 /*ARGSUSED*/
em_kill_line(EditLine * el,wint_t c)161 em_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
162 {
163 Char *kp, *cp;
164
165 cp = el->el_line.buffer;
166 kp = el->el_chared.c_kill.buf;
167 while (cp < el->el_line.lastchar)
168 *kp++ = *cp++; /* copy it */
169 el->el_chared.c_kill.last = kp;
170 /* zap! -- delete all of it */
171 el->el_line.lastchar = el->el_line.buffer;
172 el->el_line.cursor = el->el_line.buffer;
173 return CC_REFRESH;
174 }
175
176
177 /* em_kill_region():
178 * Cut area between mark and cursor and save in cut buffer
179 * [^W]
180 */
181 protected el_action_t
182 /*ARGSUSED*/
em_kill_region(EditLine * el,wint_t c)183 em_kill_region(EditLine *el, wint_t c __attribute__((__unused__)))
184 {
185 Char *kp, *cp;
186
187 if (!el->el_chared.c_kill.mark)
188 return CC_ERROR;
189
190 if (el->el_chared.c_kill.mark > el->el_line.cursor) {
191 cp = el->el_line.cursor;
192 kp = el->el_chared.c_kill.buf;
193 while (cp < el->el_chared.c_kill.mark)
194 *kp++ = *cp++; /* copy it */
195 el->el_chared.c_kill.last = kp;
196 c_delafter(el, (int)(cp - el->el_line.cursor));
197 } else { /* mark is before cursor */
198 cp = el->el_chared.c_kill.mark;
199 kp = el->el_chared.c_kill.buf;
200 while (cp < el->el_line.cursor)
201 *kp++ = *cp++; /* copy it */
202 el->el_chared.c_kill.last = kp;
203 c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark));
204 el->el_line.cursor = el->el_chared.c_kill.mark;
205 }
206 return CC_REFRESH;
207 }
208
209
210 /* em_copy_region():
211 * Copy area between mark and cursor to cut buffer
212 * [M-W]
213 */
214 protected el_action_t
215 /*ARGSUSED*/
em_copy_region(EditLine * el,wint_t c)216 em_copy_region(EditLine *el, wint_t c __attribute__((__unused__)))
217 {
218 Char *kp, *cp;
219
220 if (!el->el_chared.c_kill.mark)
221 return CC_ERROR;
222
223 if (el->el_chared.c_kill.mark > el->el_line.cursor) {
224 cp = el->el_line.cursor;
225 kp = el->el_chared.c_kill.buf;
226 while (cp < el->el_chared.c_kill.mark)
227 *kp++ = *cp++; /* copy it */
228 el->el_chared.c_kill.last = kp;
229 } else {
230 cp = el->el_chared.c_kill.mark;
231 kp = el->el_chared.c_kill.buf;
232 while (cp < el->el_line.cursor)
233 *kp++ = *cp++; /* copy it */
234 el->el_chared.c_kill.last = kp;
235 }
236 return CC_NORM;
237 }
238
239
240 /* em_gosmacs_transpose():
241 * Exchange the two characters before the cursor
242 * Gosling emacs transpose chars [^T]
243 */
244 protected el_action_t
em_gosmacs_transpose(EditLine * el,wint_t c)245 em_gosmacs_transpose(EditLine *el, wint_t c)
246 {
247
248 if (el->el_line.cursor > &el->el_line.buffer[1]) {
249 /* must have at least two chars entered */
250 c = el->el_line.cursor[-2];
251 el->el_line.cursor[-2] = el->el_line.cursor[-1];
252 el->el_line.cursor[-1] = (Char)c;
253 return CC_REFRESH;
254 } else
255 return CC_ERROR;
256 }
257
258
259 /* em_next_word():
260 * Move next to end of current word
261 * [M-f]
262 */
263 protected el_action_t
264 /*ARGSUSED*/
em_next_word(EditLine * el,wint_t c)265 em_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
266 {
267 if (el->el_line.cursor == el->el_line.lastchar)
268 return CC_ERROR;
269
270 el->el_line.cursor = c__next_word(el->el_line.cursor,
271 el->el_line.lastchar,
272 el->el_state.argument,
273 ce__isword);
274
275 if (el->el_map.type == MAP_VI)
276 if (el->el_chared.c_vcmd.action != NOP) {
277 cv_delfini(el);
278 return CC_REFRESH;
279 }
280 return CC_CURSOR;
281 }
282
283
284 /* em_upper_case():
285 * Uppercase the characters from cursor to end of current word
286 * [M-u]
287 */
288 protected el_action_t
289 /*ARGSUSED*/
em_upper_case(EditLine * el,wint_t c)290 em_upper_case(EditLine *el, wint_t c __attribute__((__unused__)))
291 {
292 Char *cp, *ep;
293
294 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
295 el->el_state.argument, ce__isword);
296
297 for (cp = el->el_line.cursor; cp < ep; cp++)
298 if (Islower(*cp))
299 *cp = Toupper(*cp);
300
301 el->el_line.cursor = ep;
302 if (el->el_line.cursor > el->el_line.lastchar)
303 el->el_line.cursor = el->el_line.lastchar;
304 return CC_REFRESH;
305 }
306
307
308 /* em_capitol_case():
309 * Capitalize the characters from cursor to end of current word
310 * [M-c]
311 */
312 protected el_action_t
313 /*ARGSUSED*/
em_capitol_case(EditLine * el,wint_t c)314 em_capitol_case(EditLine *el, wint_t c __attribute__((__unused__)))
315 {
316 Char *cp, *ep;
317
318 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
319 el->el_state.argument, ce__isword);
320
321 for (cp = el->el_line.cursor; cp < ep; cp++) {
322 if (Isalpha(*cp)) {
323 if (Islower(*cp))
324 *cp = Toupper(*cp);
325 cp++;
326 break;
327 }
328 }
329 for (; cp < ep; cp++)
330 if (Isupper(*cp))
331 *cp = Tolower(*cp);
332
333 el->el_line.cursor = ep;
334 if (el->el_line.cursor > el->el_line.lastchar)
335 el->el_line.cursor = el->el_line.lastchar;
336 return CC_REFRESH;
337 }
338
339
340 /* em_lower_case():
341 * Lowercase the characters from cursor to end of current word
342 * [M-l]
343 */
344 protected el_action_t
345 /*ARGSUSED*/
em_lower_case(EditLine * el,wint_t c)346 em_lower_case(EditLine *el, wint_t c __attribute__((__unused__)))
347 {
348 Char *cp, *ep;
349
350 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
351 el->el_state.argument, ce__isword);
352
353 for (cp = el->el_line.cursor; cp < ep; cp++)
354 if (Isupper(*cp))
355 *cp = Tolower(*cp);
356
357 el->el_line.cursor = ep;
358 if (el->el_line.cursor > el->el_line.lastchar)
359 el->el_line.cursor = el->el_line.lastchar;
360 return CC_REFRESH;
361 }
362
363
364 /* em_set_mark():
365 * Set the mark at cursor
366 * [^@]
367 */
368 protected el_action_t
369 /*ARGSUSED*/
em_set_mark(EditLine * el,wint_t c)370 em_set_mark(EditLine *el, wint_t c __attribute__((__unused__)))
371 {
372
373 el->el_chared.c_kill.mark = el->el_line.cursor;
374 return CC_NORM;
375 }
376
377
378 /* em_exchange_mark():
379 * Exchange the cursor and mark
380 * [^X^X]
381 */
382 protected el_action_t
383 /*ARGSUSED*/
em_exchange_mark(EditLine * el,wint_t c)384 em_exchange_mark(EditLine *el, wint_t c __attribute__((__unused__)))
385 {
386 Char *cp;
387
388 cp = el->el_line.cursor;
389 el->el_line.cursor = el->el_chared.c_kill.mark;
390 el->el_chared.c_kill.mark = cp;
391 return CC_CURSOR;
392 }
393
394
395 /* em_universal_argument():
396 * Universal argument (argument times 4)
397 * [^U]
398 */
399 protected el_action_t
400 /*ARGSUSED*/
em_universal_argument(EditLine * el,wint_t c)401 em_universal_argument(EditLine *el, wint_t c __attribute__((__unused__)))
402 { /* multiply current argument by 4 */
403
404 if (el->el_state.argument > 1000000)
405 return CC_ERROR;
406 el->el_state.doingarg = 1;
407 el->el_state.argument *= 4;
408 return CC_ARGHACK;
409 }
410
411
412 /* em_meta_next():
413 * Add 8th bit to next character typed
414 * [<ESC>]
415 */
416 protected el_action_t
417 /*ARGSUSED*/
em_meta_next(EditLine * el,wint_t c)418 em_meta_next(EditLine *el, wint_t c __attribute__((__unused__)))
419 {
420
421 el->el_state.metanext = 1;
422 return CC_ARGHACK;
423 }
424
425
426 /* em_toggle_overwrite():
427 * Switch from insert to overwrite mode or vice versa
428 */
429 protected el_action_t
430 /*ARGSUSED*/
em_toggle_overwrite(EditLine * el,wint_t c)431 em_toggle_overwrite(EditLine *el, wint_t c __attribute__((__unused__)))
432 {
433
434 el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
435 MODE_REPLACE : MODE_INSERT;
436 return CC_NORM;
437 }
438
439
440 /* em_copy_prev_word():
441 * Copy current word to cursor
442 */
443 protected el_action_t
444 /*ARGSUSED*/
em_copy_prev_word(EditLine * el,wint_t c)445 em_copy_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
446 {
447 Char *cp, *oldc, *dp;
448
449 if (el->el_line.cursor == el->el_line.buffer)
450 return CC_ERROR;
451
452 oldc = el->el_line.cursor;
453 /* does a bounds check */
454 cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
455 el->el_state.argument, ce__isword);
456
457 c_insert(el, (int)(oldc - cp));
458 for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
459 *dp++ = *cp;
460
461 el->el_line.cursor = dp;/* put cursor at end */
462
463 return CC_REFRESH;
464 }
465
466
467 /* em_inc_search_next():
468 * Emacs incremental next search
469 */
470 protected el_action_t
471 /*ARGSUSED*/
em_inc_search_next(EditLine * el,wint_t c)472 em_inc_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
473 {
474
475 el->el_search.patlen = 0;
476 return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
477 }
478
479
480 /* em_inc_search_prev():
481 * Emacs incremental reverse search
482 */
483 protected el_action_t
484 /*ARGSUSED*/
em_inc_search_prev(EditLine * el,wint_t c)485 em_inc_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
486 {
487
488 el->el_search.patlen = 0;
489 return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
490 }
491
492
493 /* em_delete_prev_char():
494 * Delete the character to the left of the cursor
495 * [^?]
496 */
497 protected el_action_t
498 /*ARGSUSED*/
em_delete_prev_char(EditLine * el,wint_t c)499 em_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
500 {
501
502 if (el->el_line.cursor <= el->el_line.buffer)
503 return CC_ERROR;
504
505 if (el->el_state.doingarg)
506 c_delbefore(el, el->el_state.argument);
507 else
508 c_delbefore1(el);
509 el->el_line.cursor -= el->el_state.argument;
510 if (el->el_line.cursor < el->el_line.buffer)
511 el->el_line.cursor = el->el_line.buffer;
512 return CC_REFRESH;
513 }
514