1 /* $NetBSD: emacs.c,v 1.12 2002/11/15 14:32:33 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. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include "config.h" 40 #if !defined(lint) && !defined(SCCSID) 41 #if 0 42 static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93"; 43 #else 44 __RCSID("$NetBSD: emacs.c,v 1.12 2002/11/15 14:32:33 christos Exp $"); 45 #endif 46 #endif /* not lint && not SCCSID */ 47 48 /* 49 * emacs.c: Emacs functions 50 */ 51 #include "el.h" 52 53 /* em_delete_or_list(): 54 * Delete character under cursor or list completions if at end of line 55 * [^D] 56 */ 57 protected el_action_t 58 /*ARGSUSED*/ 59 em_delete_or_list(EditLine *el, int 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 term_overwrite(el, STReof, 4); /* then do a EOF */ 67 term__flush(); 68 return (CC_EOF); 69 } else { 70 /* 71 * Here we could list completions, but it is an 72 * error right now 73 */ 74 term_beep(el); 75 return (CC_ERROR); 76 } 77 } else { 78 c_delafter(el, el->el_state.argument); /* delete after dot */ 79 if (el->el_line.cursor > el->el_line.lastchar) 80 el->el_line.cursor = el->el_line.lastchar; 81 /* bounds check */ 82 return (CC_REFRESH); 83 } 84 } 85 86 87 /* em_delete_next_word(): 88 * Cut from cursor to end of current word 89 * [M-d] 90 */ 91 protected el_action_t 92 /*ARGSUSED*/ 93 em_delete_next_word(EditLine *el, int c) 94 { 95 char *cp, *p, *kp; 96 97 if (el->el_line.cursor == el->el_line.lastchar) 98 return (CC_ERROR); 99 100 cp = c__next_word(el->el_line.cursor, el->el_line.lastchar, 101 el->el_state.argument, ce__isword); 102 103 for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++) 104 /* save the text */ 105 *kp++ = *p; 106 el->el_chared.c_kill.last = kp; 107 108 c_delafter(el, cp - el->el_line.cursor); /* delete after dot */ 109 if (el->el_line.cursor > el->el_line.lastchar) 110 el->el_line.cursor = el->el_line.lastchar; 111 /* bounds check */ 112 return (CC_REFRESH); 113 } 114 115 116 /* em_yank(): 117 * Paste cut buffer at cursor position 118 * [^Y] 119 */ 120 protected el_action_t 121 /*ARGSUSED*/ 122 em_yank(EditLine *el, int c) 123 { 124 char *kp, *cp; 125 126 if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) { 127 if (!ch_enlargebufs(el, 1)) 128 return (CC_ERROR); 129 } 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, 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, int c) 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, int c) 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, 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, 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, int c) 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_traspose(): 239 * Exchange the two characters before the cursor 240 * Gosling emacs transpose chars [^T] 241 */ 242 protected el_action_t 243 em_gosmacs_traspose(EditLine *el, int 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] = 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, int c) 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, int c) 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((unsigned char) *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, int c) 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((unsigned char) *cp)) { 321 if (islower((unsigned char) *cp)) 322 *cp = toupper(*cp); 323 cp++; 324 break; 325 } 326 } 327 for (; cp < ep; cp++) 328 if (isupper((unsigned char) *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, int c) 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((unsigned char) *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, int c) 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, int c) 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, int c) 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, int c) 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, int c) 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, int c) 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, 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, int c) 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, int c) 484 { 485 486 el->el_search.patlen = 0; 487 return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY)); 488 } 489