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