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