1 /* $NetBSD: emacs.c,v 1.21 2006/03/06 21:11: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.21 2006/03/06 21:11:56 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*/ 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 term_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 term_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*/ 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, 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*/ 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, el->el_chared.c_kill.last - el->el_chared.c_kill.buf); 137 /* copy the chars */ 138 for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++) 139 *cp++ = *kp; 140 141 /* if an arg, cursor at beginning else cursor at end */ 142 if (el->el_state.argument == 1) 143 el->el_line.cursor = cp; 144 145 return (CC_REFRESH); 146 } 147 148 149 /* em_kill_line(): 150 * Cut the entire line and save in cut buffer 151 * [^U] 152 */ 153 protected el_action_t 154 /*ARGSUSED*/ 155 em_kill_line(EditLine *el, int c __attribute__((__unused__))) 156 { 157 char *kp, *cp; 158 159 cp = el->el_line.buffer; 160 kp = el->el_chared.c_kill.buf; 161 while (cp < el->el_line.lastchar) 162 *kp++ = *cp++; /* copy it */ 163 el->el_chared.c_kill.last = kp; 164 /* zap! -- delete all of it */ 165 el->el_line.lastchar = el->el_line.buffer; 166 el->el_line.cursor = el->el_line.buffer; 167 return (CC_REFRESH); 168 } 169 170 171 /* em_kill_region(): 172 * Cut area between mark and cursor and save in cut buffer 173 * [^W] 174 */ 175 protected el_action_t 176 /*ARGSUSED*/ 177 em_kill_region(EditLine *el, int c __attribute__((__unused__))) 178 { 179 char *kp, *cp; 180 181 if (!el->el_chared.c_kill.mark) 182 return (CC_ERROR); 183 184 if (el->el_chared.c_kill.mark > el->el_line.cursor) { 185 cp = el->el_line.cursor; 186 kp = el->el_chared.c_kill.buf; 187 while (cp < el->el_chared.c_kill.mark) 188 *kp++ = *cp++; /* copy it */ 189 el->el_chared.c_kill.last = kp; 190 c_delafter(el, cp - el->el_line.cursor); 191 } else { /* mark is before cursor */ 192 cp = el->el_chared.c_kill.mark; 193 kp = el->el_chared.c_kill.buf; 194 while (cp < el->el_line.cursor) 195 *kp++ = *cp++; /* copy it */ 196 el->el_chared.c_kill.last = kp; 197 c_delbefore(el, cp - el->el_chared.c_kill.mark); 198 el->el_line.cursor = el->el_chared.c_kill.mark; 199 } 200 return (CC_REFRESH); 201 } 202 203 204 /* em_copy_region(): 205 * Copy area between mark and cursor to cut buffer 206 * [M-W] 207 */ 208 protected el_action_t 209 /*ARGSUSED*/ 210 em_copy_region(EditLine *el, int c __attribute__((__unused__))) 211 { 212 char *kp, *cp; 213 214 if (!el->el_chared.c_kill.mark) 215 return (CC_ERROR); 216 217 if (el->el_chared.c_kill.mark > el->el_line.cursor) { 218 cp = el->el_line.cursor; 219 kp = el->el_chared.c_kill.buf; 220 while (cp < el->el_chared.c_kill.mark) 221 *kp++ = *cp++; /* copy it */ 222 el->el_chared.c_kill.last = kp; 223 } else { 224 cp = el->el_chared.c_kill.mark; 225 kp = el->el_chared.c_kill.buf; 226 while (cp < el->el_line.cursor) 227 *kp++ = *cp++; /* copy it */ 228 el->el_chared.c_kill.last = kp; 229 } 230 return (CC_NORM); 231 } 232 233 234 /* em_gosmacs_transpose(): 235 * Exchange the two characters before the cursor 236 * Gosling emacs transpose chars [^T] 237 */ 238 protected el_action_t 239 em_gosmacs_transpose(EditLine *el, int c) 240 { 241 242 if (el->el_line.cursor > &el->el_line.buffer[1]) { 243 /* must have at least two chars entered */ 244 c = el->el_line.cursor[-2]; 245 el->el_line.cursor[-2] = el->el_line.cursor[-1]; 246 el->el_line.cursor[-1] = c; 247 return (CC_REFRESH); 248 } else 249 return (CC_ERROR); 250 } 251 252 253 /* em_next_word(): 254 * Move next to end of current word 255 * [M-f] 256 */ 257 protected el_action_t 258 /*ARGSUSED*/ 259 em_next_word(EditLine *el, int c __attribute__((__unused__))) 260 { 261 if (el->el_line.cursor == el->el_line.lastchar) 262 return (CC_ERROR); 263 264 el->el_line.cursor = c__next_word(el->el_line.cursor, 265 el->el_line.lastchar, 266 el->el_state.argument, 267 ce__isword); 268 269 if (el->el_map.type == MAP_VI) 270 if (el->el_chared.c_vcmd.action != NOP) { 271 cv_delfini(el); 272 return (CC_REFRESH); 273 } 274 return (CC_CURSOR); 275 } 276 277 278 /* em_upper_case(): 279 * Uppercase the characters from cursor to end of current word 280 * [M-u] 281 */ 282 protected el_action_t 283 /*ARGSUSED*/ 284 em_upper_case(EditLine *el, int c __attribute__((__unused__))) 285 { 286 char *cp, *ep; 287 288 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, 289 el->el_state.argument, ce__isword); 290 291 for (cp = el->el_line.cursor; cp < ep; cp++) 292 if (islower((unsigned char)*cp)) 293 *cp = toupper((unsigned char)*cp); 294 295 el->el_line.cursor = ep; 296 if (el->el_line.cursor > el->el_line.lastchar) 297 el->el_line.cursor = el->el_line.lastchar; 298 return (CC_REFRESH); 299 } 300 301 302 /* em_capitol_case(): 303 * Capitalize the characters from cursor to end of current word 304 * [M-c] 305 */ 306 protected el_action_t 307 /*ARGSUSED*/ 308 em_capitol_case(EditLine *el, int c __attribute__((__unused__))) 309 { 310 char *cp, *ep; 311 312 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, 313 el->el_state.argument, ce__isword); 314 315 for (cp = el->el_line.cursor; cp < ep; cp++) { 316 if (isalpha((unsigned char)*cp)) { 317 if (islower((unsigned char)*cp)) 318 *cp = toupper((unsigned char)*cp); 319 cp++; 320 break; 321 } 322 } 323 for (; cp < ep; cp++) 324 if (isupper((unsigned char)*cp)) 325 *cp = tolower((unsigned char)*cp); 326 327 el->el_line.cursor = ep; 328 if (el->el_line.cursor > el->el_line.lastchar) 329 el->el_line.cursor = el->el_line.lastchar; 330 return (CC_REFRESH); 331 } 332 333 334 /* em_lower_case(): 335 * Lowercase the characters from cursor to end of current word 336 * [M-l] 337 */ 338 protected el_action_t 339 /*ARGSUSED*/ 340 em_lower_case(EditLine *el, int c __attribute__((__unused__))) 341 { 342 char *cp, *ep; 343 344 ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, 345 el->el_state.argument, ce__isword); 346 347 for (cp = el->el_line.cursor; cp < ep; cp++) 348 if (isupper((unsigned char)*cp)) 349 *cp = tolower((unsigned char)*cp); 350 351 el->el_line.cursor = ep; 352 if (el->el_line.cursor > el->el_line.lastchar) 353 el->el_line.cursor = el->el_line.lastchar; 354 return (CC_REFRESH); 355 } 356 357 358 /* em_set_mark(): 359 * Set the mark at cursor 360 * [^@] 361 */ 362 protected el_action_t 363 /*ARGSUSED*/ 364 em_set_mark(EditLine *el, int c __attribute__((__unused__))) 365 { 366 367 el->el_chared.c_kill.mark = el->el_line.cursor; 368 return (CC_NORM); 369 } 370 371 372 /* em_exchange_mark(): 373 * Exchange the cursor and mark 374 * [^X^X] 375 */ 376 protected el_action_t 377 /*ARGSUSED*/ 378 em_exchange_mark(EditLine *el, int c __attribute__((__unused__))) 379 { 380 char *cp; 381 382 cp = el->el_line.cursor; 383 el->el_line.cursor = el->el_chared.c_kill.mark; 384 el->el_chared.c_kill.mark = cp; 385 return (CC_CURSOR); 386 } 387 388 389 /* em_universal_argument(): 390 * Universal argument (argument times 4) 391 * [^U] 392 */ 393 protected el_action_t 394 /*ARGSUSED*/ 395 em_universal_argument(EditLine *el, int c __attribute__((__unused__))) 396 { /* multiply current argument by 4 */ 397 398 if (el->el_state.argument > 1000000) 399 return (CC_ERROR); 400 el->el_state.doingarg = 1; 401 el->el_state.argument *= 4; 402 return (CC_ARGHACK); 403 } 404 405 406 /* em_meta_next(): 407 * Add 8th bit to next character typed 408 * [<ESC>] 409 */ 410 protected el_action_t 411 /*ARGSUSED*/ 412 em_meta_next(EditLine *el, int c __attribute__((__unused__))) 413 { 414 415 el->el_state.metanext = 1; 416 return (CC_ARGHACK); 417 } 418 419 420 /* em_toggle_overwrite(): 421 * Switch from insert to overwrite mode or vice versa 422 */ 423 protected el_action_t 424 /*ARGSUSED*/ 425 em_toggle_overwrite(EditLine *el, int c __attribute__((__unused__))) 426 { 427 428 el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ? 429 MODE_REPLACE : MODE_INSERT; 430 return (CC_NORM); 431 } 432 433 434 /* em_copy_prev_word(): 435 * Copy current word to cursor 436 */ 437 protected el_action_t 438 /*ARGSUSED*/ 439 em_copy_prev_word(EditLine *el, int c __attribute__((__unused__))) 440 { 441 char *cp, *oldc, *dp; 442 443 if (el->el_line.cursor == el->el_line.buffer) 444 return (CC_ERROR); 445 446 oldc = el->el_line.cursor; 447 /* does a bounds check */ 448 cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, 449 el->el_state.argument, ce__isword); 450 451 c_insert(el, oldc - cp); 452 for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++) 453 *dp++ = *cp; 454 455 el->el_line.cursor = dp;/* put cursor at end */ 456 457 return (CC_REFRESH); 458 } 459 460 461 /* em_inc_search_next(): 462 * Emacs incremental next search 463 */ 464 protected el_action_t 465 /*ARGSUSED*/ 466 em_inc_search_next(EditLine *el, int c __attribute__((__unused__))) 467 { 468 469 el->el_search.patlen = 0; 470 return (ce_inc_search(el, ED_SEARCH_NEXT_HISTORY)); 471 } 472 473 474 /* em_inc_search_prev(): 475 * Emacs incremental reverse search 476 */ 477 protected el_action_t 478 /*ARGSUSED*/ 479 em_inc_search_prev(EditLine *el, int c __attribute__((__unused__))) 480 { 481 482 el->el_search.patlen = 0; 483 return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY)); 484 } 485 486 487 /* em_delete_prev_char(): 488 * Delete the character to the left of the cursor 489 * [^?] 490 */ 491 protected el_action_t 492 /*ARGSUSED*/ 493 em_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) 494 { 495 496 if (el->el_line.cursor <= el->el_line.buffer) 497 return (CC_ERROR); 498 499 if (el->el_state.doingarg) 500 c_delbefore(el, el->el_state.argument); 501 else 502 c_delbefore1(el); 503 el->el_line.cursor -= el->el_state.argument; 504 if (el->el_line.cursor < el->el_line.buffer) 505 el->el_line.cursor = el->el_line.buffer; 506 return (CC_REFRESH); 507 } 508