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