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