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