emacs.c revision 84260
1/*- 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Christos Zoulas of Cornell University. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $NetBSD: emacs.c,v 1.8 2000/09/04 22:06:29 lukem Exp $ 37 */ 38 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: head/lib/libedit/emacs.c 84260 2001-10-01 08:41:27Z obrien $"); 41#if !defined(lint) && !defined(SCCSID) 42static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93"; 43#endif /* not lint && not SCCSID */ 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD: head/lib/libedit/emacs.c 84260 2001-10-01 08:41:27Z obrien $"); 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 */ 57protected el_action_t 58/*ARGSUSED*/ 59em_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 */ 91protected el_action_t 92/*ARGSUSED*/ 93em_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 */ 120protected el_action_t 121/*ARGSUSED*/ 122em_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 */ 157protected el_action_t 158/*ARGSUSED*/ 159em_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 */ 179protected el_action_t 180/*ARGSUSED*/ 181em_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 */ 212protected el_action_t 213/*ARGSUSED*/ 214em_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 */ 242protected el_action_t 243em_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 */ 261protected el_action_t 262/*ARGSUSED*/ 263em_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 & DELETE) { 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 */ 286protected el_action_t 287/*ARGSUSED*/ 288em_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((unsigned char) *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 */ 310protected el_action_t 311/*ARGSUSED*/ 312em_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((unsigned char) *cp); 323 cp++; 324 break; 325 } 326 } 327 for (; cp < ep; cp++) 328 if (isupper((unsigned char) *cp)) 329 *cp = tolower((unsigned char) *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 */ 342protected el_action_t 343/*ARGSUSED*/ 344em_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((unsigned char) *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 */ 366protected el_action_t 367/*ARGSUSED*/ 368em_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 */ 380protected el_action_t 381/*ARGSUSED*/ 382em_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 */ 397protected el_action_t 398/*ARGSUSED*/ 399em_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 */ 414protected el_action_t 415/*ARGSUSED*/ 416em_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 */ 427protected el_action_t 428/*ARGSUSED*/ 429em_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 */ 441protected el_action_t 442/*ARGSUSED*/ 443em_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 */ 468protected el_action_t 469/*ARGSUSED*/ 470em_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 */ 481protected el_action_t 482/*ARGSUSED*/ 483em_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