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