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