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