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