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