1 1.21 christos /* $NetBSD: vi.c,v 1.21 2021/09/16 19:44:01 christos Exp $ */ 2 1.2 tls 3 1.1 jtc /* 4 1.1 jtc * vi command editing 5 1.1 jtc * written by John Rochester (initially for nsh) 6 1.1 jtc * bludgeoned to fit pdksh by Larry Bouzane, Jeff Sparkes & Eric Gisin 7 1.1 jtc * 8 1.1 jtc */ 9 1.7 agc #include <sys/cdefs.h> 10 1.7 agc 11 1.7 agc #ifndef lint 12 1.21 christos __RCSID("$NetBSD: vi.c,v 1.21 2021/09/16 19:44:01 christos Exp $"); 13 1.7 agc #endif 14 1.7 agc 15 1.1 jtc #include "config.h" 16 1.1 jtc #ifdef VI 17 1.1 jtc 18 1.1 jtc #include "sh.h" 19 1.17 kamil #include <sys/stat.h> 20 1.1 jtc #include <ctype.h> 21 1.1 jtc #include "edit.h" 22 1.1 jtc 23 1.1 jtc #define CMDLEN 1024 24 1.1 jtc #define Ctrl(c) (c&0x1f) 25 1.1 jtc #define is_wordch(c) (letnum(c)) 26 1.1 jtc 27 1.1 jtc struct edstate { 28 1.1 jtc int winleft; 29 1.1 jtc char *cbuf; 30 1.1 jtc int cbufsize; 31 1.1 jtc int linelen; 32 1.1 jtc int cursor; 33 1.1 jtc }; 34 1.1 jtc 35 1.1 jtc 36 1.10 christos static int vi_hook ARGS((int)); 37 1.10 christos static void vi_reset ARGS((char *, size_t)); 38 1.10 christos static int nextstate ARGS((int)); 39 1.10 christos static int vi_insert ARGS((int)); 40 1.10 christos static int vi_cmd ARGS((int, const char *)); 41 1.10 christos static int domove ARGS((int, const char *, int)); 42 1.10 christos static int redo_insert ARGS((int)); 43 1.10 christos static void yank_range ARGS((int, int)); 44 1.10 christos static int bracktype ARGS((int)); 45 1.1 jtc static void save_cbuf ARGS((void)); 46 1.1 jtc static void restore_cbuf ARGS((void)); 47 1.10 christos static void edit_reset ARGS((char *, size_t)); 48 1.10 christos static int putbuf ARGS((const char *, int, int)); 49 1.10 christos static void del_range ARGS((int, int)); 50 1.10 christos static int findch ARGS((int, int, int, int)); 51 1.10 christos static int forwword ARGS((int)); 52 1.10 christos static int backword ARGS((int)); 53 1.10 christos static int endword ARGS((int)); 54 1.10 christos static int Forwword ARGS((int)); 55 1.10 christos static int Backword ARGS((int)); 56 1.10 christos static int Endword ARGS((int)); 57 1.10 christos static int grabhist ARGS((int, int)); 58 1.10 christos static int grabsearch ARGS((int, int, int, char *)); 59 1.10 christos static void redraw_line ARGS((int)); 60 1.10 christos static void refresh ARGS((int)); 61 1.1 jtc static int outofwin ARGS((void)); 62 1.1 jtc static void rewindow ARGS((void)); 63 1.10 christos static int newcol ARGS((int, int)); 64 1.10 christos static void display ARGS((char *, char *, int)); 65 1.10 christos static void ed_mov_opt ARGS((int, char *)); 66 1.10 christos static int expand_word ARGS((int)); 67 1.10 christos static int complete_word ARGS((int, int)); 68 1.10 christos static int print_expansions ARGS((struct edstate *, int)); 69 1.10 christos static int char_len ARGS((int)); 70 1.10 christos static void x_vi_zotc ARGS((int)); 71 1.10 christos static void vi_pprompt ARGS((int)); 72 1.1 jtc static void vi_error ARGS((void)); 73 1.1 jtc static void vi_macro_reset ARGS((void)); 74 1.10 christos static int x_vi_putbuf ARGS((const char *, size_t)); 75 1.1 jtc 76 1.1 jtc #define C_ 0x1 /* a valid command that isn't a M_, E_, U_ */ 77 1.1 jtc #define M_ 0x2 /* movement command (h, l, etc.) */ 78 1.1 jtc #define E_ 0x4 /* extended command (c, d, y) */ 79 1.1 jtc #define X_ 0x8 /* long command (@, f, F, t, T, etc.) */ 80 1.1 jtc #define U_ 0x10 /* an UN-undoable command (that isn't a M_) */ 81 1.1 jtc #define B_ 0x20 /* bad command (^@) */ 82 1.1 jtc #define Z_ 0x40 /* repeat count defaults to 0 (not 1) */ 83 1.1 jtc #define S_ 0x80 /* search (/, ?) */ 84 1.1 jtc 85 1.1 jtc #define is_bad(c) (classify[(c)&0x7f]&B_) 86 1.1 jtc #define is_cmd(c) (classify[(c)&0x7f]&(M_|E_|C_|U_)) 87 1.1 jtc #define is_move(c) (classify[(c)&0x7f]&M_) 88 1.1 jtc #define is_extend(c) (classify[(c)&0x7f]&E_) 89 1.1 jtc #define is_long(c) (classify[(c)&0x7f]&X_) 90 1.1 jtc #define is_undoable(c) (!(classify[(c)&0x7f]&U_)) 91 1.1 jtc #define is_srch(c) (classify[(c)&0x7f]&S_) 92 1.1 jtc #define is_zerocount(c) (classify[(c)&0x7f]&Z_) 93 1.1 jtc 94 1.1 jtc const unsigned char classify[128] = { 95 1.1 jtc /* 0 1 2 3 4 5 6 7 */ 96 1.1 jtc /* 0 ^@ ^A ^B ^C ^D ^E ^F ^G */ 97 1.1 jtc B_, 0, 0, 0, 0, C_|U_, C_|Z_, 0, 98 1.1 jtc /* 01 ^H ^I ^J ^K ^L ^M ^N ^O */ 99 1.1 jtc M_, C_|Z_, 0, 0, C_|U_, 0, C_, 0, 100 1.1 jtc /* 02 ^P ^Q ^R ^S ^T ^U ^V ^W */ 101 1.1 jtc C_, 0, C_|U_, 0, 0, 0, C_, 0, 102 1.1 jtc /* 03 ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */ 103 1.1 jtc C_, 0, 0, C_|Z_, 0, 0, 0, 0, 104 1.1 jtc /* 04 <space> ! " # $ % & ' */ 105 1.1 jtc M_, 0, 0, C_, M_, M_, 0, 0, 106 1.1 jtc /* 05 ( ) * + , - . / */ 107 1.1 jtc 0, 0, C_, C_, M_, C_, 0, C_|S_, 108 1.1 jtc /* 06 0 1 2 3 4 5 6 7 */ 109 1.1 jtc M_, 0, 0, 0, 0, 0, 0, 0, 110 1.1 jtc /* 07 8 9 : ; < = > ? */ 111 1.1 jtc 0, 0, 0, M_, 0, C_, 0, C_|S_, 112 1.1 jtc /* 010 @ A B C D E F G */ 113 1.1 jtc C_|X_, C_, M_, C_, C_, M_, M_|X_, C_|U_|Z_, 114 1.1 jtc /* 011 H I J K L M N O */ 115 1.1 jtc 0, C_, 0, 0, 0, 0, C_|U_, 0, 116 1.1 jtc /* 012 P Q R S T U V W */ 117 1.1 jtc C_, 0, C_, C_, M_|X_, C_, 0, M_, 118 1.1 jtc /* 013 X Y Z [ \ ] ^ _ */ 119 1.1 jtc C_, C_|U_, 0, 0, C_|Z_, 0, M_, C_|Z_, 120 1.1 jtc /* 014 ` a b c d e f g */ 121 1.1 jtc 0, C_, M_, E_, E_, M_, M_|X_, C_|Z_, 122 1.1 jtc /* 015 h i j k l m n o */ 123 1.1 jtc M_, C_, C_|U_, C_|U_, M_, 0, C_|U_, 0, 124 1.1 jtc /* 016 p q r s t u v w */ 125 1.1 jtc C_, 0, X_, C_, M_|X_, C_|U_, C_|U_|Z_,M_, 126 1.1 jtc /* 017 x y z { | } ~ ^? */ 127 1.1 jtc C_, E_|U_, 0, 0, M_|Z_, 0, C_, 0 128 1.1 jtc }; 129 1.1 jtc 130 1.1 jtc #define MAXVICMD 3 131 1.1 jtc #define SRCHLEN 40 132 1.1 jtc 133 1.1 jtc #define INSERT 1 134 1.1 jtc #define REPLACE 2 135 1.1 jtc 136 1.1 jtc #define VNORMAL 0 /* command, insert or replace mode */ 137 1.1 jtc #define VARG1 1 /* digit prefix (first, eg, 5l) */ 138 1.1 jtc #define VEXTCMD 2 /* cmd + movement (eg, cl) */ 139 1.1 jtc #define VARG2 3 /* digit prefix (second, eg, 2c3l) */ 140 1.1 jtc #define VXCH 4 /* f, F, t, T, @ */ 141 1.1 jtc #define VFAIL 5 /* bad command */ 142 1.1 jtc #define VCMD 6 /* single char command (eg, X) */ 143 1.1 jtc #define VREDO 7 /* . */ 144 1.1 jtc #define VLIT 8 /* ^V */ 145 1.1 jtc #define VSEARCH 9 /* /, ? */ 146 1.1 jtc #define VVERSION 10 /* <ESC> ^V */ 147 1.1 jtc 148 1.1 jtc static char undocbuf[CMDLEN]; 149 1.1 jtc 150 1.1 jtc static struct edstate *save_edstate ARGS((struct edstate *old)); 151 1.1 jtc static void restore_edstate ARGS((struct edstate *old, struct edstate *new)); 152 1.1 jtc static void free_edstate ARGS((struct edstate *old)); 153 1.1 jtc 154 1.1 jtc static struct edstate ebuf; 155 1.1 jtc static struct edstate undobuf = { 0, undocbuf, CMDLEN, 0, 0 }; 156 1.1 jtc 157 1.1 jtc static struct edstate *es; /* current editor state */ 158 1.1 jtc static struct edstate *undo; 159 1.1 jtc 160 1.1 jtc static char ibuf[CMDLEN]; /* input buffer */ 161 1.1 jtc static int first_insert; /* set when starting in insert mode */ 162 1.1 jtc static int saved_inslen; /* saved inslen for first insert */ 163 1.1 jtc static int inslen; /* length of input buffer */ 164 1.1 jtc static int srchlen; /* length of current search pattern */ 165 1.1 jtc static char ybuf[CMDLEN]; /* yank buffer */ 166 1.1 jtc static int yanklen; /* length of yank buffer */ 167 1.1 jtc static int fsavecmd = ' '; /* last find command */ 168 1.1 jtc static int fsavech; /* character to find */ 169 1.1 jtc static char lastcmd[MAXVICMD]; /* last non-move command */ 170 1.1 jtc static int lastac; /* argcnt for lastcmd */ 171 1.1 jtc static int lastsearch = ' '; /* last search command */ 172 1.1 jtc static char srchpat[SRCHLEN]; /* last search pattern */ 173 1.1 jtc static int insert; /* non-zero in insert mode */ 174 1.1 jtc static int hnum; /* position in history */ 175 1.1 jtc static int ohnum; /* history line copied (after mod) */ 176 1.1 jtc static int hlast; /* 1 past last position in history */ 177 1.1 jtc static int modified; /* buffer has been "modified" */ 178 1.1 jtc static int state; 179 1.1 jtc 180 1.1 jtc /* Information for keeping track of macros that are being expanded. 181 1.1 jtc * The format of buf is the alias contents followed by a null byte followed 182 1.1 jtc * by the name (letter) of the alias. The end of the buffer is marked by 183 1.1 jtc * a double null. The name of the alias is stored so recursive macros can 184 1.1 jtc * be detected. 185 1.1 jtc */ 186 1.1 jtc struct macro_state { 187 1.1 jtc unsigned char *p; /* current position in buf */ 188 1.1 jtc unsigned char *buf; /* pointer to macro(s) being expanded */ 189 1.1 jtc int len; /* how much data in buffer */ 190 1.1 jtc }; 191 1.1 jtc static struct macro_state macro; 192 1.1 jtc 193 1.1 jtc enum expand_mode { NONE, EXPAND, COMPLETE, PRINT }; 194 1.1 jtc static enum expand_mode expanded = NONE;/* last input was expanded */ 195 1.1 jtc 196 1.1 jtc int 197 1.1 jtc x_vi(buf, len) 198 1.1 jtc char *buf; 199 1.1 jtc size_t len; 200 1.1 jtc { 201 1.1 jtc int c; 202 1.1 jtc 203 1.1 jtc vi_reset(buf, len > CMDLEN ? CMDLEN : len); 204 1.1 jtc vi_pprompt(1); 205 1.1 jtc x_flush(); 206 1.1 jtc while (1) { 207 1.1 jtc if (macro.p) { 208 1.1 jtc c = *macro.p++; 209 1.1 jtc /* end of current macro? */ 210 1.1 jtc if (!c) { 211 1.1 jtc /* more macros left to finish? */ 212 1.1 jtc if (*macro.p++) 213 1.1 jtc continue; 214 1.1 jtc /* must be the end of all the macros */ 215 1.1 jtc vi_macro_reset(); 216 1.1 jtc c = x_getc(); 217 1.1 jtc } 218 1.4 hubertf } else { 219 1.1 jtc c = x_getc(); 220 1.4 hubertf } 221 1.1 jtc if (c == -1) 222 1.1 jtc break; 223 1.1 jtc if (state != VLIT) { 224 1.1 jtc if (c == edchars.intr || c == edchars.quit) { 225 1.1 jtc /* pretend we got an interrupt */ 226 1.1 jtc x_vi_zotc(c); 227 1.1 jtc x_flush(); 228 1.1 jtc trapsig(c == edchars.intr ? SIGINT : SIGQUIT); 229 1.18 kamil x_mode(false); 230 1.1 jtc unwind(LSHELL); 231 1.1 jtc } else if (c == edchars.eof && state != VVERSION) { 232 1.1 jtc if (es->linelen == 0) { 233 1.1 jtc x_vi_zotc(edchars.eof); 234 1.1 jtc c = -1; 235 1.1 jtc break; 236 1.1 jtc } 237 1.1 jtc continue; 238 1.1 jtc } 239 1.1 jtc } 240 1.1 jtc if (vi_hook(c)) 241 1.1 jtc break; 242 1.1 jtc x_flush(); 243 1.1 jtc } 244 1.1 jtc 245 1.1 jtc x_putc('\r'); x_putc('\n'); x_flush(); 246 1.1 jtc 247 1.11 lukem if (c == -1 || len <= (size_t)es->linelen) 248 1.1 jtc return -1; 249 1.1 jtc 250 1.1 jtc if (es->cbuf != buf) 251 1.1 jtc memmove(buf, es->cbuf, es->linelen); 252 1.1 jtc 253 1.1 jtc buf[es->linelen++] = '\n'; 254 1.1 jtc 255 1.1 jtc return es->linelen; 256 1.1 jtc } 257 1.1 jtc 258 1.1 jtc static int 259 1.1 jtc vi_hook(ch) 260 1.1 jtc int ch; 261 1.1 jtc { 262 1.1 jtc static char curcmd[MAXVICMD]; 263 1.1 jtc static char locpat[SRCHLEN]; 264 1.1 jtc static int cmdlen; 265 1.1 jtc static int argc1, argc2; 266 1.1 jtc 267 1.1 jtc switch (state) { 268 1.1 jtc 269 1.1 jtc case VNORMAL: 270 1.1 jtc if (insert != 0) { 271 1.1 jtc if (ch == Ctrl('v')) { 272 1.1 jtc state = VLIT; 273 1.1 jtc ch = '^'; 274 1.1 jtc } 275 1.1 jtc switch (vi_insert(ch)) { 276 1.1 jtc case -1: 277 1.1 jtc vi_error(); 278 1.1 jtc state = VNORMAL; 279 1.1 jtc break; 280 1.1 jtc case 0: 281 1.1 jtc if (state == VLIT) { 282 1.1 jtc es->cursor--; 283 1.1 jtc refresh(0); 284 1.1 jtc } else 285 1.1 jtc refresh(insert != 0); 286 1.1 jtc break; 287 1.1 jtc case 1: 288 1.1 jtc return 1; 289 1.1 jtc } 290 1.1 jtc } else { 291 1.1 jtc if (ch == '\r' || ch == '\n') 292 1.1 jtc return 1; 293 1.1 jtc cmdlen = 0; 294 1.1 jtc argc1 = 0; 295 1.1 jtc if (ch >= '1' && ch <= '9') { 296 1.1 jtc argc1 = ch - '0'; 297 1.1 jtc state = VARG1; 298 1.1 jtc } else { 299 1.1 jtc curcmd[cmdlen++] = ch; 300 1.1 jtc state = nextstate(ch); 301 1.1 jtc if (state == VSEARCH) { 302 1.1 jtc save_cbuf(); 303 1.1 jtc es->cursor = 0; 304 1.1 jtc es->linelen = 0; 305 1.1 jtc if (ch == '/') { 306 1.1 jtc if (putbuf("/", 1, 0) != 0) { 307 1.1 jtc return -1; 308 1.1 jtc } 309 1.1 jtc } else if (putbuf("?", 1, 0) != 0) 310 1.1 jtc return -1; 311 1.1 jtc refresh(0); 312 1.1 jtc } 313 1.1 jtc if (state == VVERSION) { 314 1.1 jtc save_cbuf(); 315 1.1 jtc es->cursor = 0; 316 1.1 jtc es->linelen = 0; 317 1.1 jtc putbuf(ksh_version + 4, 318 1.1 jtc strlen(ksh_version + 4), 0); 319 1.1 jtc refresh(0); 320 1.1 jtc } 321 1.1 jtc } 322 1.1 jtc } 323 1.1 jtc break; 324 1.1 jtc 325 1.1 jtc case VLIT: 326 1.1 jtc if (is_bad(ch)) { 327 1.1 jtc del_range(es->cursor, es->cursor + 1); 328 1.1 jtc vi_error(); 329 1.1 jtc } else 330 1.1 jtc es->cbuf[es->cursor++] = ch; 331 1.1 jtc refresh(1); 332 1.1 jtc state = VNORMAL; 333 1.1 jtc break; 334 1.1 jtc 335 1.1 jtc case VVERSION: 336 1.1 jtc restore_cbuf(); 337 1.1 jtc state = VNORMAL; 338 1.1 jtc refresh(0); 339 1.1 jtc break; 340 1.1 jtc 341 1.1 jtc case VARG1: 342 1.1 jtc if (isdigit(ch)) 343 1.1 jtc argc1 = argc1 * 10 + ch - '0'; 344 1.1 jtc else { 345 1.1 jtc curcmd[cmdlen++] = ch; 346 1.1 jtc state = nextstate(ch); 347 1.1 jtc } 348 1.1 jtc break; 349 1.1 jtc 350 1.1 jtc case VEXTCMD: 351 1.1 jtc argc2 = 0; 352 1.1 jtc if (ch >= '1' && ch <= '9') { 353 1.1 jtc argc2 = ch - '0'; 354 1.1 jtc state = VARG2; 355 1.1 jtc return 0; 356 1.1 jtc } else { 357 1.1 jtc curcmd[cmdlen++] = ch; 358 1.1 jtc if (ch == curcmd[0]) 359 1.1 jtc state = VCMD; 360 1.1 jtc else if (is_move(ch)) 361 1.1 jtc state = nextstate(ch); 362 1.1 jtc else 363 1.1 jtc state = VFAIL; 364 1.1 jtc } 365 1.1 jtc break; 366 1.1 jtc 367 1.1 jtc case VARG2: 368 1.1 jtc if (isdigit(ch)) 369 1.1 jtc argc2 = argc2 * 10 + ch - '0'; 370 1.1 jtc else { 371 1.1 jtc if (argc1 == 0) 372 1.1 jtc argc1 = argc2; 373 1.1 jtc else 374 1.1 jtc argc1 *= argc2; 375 1.1 jtc curcmd[cmdlen++] = ch; 376 1.1 jtc if (ch == curcmd[0]) 377 1.1 jtc state = VCMD; 378 1.1 jtc else if (is_move(ch)) 379 1.1 jtc state = nextstate(ch); 380 1.1 jtc else 381 1.1 jtc state = VFAIL; 382 1.1 jtc } 383 1.1 jtc break; 384 1.1 jtc 385 1.1 jtc case VXCH: 386 1.1 jtc if (ch == Ctrl('[')) 387 1.1 jtc state = VNORMAL; 388 1.1 jtc else { 389 1.1 jtc curcmd[cmdlen++] = ch; 390 1.1 jtc state = VCMD; 391 1.1 jtc } 392 1.1 jtc break; 393 1.1 jtc 394 1.1 jtc case VSEARCH: 395 1.1 jtc if (ch == '\r' || ch == '\n' /*|| ch == Ctrl('[')*/ ) { 396 1.1 jtc restore_cbuf(); 397 1.1 jtc /* Repeat last search? */ 398 1.1 jtc if (srchlen == 0) { 399 1.1 jtc if (!srchpat[0]) { 400 1.1 jtc vi_error(); 401 1.1 jtc state = VNORMAL; 402 1.1 jtc refresh(0); 403 1.1 jtc return 0; 404 1.1 jtc } 405 1.1 jtc } else { 406 1.1 jtc locpat[srchlen] = '\0'; 407 1.8 mycroft (void) strlcpy(srchpat, locpat, sizeof srchpat); 408 1.1 jtc } 409 1.1 jtc state = VCMD; 410 1.1 jtc } else if (ch == edchars.erase || ch == Ctrl('h')) { 411 1.1 jtc if (srchlen != 0) { 412 1.1 jtc srchlen--; 413 1.1 jtc es->linelen -= char_len((unsigned char) locpat[srchlen]); 414 1.1 jtc es->cursor = es->linelen; 415 1.1 jtc refresh(0); 416 1.1 jtc return 0; 417 1.1 jtc } 418 1.1 jtc restore_cbuf(); 419 1.1 jtc state = VNORMAL; 420 1.1 jtc refresh(0); 421 1.1 jtc } else if (ch == edchars.kill) { 422 1.1 jtc srchlen = 0; 423 1.1 jtc es->linelen = 1; 424 1.1 jtc es->cursor = 1; 425 1.1 jtc refresh(0); 426 1.1 jtc return 0; 427 1.1 jtc } else if (ch == edchars.werase) { 428 1.1 jtc int i; 429 1.1 jtc int n = srchlen; 430 1.1 jtc 431 1.3 christos while (n > 0 && isspace((unsigned char)locpat[n - 1])) 432 1.1 jtc n--; 433 1.3 christos while (n > 0 && !isspace((unsigned char)locpat[n - 1])) 434 1.1 jtc n--; 435 1.1 jtc for (i = srchlen; --i >= n; ) 436 1.1 jtc es->linelen -= char_len((unsigned char) locpat[i]); 437 1.1 jtc srchlen = n; 438 1.1 jtc es->cursor = es->linelen; 439 1.1 jtc refresh(0); 440 1.1 jtc return 0; 441 1.1 jtc } else { 442 1.1 jtc if (srchlen == SRCHLEN - 1) 443 1.1 jtc vi_error(); 444 1.1 jtc else { 445 1.1 jtc locpat[srchlen++] = ch; 446 1.1 jtc if ((ch & 0x80) && Flag(FVISHOW8)) { 447 1.8 mycroft if (es->linelen + 2 > es->cbufsize) 448 1.8 mycroft vi_error(); 449 1.1 jtc es->cbuf[es->linelen++] = 'M'; 450 1.1 jtc es->cbuf[es->linelen++] = '-'; 451 1.1 jtc ch &= 0x7f; 452 1.1 jtc } 453 1.1 jtc if (ch < ' ' || ch == 0x7f) { 454 1.8 mycroft if (es->linelen + 2 > es->cbufsize) 455 1.8 mycroft vi_error(); 456 1.1 jtc es->cbuf[es->linelen++] = '^'; 457 1.1 jtc es->cbuf[es->linelen++] = ch ^ '@'; 458 1.8 mycroft } else { 459 1.8 mycroft if (es->linelen >= es->cbufsize) 460 1.8 mycroft vi_error(); 461 1.1 jtc es->cbuf[es->linelen++] = ch; 462 1.8 mycroft } 463 1.1 jtc es->cursor = es->linelen; 464 1.1 jtc refresh(0); 465 1.1 jtc } 466 1.1 jtc return 0; 467 1.1 jtc } 468 1.1 jtc break; 469 1.1 jtc } 470 1.1 jtc 471 1.1 jtc switch (state) { 472 1.1 jtc case VCMD: 473 1.1 jtc state = VNORMAL; 474 1.1 jtc switch (vi_cmd(argc1, curcmd)) { 475 1.1 jtc case -1: 476 1.1 jtc vi_error(); 477 1.1 jtc refresh(0); 478 1.1 jtc break; 479 1.1 jtc case 0: 480 1.1 jtc if (insert != 0) 481 1.1 jtc inslen = 0; 482 1.1 jtc refresh(insert != 0); 483 1.1 jtc break; 484 1.1 jtc case 1: 485 1.1 jtc refresh(0); 486 1.1 jtc return 1; 487 1.1 jtc case 2: 488 1.1 jtc /* back from a 'v' command - don't redraw the screen */ 489 1.1 jtc return 1; 490 1.1 jtc } 491 1.1 jtc break; 492 1.1 jtc 493 1.1 jtc case VREDO: 494 1.1 jtc state = VNORMAL; 495 1.1 jtc if (argc1 != 0) 496 1.1 jtc lastac = argc1; 497 1.4 hubertf switch (vi_cmd(lastac, lastcmd)) { 498 1.1 jtc case -1: 499 1.1 jtc vi_error(); 500 1.1 jtc refresh(0); 501 1.1 jtc break; 502 1.1 jtc case 0: 503 1.1 jtc if (insert != 0) { 504 1.1 jtc if (lastcmd[0] == 's' || lastcmd[0] == 'c' || 505 1.1 jtc lastcmd[0] == 'C') { 506 1.1 jtc if (redo_insert(1) != 0) 507 1.1 jtc vi_error(); 508 1.1 jtc } else { 509 1.1 jtc if (redo_insert(lastac) != 0) 510 1.1 jtc vi_error(); 511 1.1 jtc } 512 1.1 jtc } 513 1.1 jtc refresh(0); 514 1.1 jtc break; 515 1.1 jtc case 1: 516 1.1 jtc refresh(0); 517 1.1 jtc return 1; 518 1.1 jtc case 2: 519 1.4 hubertf /* back from a 'v' command - can't happen */ 520 1.4 hubertf break; 521 1.1 jtc } 522 1.1 jtc break; 523 1.1 jtc 524 1.1 jtc case VFAIL: 525 1.1 jtc state = VNORMAL; 526 1.1 jtc vi_error(); 527 1.1 jtc break; 528 1.1 jtc } 529 1.1 jtc return 0; 530 1.1 jtc } 531 1.1 jtc 532 1.1 jtc static void 533 1.1 jtc vi_reset(buf, len) 534 1.1 jtc char *buf; 535 1.1 jtc size_t len; 536 1.1 jtc { 537 1.1 jtc state = VNORMAL; 538 1.1 jtc ohnum = hnum = hlast = histnum(-1) + 1; 539 1.1 jtc insert = INSERT; 540 1.1 jtc saved_inslen = inslen; 541 1.1 jtc first_insert = 1; 542 1.1 jtc inslen = 0; 543 1.1 jtc modified = 1; 544 1.1 jtc vi_macro_reset(); 545 1.1 jtc edit_reset(buf, len); 546 1.1 jtc } 547 1.1 jtc 548 1.1 jtc static int 549 1.1 jtc nextstate(ch) 550 1.1 jtc int ch; 551 1.1 jtc { 552 1.1 jtc if (is_extend(ch)) 553 1.1 jtc return VEXTCMD; 554 1.1 jtc else if (is_srch(ch)) 555 1.1 jtc return VSEARCH; 556 1.1 jtc else if (is_long(ch)) 557 1.1 jtc return VXCH; 558 1.1 jtc else if (ch == '.') 559 1.1 jtc return VREDO; 560 1.1 jtc else if (ch == Ctrl('v')) 561 1.1 jtc return VVERSION; 562 1.1 jtc else if (is_cmd(ch)) 563 1.1 jtc return VCMD; 564 1.1 jtc else 565 1.1 jtc return VFAIL; 566 1.1 jtc } 567 1.1 jtc 568 1.1 jtc static int 569 1.1 jtc vi_insert(ch) 570 1.1 jtc int ch; 571 1.1 jtc { 572 1.1 jtc int tcursor; 573 1.1 jtc 574 1.1 jtc if (ch == edchars.erase || ch == Ctrl('h')) { 575 1.1 jtc if (insert == REPLACE) { 576 1.1 jtc if (es->cursor == undo->cursor) { 577 1.1 jtc vi_error(); 578 1.1 jtc return 0; 579 1.1 jtc } 580 1.1 jtc if (inslen > 0) 581 1.1 jtc inslen--; 582 1.1 jtc es->cursor--; 583 1.1 jtc if (es->cursor >= undo->linelen) 584 1.1 jtc es->linelen--; 585 1.1 jtc else 586 1.1 jtc es->cbuf[es->cursor] = undo->cbuf[es->cursor]; 587 1.1 jtc } else { 588 1.1 jtc if (es->cursor == 0) { 589 1.1 jtc /* x_putc(BEL); no annoying bell here */ 590 1.1 jtc return 0; 591 1.1 jtc } 592 1.1 jtc if (inslen > 0) 593 1.1 jtc inslen--; 594 1.1 jtc es->cursor--; 595 1.1 jtc es->linelen--; 596 1.1 jtc memmove(&es->cbuf[es->cursor], &es->cbuf[es->cursor+1], 597 1.1 jtc es->linelen - es->cursor + 1); 598 1.1 jtc } 599 1.1 jtc expanded = NONE; 600 1.1 jtc return 0; 601 1.1 jtc } 602 1.1 jtc if (ch == edchars.kill) { 603 1.1 jtc if (es->cursor != 0) { 604 1.1 jtc inslen = 0; 605 1.1 jtc memmove(es->cbuf, &es->cbuf[es->cursor], 606 1.1 jtc es->linelen - es->cursor); 607 1.1 jtc es->linelen -= es->cursor; 608 1.1 jtc es->cursor = 0; 609 1.1 jtc } 610 1.1 jtc expanded = NONE; 611 1.1 jtc return 0; 612 1.1 jtc } 613 1.1 jtc if (ch == edchars.werase) { 614 1.1 jtc if (es->cursor != 0) { 615 1.1 jtc tcursor = Backword(1); 616 1.1 jtc memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor], 617 1.1 jtc es->linelen - es->cursor); 618 1.1 jtc es->linelen -= es->cursor - tcursor; 619 1.1 jtc if (inslen < es->cursor - tcursor) 620 1.1 jtc inslen = 0; 621 1.1 jtc else 622 1.1 jtc inslen -= es->cursor - tcursor; 623 1.1 jtc es->cursor = tcursor; 624 1.1 jtc } 625 1.1 jtc expanded = NONE; 626 1.1 jtc return 0; 627 1.1 jtc } 628 1.1 jtc /* If any chars are entered before escape, trash the saved insert 629 1.1 jtc * buffer (if user inserts & deletes char, ibuf gets trashed and 630 1.1 jtc * we don't want to use it) 631 1.1 jtc */ 632 1.1 jtc if (first_insert && ch != Ctrl('[')) 633 1.1 jtc saved_inslen = 0; 634 1.1 jtc switch (ch) { 635 1.1 jtc 636 1.1 jtc case '\0': 637 1.1 jtc return -1; 638 1.1 jtc 639 1.1 jtc case '\r': 640 1.1 jtc case '\n': 641 1.1 jtc return 1; 642 1.1 jtc 643 1.1 jtc case Ctrl('['): 644 1.1 jtc expanded = NONE; 645 1.1 jtc if (first_insert) { 646 1.1 jtc first_insert = 0; 647 1.1 jtc if (inslen == 0) { 648 1.1 jtc inslen = saved_inslen; 649 1.1 jtc return redo_insert(0); 650 1.1 jtc } 651 1.1 jtc lastcmd[0] = 'a'; 652 1.1 jtc lastac = 1; 653 1.1 jtc } 654 1.1 jtc if (lastcmd[0] == 's' || lastcmd[0] == 'c' || 655 1.1 jtc lastcmd[0] == 'C') 656 1.1 jtc return redo_insert(0); 657 1.1 jtc else 658 1.1 jtc return redo_insert(lastac - 1); 659 1.1 jtc 660 1.1 jtc /* { Begin nonstandard vi commands */ 661 1.1 jtc case Ctrl('x'): 662 1.1 jtc expand_word(0); 663 1.1 jtc break; 664 1.1 jtc 665 1.1 jtc case Ctrl('f'): 666 1.1 jtc complete_word(0, 0); 667 1.1 jtc break; 668 1.1 jtc 669 1.1 jtc case Ctrl('e'): 670 1.1 jtc print_expansions(es, 0); 671 1.1 jtc break; 672 1.1 jtc 673 1.1 jtc case Ctrl('i'): 674 1.1 jtc if (Flag(FVITABCOMPLETE)) { 675 1.1 jtc complete_word(0, 0); 676 1.1 jtc break; 677 1.1 jtc } 678 1.1 jtc /* FALLTHROUGH */ 679 1.1 jtc /* End nonstandard vi commands } */ 680 1.1 jtc 681 1.1 jtc default: 682 1.8 mycroft if (es->linelen >= es->cbufsize - 1) 683 1.1 jtc return -1; 684 1.1 jtc ibuf[inslen++] = ch; 685 1.1 jtc if (insert == INSERT) { 686 1.1 jtc memmove(&es->cbuf[es->cursor+1], &es->cbuf[es->cursor], 687 1.1 jtc es->linelen - es->cursor); 688 1.1 jtc es->linelen++; 689 1.1 jtc } 690 1.1 jtc es->cbuf[es->cursor++] = ch; 691 1.1 jtc if (insert == REPLACE && es->cursor > es->linelen) 692 1.1 jtc es->linelen++; 693 1.1 jtc expanded = NONE; 694 1.1 jtc } 695 1.1 jtc return 0; 696 1.1 jtc } 697 1.1 jtc 698 1.1 jtc static int 699 1.1 jtc vi_cmd(argcnt, cmd) 700 1.1 jtc int argcnt; 701 1.1 jtc const char *cmd; 702 1.1 jtc { 703 1.1 jtc int ncursor; 704 1.1 jtc int cur, c1, c2, c3 = 0; 705 1.1 jtc int any; 706 1.1 jtc struct edstate *t; 707 1.1 jtc 708 1.1 jtc if (argcnt == 0 && !is_zerocount(*cmd)) 709 1.1 jtc argcnt = 1; 710 1.1 jtc 711 1.1 jtc if (is_move(*cmd)) { 712 1.1 jtc if ((cur = domove(argcnt, cmd, 0)) >= 0) { 713 1.1 jtc if (cur == es->linelen && cur != 0) 714 1.1 jtc cur--; 715 1.1 jtc es->cursor = cur; 716 1.1 jtc } else 717 1.1 jtc return -1; 718 1.1 jtc } else { 719 1.1 jtc /* Don't save state in middle of macro.. */ 720 1.1 jtc if (is_undoable(*cmd) && !macro.p) { 721 1.1 jtc undo->winleft = es->winleft; 722 1.1 jtc memmove(undo->cbuf, es->cbuf, es->linelen); 723 1.1 jtc undo->linelen = es->linelen; 724 1.1 jtc undo->cursor = es->cursor; 725 1.1 jtc lastac = argcnt; 726 1.1 jtc memmove(lastcmd, cmd, MAXVICMD); 727 1.1 jtc } 728 1.1 jtc switch (*cmd) { 729 1.1 jtc 730 1.1 jtc case Ctrl('l'): 731 1.1 jtc case Ctrl('r'): 732 1.1 jtc redraw_line(1); 733 1.1 jtc break; 734 1.1 jtc 735 1.1 jtc case '@': 736 1.1 jtc { 737 1.1 jtc static char alias[] = "_\0"; 738 1.1 jtc struct tbl *ap; 739 1.1 jtc int olen, nlen; 740 1.1 jtc char *p, *nbuf; 741 1.1 jtc 742 1.1 jtc /* lookup letter in alias list... */ 743 1.1 jtc alias[1] = cmd[1]; 744 1.19 kamil ap = mytsearch(&aliases, alias, hash(alias)); 745 1.1 jtc if (!cmd[1] || !ap || !(ap->flag & ISSET)) 746 1.1 jtc return -1; 747 1.1 jtc /* check if this is a recursive call... */ 748 1.1 jtc if ((p = (char *) macro.p)) 749 1.1 jtc while ((p = strchr(p, '\0')) && p[1]) 750 1.1 jtc if (*++p == cmd[1]) 751 1.1 jtc return -1; 752 1.1 jtc /* insert alias into macro buffer */ 753 1.1 jtc nlen = strlen(ap->val.s) + 1; 754 1.1 jtc olen = !macro.p ? 2 755 1.1 jtc : macro.len - (macro.p - macro.buf); 756 1.1 jtc nbuf = alloc(nlen + 1 + olen, APERM); 757 1.1 jtc memcpy(nbuf, ap->val.s, nlen); 758 1.1 jtc nbuf[nlen++] = cmd[1]; 759 1.1 jtc if (macro.p) { 760 1.1 jtc memcpy(nbuf + nlen, macro.p, olen); 761 1.1 jtc afree(macro.buf, APERM); 762 1.1 jtc nlen += olen; 763 1.1 jtc } else { 764 1.1 jtc nbuf[nlen++] = '\0'; 765 1.1 jtc nbuf[nlen++] = '\0'; 766 1.1 jtc } 767 1.1 jtc macro.p = macro.buf = (unsigned char *) nbuf; 768 1.1 jtc macro.len = nlen; 769 1.1 jtc } 770 1.1 jtc break; 771 1.1 jtc 772 1.1 jtc case 'a': 773 1.1 jtc modified = 1; hnum = hlast; 774 1.1 jtc if (es->linelen != 0) 775 1.1 jtc es->cursor++; 776 1.1 jtc insert = INSERT; 777 1.1 jtc break; 778 1.1 jtc 779 1.1 jtc case 'A': 780 1.1 jtc modified = 1; hnum = hlast; 781 1.1 jtc del_range(0, 0); 782 1.1 jtc es->cursor = es->linelen; 783 1.1 jtc insert = INSERT; 784 1.1 jtc break; 785 1.1 jtc 786 1.1 jtc case 'S': 787 1.1 jtc es->cursor = domove(1, "^", 1); 788 1.1 jtc del_range(es->cursor, es->linelen); 789 1.1 jtc modified = 1; hnum = hlast; 790 1.1 jtc insert = INSERT; 791 1.1 jtc break; 792 1.1 jtc 793 1.1 jtc case 'Y': 794 1.1 jtc cmd = "y$"; 795 1.1 jtc /* ahhhhhh... */ 796 1.21 christos /*FALLTHROUGH*/ 797 1.1 jtc case 'c': 798 1.1 jtc case 'd': 799 1.1 jtc case 'y': 800 1.1 jtc if (*cmd == cmd[1]) { 801 1.1 jtc c1 = *cmd == 'c' ? domove(1, "^", 1) : 0; 802 1.1 jtc c2 = es->linelen; 803 1.1 jtc } else if (!is_move(cmd[1])) 804 1.1 jtc return -1; 805 1.1 jtc else { 806 1.1 jtc if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0) 807 1.1 jtc return -1; 808 1.1 jtc if (*cmd == 'c' && 809 1.1 jtc (cmd[1]=='w' || cmd[1]=='W') && 810 1.3 christos !isspace((unsigned char)es->cbuf[es->cursor])) { 811 1.3 christos while (isspace((unsigned char)es->cbuf[--ncursor])) 812 1.13 christos continue; 813 1.1 jtc ncursor++; 814 1.1 jtc } 815 1.1 jtc if (ncursor > es->cursor) { 816 1.1 jtc c1 = es->cursor; 817 1.1 jtc c2 = ncursor; 818 1.1 jtc } else { 819 1.1 jtc c1 = ncursor; 820 1.1 jtc c2 = es->cursor; 821 1.1 jtc if (cmd[1] == '%') 822 1.1 jtc c2++; 823 1.1 jtc } 824 1.1 jtc } 825 1.1 jtc if (*cmd != 'c' && c1 != c2) 826 1.1 jtc yank_range(c1, c2); 827 1.1 jtc if (*cmd != 'y') { 828 1.1 jtc del_range(c1, c2); 829 1.1 jtc es->cursor = c1; 830 1.1 jtc } 831 1.1 jtc if (*cmd == 'c') { 832 1.1 jtc modified = 1; hnum = hlast; 833 1.1 jtc insert = INSERT; 834 1.1 jtc } 835 1.1 jtc break; 836 1.1 jtc 837 1.1 jtc case 'p': 838 1.1 jtc modified = 1; hnum = hlast; 839 1.1 jtc if (es->linelen != 0) 840 1.1 jtc es->cursor++; 841 1.1 jtc while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0) 842 1.13 christos continue; 843 1.1 jtc if (es->cursor != 0) 844 1.1 jtc es->cursor--; 845 1.1 jtc if (argcnt != 0) 846 1.1 jtc return -1; 847 1.1 jtc break; 848 1.1 jtc 849 1.1 jtc case 'P': 850 1.1 jtc modified = 1; hnum = hlast; 851 1.1 jtc any = 0; 852 1.1 jtc while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0) 853 1.1 jtc any = 1; 854 1.1 jtc if (any && es->cursor != 0) 855 1.1 jtc es->cursor--; 856 1.1 jtc if (argcnt != 0) 857 1.1 jtc return -1; 858 1.1 jtc break; 859 1.1 jtc 860 1.1 jtc case 'C': 861 1.1 jtc modified = 1; hnum = hlast; 862 1.1 jtc del_range(es->cursor, es->linelen); 863 1.1 jtc insert = INSERT; 864 1.1 jtc break; 865 1.1 jtc 866 1.1 jtc case 'D': 867 1.1 jtc yank_range(es->cursor, es->linelen); 868 1.1 jtc del_range(es->cursor, es->linelen); 869 1.1 jtc if (es->cursor != 0) 870 1.1 jtc es->cursor--; 871 1.1 jtc break; 872 1.1 jtc 873 1.1 jtc case 'g': 874 1.1 jtc if (!argcnt) 875 1.1 jtc argcnt = hlast + 1; 876 1.1 jtc /* fall through */ 877 1.1 jtc case 'G': 878 1.1 jtc if (!argcnt) 879 1.1 jtc argcnt = 1; 880 1.1 jtc else 881 1.1 jtc argcnt = hlast - (source->line - argcnt); 882 1.1 jtc if (grabhist(modified, argcnt - 1) < 0) 883 1.1 jtc return -1; 884 1.1 jtc else { 885 1.1 jtc modified = 0; 886 1.1 jtc hnum = argcnt - 1; 887 1.1 jtc } 888 1.1 jtc break; 889 1.1 jtc 890 1.1 jtc case 'i': 891 1.1 jtc modified = 1; hnum = hlast; 892 1.1 jtc insert = INSERT; 893 1.1 jtc break; 894 1.1 jtc 895 1.1 jtc case 'I': 896 1.1 jtc modified = 1; hnum = hlast; 897 1.1 jtc es->cursor = domove(1, "^", 1); 898 1.1 jtc insert = INSERT; 899 1.1 jtc break; 900 1.1 jtc 901 1.1 jtc case 'j': 902 1.1 jtc case '+': 903 1.1 jtc case Ctrl('n'): 904 1.1 jtc if (grabhist(modified, hnum + argcnt) < 0) 905 1.1 jtc return -1; 906 1.1 jtc else { 907 1.1 jtc modified = 0; 908 1.1 jtc hnum += argcnt; 909 1.1 jtc } 910 1.1 jtc break; 911 1.1 jtc 912 1.1 jtc case 'k': 913 1.1 jtc case '-': 914 1.1 jtc case Ctrl('p'): 915 1.1 jtc if (grabhist(modified, hnum - argcnt) < 0) 916 1.1 jtc return -1; 917 1.1 jtc else { 918 1.1 jtc modified = 0; 919 1.1 jtc hnum -= argcnt; 920 1.1 jtc } 921 1.1 jtc break; 922 1.1 jtc 923 1.1 jtc case 'r': 924 1.1 jtc if (es->linelen == 0) 925 1.1 jtc return -1; 926 1.1 jtc modified = 1; hnum = hlast; 927 1.1 jtc if (cmd[1] == 0) 928 1.1 jtc vi_error(); 929 1.1 jtc else 930 1.1 jtc es->cbuf[es->cursor] = cmd[1]; 931 1.1 jtc break; 932 1.1 jtc 933 1.1 jtc case 'R': 934 1.1 jtc modified = 1; hnum = hlast; 935 1.1 jtc insert = REPLACE; 936 1.1 jtc break; 937 1.1 jtc 938 1.1 jtc case 's': 939 1.1 jtc if (es->linelen == 0) 940 1.1 jtc return -1; 941 1.1 jtc modified = 1; hnum = hlast; 942 1.1 jtc if (es->cursor + argcnt > es->linelen) 943 1.1 jtc argcnt = es->linelen - es->cursor; 944 1.1 jtc del_range(es->cursor, es->cursor + argcnt); 945 1.1 jtc insert = INSERT; 946 1.1 jtc break; 947 1.1 jtc 948 1.1 jtc case 'v': 949 1.1 jtc if (es->linelen == 0) 950 1.1 jtc return -1; 951 1.1 jtc if (!argcnt) { 952 1.1 jtc if (modified) { 953 1.1 jtc es->cbuf[es->linelen] = '\0'; 954 1.1 jtc source->line++; 955 1.1 jtc histsave(source->line, es->cbuf, 1); 956 1.1 jtc } else 957 1.1 jtc argcnt = source->line + 1 958 1.1 jtc - (hlast - hnum); 959 1.1 jtc } 960 1.1 jtc shf_snprintf(es->cbuf, es->cbufsize, 961 1.1 jtc argcnt ? "%s %d" : "%s", 962 1.1 jtc "fc -e ${VISUAL:-${EDITOR:-vi}} --", 963 1.1 jtc argcnt); 964 1.1 jtc es->linelen = strlen(es->cbuf); 965 1.1 jtc return 2; 966 1.1 jtc 967 1.1 jtc case 'x': 968 1.1 jtc if (es->linelen == 0) 969 1.1 jtc return -1; 970 1.1 jtc modified = 1; hnum = hlast; 971 1.1 jtc if (es->cursor + argcnt > es->linelen) 972 1.1 jtc argcnt = es->linelen - es->cursor; 973 1.1 jtc yank_range(es->cursor, es->cursor + argcnt); 974 1.1 jtc del_range(es->cursor, es->cursor + argcnt); 975 1.1 jtc break; 976 1.1 jtc 977 1.1 jtc case 'X': 978 1.1 jtc if (es->cursor > 0) { 979 1.1 jtc modified = 1; hnum = hlast; 980 1.1 jtc if (es->cursor < argcnt) 981 1.1 jtc argcnt = es->cursor; 982 1.1 jtc yank_range(es->cursor - argcnt, es->cursor); 983 1.1 jtc del_range(es->cursor - argcnt, es->cursor); 984 1.1 jtc es->cursor -= argcnt; 985 1.1 jtc } else 986 1.1 jtc return -1; 987 1.1 jtc break; 988 1.1 jtc 989 1.1 jtc case 'u': 990 1.1 jtc t = es; 991 1.1 jtc es = undo; 992 1.1 jtc undo = t; 993 1.1 jtc break; 994 1.1 jtc 995 1.1 jtc case 'U': 996 1.1 jtc if (!modified) 997 1.1 jtc return -1; 998 1.1 jtc if (grabhist(modified, ohnum) < 0) 999 1.1 jtc return -1; 1000 1.1 jtc modified = 0; 1001 1.1 jtc hnum = ohnum; 1002 1.1 jtc break; 1003 1.1 jtc 1004 1.1 jtc case '?': 1005 1.1 jtc if (hnum == hlast) 1006 1.1 jtc hnum = -1; 1007 1.1 jtc /* ahhh */ 1008 1.21 christos /*FALLTHROUGH*/ 1009 1.1 jtc case '/': 1010 1.1 jtc c3 = 1; 1011 1.1 jtc srchlen = 0; 1012 1.1 jtc lastsearch = *cmd; 1013 1.1 jtc /* fall through */ 1014 1.1 jtc case 'n': 1015 1.1 jtc case 'N': 1016 1.1 jtc if (lastsearch == ' ') 1017 1.1 jtc return -1; 1018 1.1 jtc if (lastsearch == '?') 1019 1.1 jtc c1 = 1; 1020 1.1 jtc else 1021 1.1 jtc c1 = 0; 1022 1.1 jtc if (*cmd == 'N') 1023 1.1 jtc c1 = !c1; 1024 1.1 jtc if ((c2 = grabsearch(modified, hnum, 1025 1.1 jtc c1, srchpat)) < 0) { 1026 1.1 jtc if (c3) { 1027 1.1 jtc restore_cbuf(); 1028 1.1 jtc refresh(0); 1029 1.1 jtc } 1030 1.1 jtc return -1; 1031 1.1 jtc } else { 1032 1.1 jtc modified = 0; 1033 1.1 jtc hnum = c2; 1034 1.1 jtc ohnum = hnum; 1035 1.1 jtc } 1036 1.1 jtc break; 1037 1.1 jtc case '_': { 1038 1.1 jtc int inspace; 1039 1.1 jtc char *p, *sp; 1040 1.1 jtc 1041 1.1 jtc if (histnum(-1) < 0) 1042 1.1 jtc return -1; 1043 1.1 jtc p = *histpos(); 1044 1.3 christos #define issp(c) (isspace((unsigned char)(c)) || (c) == '\n') 1045 1.1 jtc if (argcnt) { 1046 1.1 jtc while (*p && issp(*p)) 1047 1.1 jtc p++; 1048 1.1 jtc while (*p && --argcnt) { 1049 1.1 jtc while (*p && !issp(*p)) 1050 1.1 jtc p++; 1051 1.1 jtc while (*p && issp(*p)) 1052 1.1 jtc p++; 1053 1.1 jtc } 1054 1.1 jtc if (!*p) 1055 1.1 jtc return -1; 1056 1.1 jtc sp = p; 1057 1.1 jtc } else { 1058 1.1 jtc sp = p; 1059 1.1 jtc inspace = 0; 1060 1.1 jtc while (*p) { 1061 1.1 jtc if (issp(*p)) 1062 1.1 jtc inspace = 1; 1063 1.1 jtc else if (inspace) { 1064 1.1 jtc inspace = 0; 1065 1.1 jtc sp = p; 1066 1.1 jtc } 1067 1.1 jtc p++; 1068 1.1 jtc } 1069 1.1 jtc p = sp; 1070 1.1 jtc } 1071 1.1 jtc modified = 1; hnum = hlast; 1072 1.1 jtc if (es->cursor != es->linelen) 1073 1.1 jtc es->cursor++; 1074 1.1 jtc while (*p && !issp(*p)) { 1075 1.1 jtc argcnt++; 1076 1.1 jtc p++; 1077 1.1 jtc } 1078 1.1 jtc if (putbuf(space, 1, 0) != 0) 1079 1.1 jtc argcnt = -1; 1080 1.1 jtc else if (putbuf(sp, argcnt, 0) != 0) 1081 1.1 jtc argcnt = -1; 1082 1.1 jtc if (argcnt < 0) { 1083 1.1 jtc if (es->cursor != 0) 1084 1.1 jtc es->cursor--; 1085 1.1 jtc return -1; 1086 1.1 jtc } 1087 1.1 jtc insert = INSERT; 1088 1.1 jtc } 1089 1.1 jtc break; 1090 1.1 jtc 1091 1.1 jtc case '~': { 1092 1.1 jtc char *p; 1093 1.1 jtc int i; 1094 1.1 jtc 1095 1.1 jtc if (es->linelen == 0) 1096 1.1 jtc return -1; 1097 1.1 jtc for (i = 0; i < argcnt; i++) { 1098 1.1 jtc p = &es->cbuf[es->cursor]; 1099 1.3 christos if (islower((unsigned char)*p)) { 1100 1.1 jtc modified = 1; hnum = hlast; 1101 1.9 dsl *p = toupper((unsigned char)*p); 1102 1.3 christos } else if (isupper((unsigned char)*p)) { 1103 1.1 jtc modified = 1; hnum = hlast; 1104 1.9 dsl *p = tolower((unsigned char)*p); 1105 1.1 jtc } 1106 1.1 jtc if (es->cursor < es->linelen - 1) 1107 1.1 jtc es->cursor++; 1108 1.1 jtc } 1109 1.1 jtc break; 1110 1.1 jtc } 1111 1.1 jtc 1112 1.1 jtc case '#': 1113 1.1 jtc { 1114 1.1 jtc int ret = x_do_comment(es->cbuf, es->cbufsize, 1115 1.1 jtc &es->linelen); 1116 1.1 jtc if (ret >= 0) 1117 1.1 jtc es->cursor = 0; 1118 1.1 jtc return ret; 1119 1.1 jtc } 1120 1.1 jtc 1121 1.1 jtc case '=': /* at&t ksh */ 1122 1.1 jtc case Ctrl('e'): /* Nonstandard vi/ksh */ 1123 1.1 jtc print_expansions(es, 1); 1124 1.1 jtc break; 1125 1.1 jtc 1126 1.1 jtc 1127 1.1 jtc case Ctrl('i'): /* Nonstandard vi/ksh */ 1128 1.1 jtc if (!Flag(FVITABCOMPLETE)) 1129 1.1 jtc return -1; 1130 1.2 tls complete_word(1, argcnt); 1131 1.2 tls break; 1132 1.1 jtc 1133 1.1 jtc case Ctrl('['): /* some annoying at&t ksh's */ 1134 1.1 jtc if (!Flag(FVIESCCOMPLETE)) 1135 1.1 jtc return -1; 1136 1.21 christos /*FALLTHROUGH*/ 1137 1.1 jtc case '\\': /* at&t ksh */ 1138 1.1 jtc case Ctrl('f'): /* Nonstandard vi/ksh */ 1139 1.1 jtc complete_word(1, argcnt); 1140 1.1 jtc break; 1141 1.1 jtc 1142 1.1 jtc 1143 1.1 jtc case '*': /* at&t ksh */ 1144 1.1 jtc case Ctrl('x'): /* Nonstandard vi/ksh */ 1145 1.1 jtc expand_word(1); 1146 1.1 jtc break; 1147 1.1 jtc } 1148 1.1 jtc if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen) 1149 1.1 jtc es->cursor--; 1150 1.1 jtc } 1151 1.1 jtc return 0; 1152 1.1 jtc } 1153 1.1 jtc 1154 1.1 jtc static int 1155 1.1 jtc domove(argcnt, cmd, sub) 1156 1.1 jtc int argcnt; 1157 1.1 jtc const char *cmd; 1158 1.1 jtc int sub; 1159 1.1 jtc { 1160 1.1 jtc int bcount, UNINITIALIZED(i), t; 1161 1.1 jtc int UNINITIALIZED(ncursor); 1162 1.1 jtc 1163 1.1 jtc switch (*cmd) { 1164 1.1 jtc 1165 1.1 jtc case 'b': 1166 1.1 jtc if (!sub && es->cursor == 0) 1167 1.1 jtc return -1; 1168 1.1 jtc ncursor = backword(argcnt); 1169 1.1 jtc break; 1170 1.1 jtc 1171 1.1 jtc case 'B': 1172 1.1 jtc if (!sub && es->cursor == 0) 1173 1.1 jtc return -1; 1174 1.1 jtc ncursor = Backword(argcnt); 1175 1.1 jtc break; 1176 1.1 jtc 1177 1.1 jtc case 'e': 1178 1.1 jtc if (!sub && es->cursor + 1 >= es->linelen) 1179 1.1 jtc return -1; 1180 1.1 jtc ncursor = endword(argcnt); 1181 1.1 jtc if (sub && ncursor < es->linelen) 1182 1.1 jtc ncursor++; 1183 1.1 jtc break; 1184 1.1 jtc 1185 1.1 jtc case 'E': 1186 1.1 jtc if (!sub && es->cursor + 1 >= es->linelen) 1187 1.1 jtc return -1; 1188 1.1 jtc ncursor = Endword(argcnt); 1189 1.1 jtc if (sub && ncursor < es->linelen) 1190 1.1 jtc ncursor++; 1191 1.1 jtc break; 1192 1.1 jtc 1193 1.1 jtc case 'f': 1194 1.1 jtc case 'F': 1195 1.1 jtc case 't': 1196 1.1 jtc case 'T': 1197 1.1 jtc fsavecmd = *cmd; 1198 1.1 jtc fsavech = cmd[1]; 1199 1.1 jtc /* drop through */ 1200 1.21 christos /*FALLTHROUGH*/ 1201 1.1 jtc case ',': 1202 1.1 jtc case ';': 1203 1.1 jtc if (fsavecmd == ' ') 1204 1.1 jtc return -1; 1205 1.1 jtc i = fsavecmd == 'f' || fsavecmd == 'F'; 1206 1.1 jtc t = fsavecmd > 'a'; 1207 1.1 jtc if (*cmd == ',') 1208 1.1 jtc t = !t; 1209 1.1 jtc if ((ncursor = findch(fsavech, argcnt, t, i)) < 0) 1210 1.1 jtc return -1; 1211 1.1 jtc if (sub && t) 1212 1.1 jtc ncursor++; 1213 1.1 jtc break; 1214 1.1 jtc 1215 1.1 jtc case 'h': 1216 1.1 jtc case Ctrl('h'): 1217 1.1 jtc if (!sub && es->cursor == 0) 1218 1.1 jtc return -1; 1219 1.1 jtc ncursor = es->cursor - argcnt; 1220 1.1 jtc if (ncursor < 0) 1221 1.1 jtc ncursor = 0; 1222 1.1 jtc break; 1223 1.1 jtc 1224 1.1 jtc case ' ': 1225 1.1 jtc case 'l': 1226 1.1 jtc if (!sub && es->cursor + 1 >= es->linelen) 1227 1.1 jtc return -1; 1228 1.1 jtc if (es->linelen != 0) { 1229 1.1 jtc ncursor = es->cursor + argcnt; 1230 1.1 jtc if (ncursor > es->linelen) 1231 1.1 jtc ncursor = es->linelen; 1232 1.1 jtc } 1233 1.1 jtc break; 1234 1.1 jtc 1235 1.1 jtc case 'w': 1236 1.1 jtc if (!sub && es->cursor + 1 >= es->linelen) 1237 1.1 jtc return -1; 1238 1.1 jtc ncursor = forwword(argcnt); 1239 1.1 jtc break; 1240 1.1 jtc 1241 1.1 jtc case 'W': 1242 1.1 jtc if (!sub && es->cursor + 1 >= es->linelen) 1243 1.1 jtc return -1; 1244 1.1 jtc ncursor = Forwword(argcnt); 1245 1.1 jtc break; 1246 1.1 jtc 1247 1.1 jtc case '0': 1248 1.1 jtc ncursor = 0; 1249 1.1 jtc break; 1250 1.1 jtc 1251 1.1 jtc case '^': 1252 1.1 jtc ncursor = 0; 1253 1.3 christos while (ncursor < es->linelen - 1 && isspace((unsigned char)es->cbuf[ncursor])) 1254 1.1 jtc ncursor++; 1255 1.1 jtc break; 1256 1.1 jtc 1257 1.1 jtc case '|': 1258 1.1 jtc ncursor = argcnt; 1259 1.1 jtc if (ncursor > es->linelen) 1260 1.1 jtc ncursor = es->linelen; 1261 1.1 jtc if (ncursor) 1262 1.1 jtc ncursor--; 1263 1.1 jtc break; 1264 1.1 jtc 1265 1.1 jtc case '$': 1266 1.1 jtc if (es->linelen != 0) 1267 1.1 jtc ncursor = es->linelen; 1268 1.1 jtc else 1269 1.1 jtc ncursor = 0; 1270 1.1 jtc break; 1271 1.1 jtc 1272 1.1 jtc case '%': 1273 1.1 jtc ncursor = es->cursor; 1274 1.1 jtc while (ncursor < es->linelen && 1275 1.1 jtc (i = bracktype(es->cbuf[ncursor])) == 0) 1276 1.1 jtc ncursor++; 1277 1.1 jtc if (ncursor == es->linelen) 1278 1.1 jtc return -1; 1279 1.1 jtc bcount = 1; 1280 1.1 jtc do { 1281 1.1 jtc if (i > 0) { 1282 1.1 jtc if (++ncursor >= es->linelen) 1283 1.1 jtc return -1; 1284 1.1 jtc } else { 1285 1.1 jtc if (--ncursor < 0) 1286 1.1 jtc return -1; 1287 1.1 jtc } 1288 1.1 jtc t = bracktype(es->cbuf[ncursor]); 1289 1.1 jtc if (t == i) 1290 1.1 jtc bcount++; 1291 1.1 jtc else if (t == -i) 1292 1.1 jtc bcount--; 1293 1.1 jtc } while (bcount != 0); 1294 1.1 jtc if (sub && i > 0) 1295 1.1 jtc ncursor++; 1296 1.1 jtc break; 1297 1.1 jtc 1298 1.1 jtc default: 1299 1.1 jtc return -1; 1300 1.1 jtc } 1301 1.1 jtc return ncursor; 1302 1.1 jtc } 1303 1.1 jtc 1304 1.1 jtc static int 1305 1.1 jtc redo_insert(count) 1306 1.1 jtc int count; 1307 1.1 jtc { 1308 1.1 jtc while (count-- > 0) 1309 1.1 jtc if (putbuf(ibuf, inslen, insert==REPLACE) != 0) 1310 1.1 jtc return -1; 1311 1.1 jtc if (es->cursor > 0) 1312 1.1 jtc es->cursor--; 1313 1.1 jtc insert = 0; 1314 1.1 jtc return 0; 1315 1.1 jtc } 1316 1.1 jtc 1317 1.1 jtc static void 1318 1.1 jtc yank_range(a, b) 1319 1.1 jtc int a, b; 1320 1.1 jtc { 1321 1.1 jtc yanklen = b - a; 1322 1.1 jtc if (yanklen != 0) 1323 1.1 jtc memmove(ybuf, &es->cbuf[a], yanklen); 1324 1.1 jtc } 1325 1.1 jtc 1326 1.1 jtc static int 1327 1.1 jtc bracktype(ch) 1328 1.1 jtc int ch; 1329 1.1 jtc { 1330 1.1 jtc switch (ch) { 1331 1.1 jtc 1332 1.1 jtc case '(': 1333 1.1 jtc return 1; 1334 1.1 jtc 1335 1.1 jtc case '[': 1336 1.1 jtc return 2; 1337 1.1 jtc 1338 1.1 jtc case '{': 1339 1.1 jtc return 3; 1340 1.1 jtc 1341 1.1 jtc case ')': 1342 1.1 jtc return -1; 1343 1.1 jtc 1344 1.1 jtc case ']': 1345 1.1 jtc return -2; 1346 1.1 jtc 1347 1.1 jtc case '}': 1348 1.1 jtc return -3; 1349 1.1 jtc 1350 1.1 jtc default: 1351 1.1 jtc return 0; 1352 1.1 jtc } 1353 1.1 jtc } 1354 1.1 jtc 1355 1.1 jtc /* 1356 1.1 jtc * Non user interface editor routines below here 1357 1.1 jtc */ 1358 1.1 jtc 1359 1.1 jtc static int cur_col; /* current column on line */ 1360 1.1 jtc static int pwidth; /* width of prompt */ 1361 1.1 jtc static int prompt_trunc; /* how much of prompt to truncate */ 1362 1.1 jtc static int prompt_skip; /* how much of prompt to skip */ 1363 1.1 jtc static int winwidth; /* width of window */ 1364 1.1 jtc static char *wbuf[2]; /* window buffers */ 1365 1.1 jtc static int wbuf_len; /* length of window buffers (x_cols-3)*/ 1366 1.1 jtc static int win; /* window buffer in use */ 1367 1.1 jtc static char morec; /* more character at right of window */ 1368 1.1 jtc static int lastref; /* argument to last refresh() */ 1369 1.1 jtc static char holdbuf[CMDLEN]; /* place to hold last edit buffer */ 1370 1.1 jtc static int holdlen; /* length of holdbuf */ 1371 1.1 jtc 1372 1.1 jtc static void 1373 1.1 jtc save_cbuf() 1374 1.1 jtc { 1375 1.1 jtc memmove(holdbuf, es->cbuf, es->linelen); 1376 1.1 jtc holdlen = es->linelen; 1377 1.1 jtc holdbuf[holdlen] = '\0'; 1378 1.1 jtc } 1379 1.1 jtc 1380 1.1 jtc static void 1381 1.1 jtc restore_cbuf() 1382 1.1 jtc { 1383 1.1 jtc es->cursor = 0; 1384 1.1 jtc es->linelen = holdlen; 1385 1.1 jtc memmove(es->cbuf, holdbuf, holdlen); 1386 1.1 jtc } 1387 1.1 jtc 1388 1.1 jtc /* return a new edstate */ 1389 1.1 jtc static struct edstate * 1390 1.1 jtc save_edstate(old) 1391 1.1 jtc struct edstate *old; 1392 1.1 jtc { 1393 1.1 jtc struct edstate *new; 1394 1.1 jtc 1395 1.1 jtc new = (struct edstate *)alloc(sizeof(struct edstate), APERM); 1396 1.1 jtc new->cbuf = alloc(old->cbufsize, APERM); 1397 1.8 mycroft memcpy(new->cbuf, old->cbuf, old->linelen); 1398 1.1 jtc new->cbufsize = old->cbufsize; 1399 1.1 jtc new->linelen = old->linelen; 1400 1.1 jtc new->cursor = old->cursor; 1401 1.1 jtc new->winleft = old->winleft; 1402 1.1 jtc return new; 1403 1.1 jtc } 1404 1.1 jtc 1405 1.1 jtc static void 1406 1.1 jtc restore_edstate(new, old) 1407 1.1 jtc struct edstate *old, *new; 1408 1.1 jtc { 1409 1.8 mycroft memcpy(new->cbuf, old->cbuf, old->linelen); 1410 1.1 jtc new->linelen = old->linelen; 1411 1.1 jtc new->cursor = old->cursor; 1412 1.1 jtc new->winleft = old->winleft; 1413 1.1 jtc free_edstate(old); 1414 1.1 jtc } 1415 1.1 jtc 1416 1.1 jtc static void 1417 1.1 jtc free_edstate(old) 1418 1.1 jtc struct edstate *old; 1419 1.1 jtc { 1420 1.1 jtc afree(old->cbuf, APERM); 1421 1.1 jtc afree((char *)old, APERM); 1422 1.1 jtc } 1423 1.1 jtc 1424 1.1 jtc 1425 1.1 jtc 1426 1.1 jtc static void 1427 1.1 jtc edit_reset(buf, len) 1428 1.1 jtc char *buf; 1429 1.1 jtc size_t len; 1430 1.1 jtc { 1431 1.1 jtc const char *p; 1432 1.1 jtc 1433 1.1 jtc es = &ebuf; 1434 1.1 jtc es->cbuf = buf; 1435 1.1 jtc es->cbufsize = len; 1436 1.1 jtc undo = &undobuf; 1437 1.1 jtc undo->cbufsize = len; 1438 1.1 jtc 1439 1.1 jtc es->linelen = undo->linelen = 0; 1440 1.1 jtc es->cursor = undo->cursor = 0; 1441 1.1 jtc es->winleft = undo->winleft = 0; 1442 1.1 jtc 1443 1.1 jtc cur_col = pwidth = promptlen(prompt, &p); 1444 1.1 jtc prompt_skip = p - prompt; 1445 1.1 jtc if (pwidth > x_cols - 3 - MIN_EDIT_SPACE) { 1446 1.1 jtc cur_col = x_cols - 3 - MIN_EDIT_SPACE; 1447 1.1 jtc prompt_trunc = pwidth - cur_col; 1448 1.1 jtc pwidth -= prompt_trunc; 1449 1.1 jtc } else 1450 1.1 jtc prompt_trunc = 0; 1451 1.1 jtc if (!wbuf_len || wbuf_len != x_cols - 3) { 1452 1.1 jtc wbuf_len = x_cols - 3; 1453 1.1 jtc wbuf[0] = aresize(wbuf[0], wbuf_len, APERM); 1454 1.1 jtc wbuf[1] = aresize(wbuf[1], wbuf_len, APERM); 1455 1.1 jtc } 1456 1.1 jtc (void) memset(wbuf[0], ' ', wbuf_len); 1457 1.1 jtc (void) memset(wbuf[1], ' ', wbuf_len); 1458 1.1 jtc winwidth = x_cols - pwidth - 3; 1459 1.1 jtc win = 0; 1460 1.1 jtc morec = ' '; 1461 1.1 jtc lastref = 1; 1462 1.1 jtc holdlen = 0; 1463 1.1 jtc } 1464 1.1 jtc 1465 1.5 jdolecek /* 1466 1.5 jdolecek * this is used for calling x_escape() in complete_word() 1467 1.5 jdolecek */ 1468 1.5 jdolecek static int 1469 1.5 jdolecek x_vi_putbuf(s, len) 1470 1.5 jdolecek const char *s; 1471 1.5 jdolecek size_t len; 1472 1.5 jdolecek { 1473 1.5 jdolecek return putbuf(s, len, 0); 1474 1.5 jdolecek } 1475 1.5 jdolecek 1476 1.1 jtc static int 1477 1.1 jtc putbuf(buf, len, repl) 1478 1.1 jtc const char *buf; 1479 1.1 jtc int len; 1480 1.1 jtc int repl; 1481 1.1 jtc { 1482 1.1 jtc if (len == 0) 1483 1.1 jtc return 0; 1484 1.1 jtc if (repl) { 1485 1.1 jtc if (es->cursor + len >= es->cbufsize) 1486 1.1 jtc return -1; 1487 1.1 jtc if (es->cursor + len > es->linelen) 1488 1.1 jtc es->linelen = es->cursor + len; 1489 1.1 jtc } else { 1490 1.1 jtc if (es->linelen + len >= es->cbufsize) 1491 1.1 jtc return -1; 1492 1.1 jtc memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor], 1493 1.1 jtc es->linelen - es->cursor); 1494 1.1 jtc es->linelen += len; 1495 1.1 jtc } 1496 1.1 jtc memmove(&es->cbuf[es->cursor], buf, len); 1497 1.1 jtc es->cursor += len; 1498 1.1 jtc return 0; 1499 1.1 jtc } 1500 1.1 jtc 1501 1.1 jtc static void 1502 1.1 jtc del_range(a, b) 1503 1.1 jtc int a, b; 1504 1.1 jtc { 1505 1.1 jtc if (es->linelen != b) 1506 1.1 jtc memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b); 1507 1.1 jtc es->linelen -= b - a; 1508 1.1 jtc } 1509 1.1 jtc 1510 1.1 jtc static int 1511 1.1 jtc findch(ch, cnt, forw, incl) 1512 1.1 jtc int ch; 1513 1.1 jtc int cnt; 1514 1.1 jtc int forw; 1515 1.1 jtc int incl; 1516 1.1 jtc { 1517 1.1 jtc int ncursor; 1518 1.1 jtc 1519 1.1 jtc if (es->linelen == 0) 1520 1.1 jtc return -1; 1521 1.1 jtc ncursor = es->cursor; 1522 1.1 jtc while (cnt--) { 1523 1.1 jtc do { 1524 1.1 jtc if (forw) { 1525 1.1 jtc if (++ncursor == es->linelen) 1526 1.1 jtc return -1; 1527 1.1 jtc } else { 1528 1.1 jtc if (--ncursor < 0) 1529 1.1 jtc return -1; 1530 1.1 jtc } 1531 1.1 jtc } while (es->cbuf[ncursor] != ch); 1532 1.1 jtc } 1533 1.1 jtc if (!incl) { 1534 1.1 jtc if (forw) 1535 1.1 jtc ncursor--; 1536 1.1 jtc else 1537 1.1 jtc ncursor++; 1538 1.1 jtc } 1539 1.1 jtc return ncursor; 1540 1.1 jtc } 1541 1.1 jtc 1542 1.1 jtc static int 1543 1.1 jtc forwword(argcnt) 1544 1.1 jtc int argcnt; 1545 1.1 jtc { 1546 1.1 jtc int ncursor; 1547 1.1 jtc 1548 1.1 jtc ncursor = es->cursor; 1549 1.1 jtc while (ncursor < es->linelen && argcnt--) { 1550 1.1 jtc if (is_wordch(es->cbuf[ncursor])) 1551 1.13 christos while (ncursor < es->linelen && 1552 1.13 christos is_wordch(es->cbuf[ncursor])) 1553 1.1 jtc ncursor++; 1554 1.3 christos else if (!isspace((unsigned char)es->cbuf[ncursor])) 1555 1.13 christos while (ncursor < es->linelen && 1556 1.13 christos !is_wordch(es->cbuf[ncursor]) && 1557 1.13 christos !isspace((unsigned char)es->cbuf[ncursor])) 1558 1.1 jtc ncursor++; 1559 1.13 christos while (ncursor < es->linelen && 1560 1.13 christos isspace((unsigned char)es->cbuf[ncursor])) 1561 1.1 jtc ncursor++; 1562 1.1 jtc } 1563 1.1 jtc return ncursor; 1564 1.1 jtc } 1565 1.1 jtc 1566 1.1 jtc static int 1567 1.1 jtc backword(argcnt) 1568 1.1 jtc int argcnt; 1569 1.1 jtc { 1570 1.1 jtc int ncursor; 1571 1.1 jtc 1572 1.1 jtc ncursor = es->cursor; 1573 1.1 jtc while (ncursor > 0 && argcnt--) { 1574 1.3 christos while (--ncursor > 0 && isspace((unsigned char)es->cbuf[ncursor])) 1575 1.13 christos continue; 1576 1.1 jtc if (ncursor > 0) { 1577 1.1 jtc if (is_wordch(es->cbuf[ncursor])) 1578 1.1 jtc while (--ncursor >= 0 && 1579 1.1 jtc is_wordch(es->cbuf[ncursor])) 1580 1.13 christos continue; 1581 1.1 jtc else 1582 1.1 jtc while (--ncursor >= 0 && 1583 1.1 jtc !is_wordch(es->cbuf[ncursor]) && 1584 1.3 christos !isspace((unsigned char)es->cbuf[ncursor])) 1585 1.13 christos continue; 1586 1.1 jtc ncursor++; 1587 1.1 jtc } 1588 1.1 jtc } 1589 1.1 jtc return ncursor; 1590 1.1 jtc } 1591 1.1 jtc 1592 1.1 jtc static int 1593 1.1 jtc endword(argcnt) 1594 1.1 jtc int argcnt; 1595 1.1 jtc { 1596 1.1 jtc int ncursor; 1597 1.1 jtc 1598 1.1 jtc ncursor = es->cursor; 1599 1.1 jtc while (ncursor < es->linelen && argcnt--) { 1600 1.1 jtc while (++ncursor < es->linelen - 1 && 1601 1.13 christos isspace((unsigned char)es->cbuf[ncursor])) 1602 1.13 christos continue; 1603 1.1 jtc if (ncursor < es->linelen - 1) { 1604 1.1 jtc if (is_wordch(es->cbuf[ncursor])) 1605 1.1 jtc while (++ncursor < es->linelen && 1606 1.13 christos is_wordch(es->cbuf[ncursor])) 1607 1.13 christos continue; 1608 1.1 jtc else 1609 1.1 jtc while (++ncursor < es->linelen && 1610 1.1 jtc !is_wordch(es->cbuf[ncursor]) && 1611 1.3 christos !isspace((unsigned char)es->cbuf[ncursor])) 1612 1.13 christos continue; 1613 1.1 jtc ncursor--; 1614 1.1 jtc } 1615 1.1 jtc } 1616 1.1 jtc return ncursor; 1617 1.1 jtc } 1618 1.1 jtc 1619 1.1 jtc static int 1620 1.1 jtc Forwword(argcnt) 1621 1.1 jtc int argcnt; 1622 1.1 jtc { 1623 1.1 jtc int ncursor; 1624 1.1 jtc 1625 1.1 jtc ncursor = es->cursor; 1626 1.1 jtc while (ncursor < es->linelen && argcnt--) { 1627 1.13 christos while (ncursor < es->linelen && 1628 1.13 christos !isspace((unsigned char)es->cbuf[ncursor])) 1629 1.1 jtc ncursor++; 1630 1.13 christos while (ncursor < es->linelen && 1631 1.13 christos isspace((unsigned char)es->cbuf[ncursor])) 1632 1.1 jtc ncursor++; 1633 1.1 jtc } 1634 1.1 jtc return ncursor; 1635 1.1 jtc } 1636 1.1 jtc 1637 1.1 jtc static int 1638 1.1 jtc Backword(argcnt) 1639 1.1 jtc int argcnt; 1640 1.1 jtc { 1641 1.1 jtc int ncursor; 1642 1.1 jtc 1643 1.1 jtc ncursor = es->cursor; 1644 1.1 jtc while (ncursor > 0 && argcnt--) { 1645 1.3 christos while (--ncursor >= 0 && isspace((unsigned char)es->cbuf[ncursor])) 1646 1.13 christos continue; 1647 1.3 christos while (ncursor >= 0 && !isspace((unsigned char)es->cbuf[ncursor])) 1648 1.1 jtc ncursor--; 1649 1.1 jtc ncursor++; 1650 1.1 jtc } 1651 1.1 jtc return ncursor; 1652 1.1 jtc } 1653 1.1 jtc 1654 1.1 jtc static int 1655 1.1 jtc Endword(argcnt) 1656 1.1 jtc int argcnt; 1657 1.1 jtc { 1658 1.1 jtc int ncursor; 1659 1.1 jtc 1660 1.1 jtc ncursor = es->cursor; 1661 1.1 jtc while (ncursor < es->linelen - 1 && argcnt--) { 1662 1.1 jtc while (++ncursor < es->linelen - 1 && 1663 1.13 christos isspace((unsigned char)es->cbuf[ncursor])) 1664 1.13 christos continue; 1665 1.1 jtc if (ncursor < es->linelen - 1) { 1666 1.1 jtc while (++ncursor < es->linelen && 1667 1.13 christos !isspace((unsigned char)es->cbuf[ncursor])) 1668 1.13 christos continue; 1669 1.1 jtc ncursor--; 1670 1.1 jtc } 1671 1.1 jtc } 1672 1.1 jtc return ncursor; 1673 1.1 jtc } 1674 1.1 jtc 1675 1.1 jtc static int 1676 1.1 jtc grabhist(save, n) 1677 1.1 jtc int save; 1678 1.1 jtc int n; 1679 1.1 jtc { 1680 1.1 jtc char *hptr; 1681 1.1 jtc 1682 1.1 jtc if (n < 0 || n > hlast) 1683 1.1 jtc return -1; 1684 1.1 jtc if (n == hlast) { 1685 1.1 jtc restore_cbuf(); 1686 1.1 jtc ohnum = n; 1687 1.1 jtc return 0; 1688 1.1 jtc } 1689 1.1 jtc (void) histnum(n); 1690 1.1 jtc if ((hptr = *histpos()) == NULL) { 1691 1.1 jtc internal_errorf(0, "grabhist: bad history array"); 1692 1.1 jtc return -1; 1693 1.1 jtc } 1694 1.1 jtc if (save) 1695 1.1 jtc save_cbuf(); 1696 1.1 jtc if ((es->linelen = strlen(hptr)) >= es->cbufsize) 1697 1.1 jtc es->linelen = es->cbufsize - 1; 1698 1.1 jtc memmove(es->cbuf, hptr, es->linelen); 1699 1.1 jtc es->cursor = 0; 1700 1.1 jtc ohnum = n; 1701 1.1 jtc return 0; 1702 1.1 jtc } 1703 1.1 jtc 1704 1.1 jtc static int 1705 1.1 jtc grabsearch(save, start, fwd, pat) 1706 1.1 jtc int save, start, fwd; 1707 1.1 jtc char *pat; 1708 1.1 jtc { 1709 1.1 jtc char *hptr; 1710 1.1 jtc int hist; 1711 1.1 jtc int anchored; 1712 1.1 jtc 1713 1.1 jtc if ((start == 0 && fwd == 0) || (start >= hlast-1 && fwd == 1)) 1714 1.1 jtc return -1; 1715 1.1 jtc if (fwd) 1716 1.1 jtc start++; 1717 1.1 jtc else 1718 1.1 jtc start--; 1719 1.1 jtc anchored = *pat == '^' ? (++pat, 1) : 0; 1720 1.1 jtc if ((hist = findhist(start, fwd, pat, anchored)) < 0) { 1721 1.1 jtc /* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */ 1722 1.1 jtc /* XXX should FILECMP be strncmp? */ 1723 1.1 jtc if (start != 0 && fwd && FILECMP(holdbuf, pat) >= 0) { 1724 1.1 jtc restore_cbuf(); 1725 1.1 jtc return 0; 1726 1.1 jtc } else 1727 1.1 jtc return -1; 1728 1.1 jtc } 1729 1.1 jtc if (save) 1730 1.1 jtc save_cbuf(); 1731 1.1 jtc histnum(hist); 1732 1.1 jtc hptr = *histpos(); 1733 1.1 jtc if ((es->linelen = strlen(hptr)) >= es->cbufsize) 1734 1.1 jtc es->linelen = es->cbufsize - 1; 1735 1.1 jtc memmove(es->cbuf, hptr, es->linelen); 1736 1.1 jtc es->cursor = 0; 1737 1.1 jtc return hist; 1738 1.1 jtc } 1739 1.1 jtc 1740 1.1 jtc static void 1741 1.10 christos redraw_line(newlinex) 1742 1.10 christos int newlinex; 1743 1.1 jtc { 1744 1.1 jtc (void) memset(wbuf[win], ' ', wbuf_len); 1745 1.12 mrg if (newlinex) { 1746 1.1 jtc x_putc('\r'); 1747 1.1 jtc x_putc('\n'); 1748 1.1 jtc } 1749 1.1 jtc vi_pprompt(0); 1750 1.1 jtc cur_col = pwidth; 1751 1.1 jtc morec = ' '; 1752 1.1 jtc } 1753 1.1 jtc 1754 1.1 jtc static void 1755 1.1 jtc refresh(leftside) 1756 1.1 jtc int leftside; 1757 1.1 jtc { 1758 1.1 jtc if (leftside < 0) 1759 1.1 jtc leftside = lastref; 1760 1.1 jtc else 1761 1.1 jtc lastref = leftside; 1762 1.1 jtc if (outofwin()) 1763 1.1 jtc rewindow(); 1764 1.1 jtc display(wbuf[1 - win], wbuf[win], leftside); 1765 1.1 jtc win = 1 - win; 1766 1.1 jtc } 1767 1.1 jtc 1768 1.1 jtc static int 1769 1.1 jtc outofwin() 1770 1.1 jtc { 1771 1.1 jtc int cur, col; 1772 1.1 jtc 1773 1.1 jtc if (es->cursor < es->winleft) 1774 1.1 jtc return 1; 1775 1.1 jtc col = 0; 1776 1.1 jtc cur = es->winleft; 1777 1.1 jtc while (cur < es->cursor) 1778 1.1 jtc col = newcol((unsigned char) es->cbuf[cur++], col); 1779 1.1 jtc if (col >= winwidth) 1780 1.1 jtc return 1; 1781 1.1 jtc return 0; 1782 1.1 jtc } 1783 1.1 jtc 1784 1.1 jtc static void 1785 1.1 jtc rewindow() 1786 1.1 jtc { 1787 1.20 kamil int tcur, tcol; 1788 1.1 jtc int holdcur1, holdcol1; 1789 1.1 jtc int holdcur2, holdcol2; 1790 1.1 jtc 1791 1.1 jtc holdcur1 = holdcur2 = tcur = 0; 1792 1.1 jtc holdcol1 = holdcol2 = tcol = 0; 1793 1.1 jtc while (tcur < es->cursor) { 1794 1.1 jtc if (tcol - holdcol2 > winwidth / 2) { 1795 1.1 jtc holdcur1 = holdcur2; 1796 1.1 jtc holdcol1 = holdcol2; 1797 1.1 jtc holdcur2 = tcur; 1798 1.1 jtc holdcol2 = tcol; 1799 1.1 jtc } 1800 1.1 jtc tcol = newcol((unsigned char) es->cbuf[tcur++], tcol); 1801 1.1 jtc } 1802 1.1 jtc while (tcol - holdcol1 > winwidth / 2) 1803 1.1 jtc holdcol1 = newcol((unsigned char) es->cbuf[holdcur1++], 1804 1.1 jtc holdcol1); 1805 1.1 jtc es->winleft = holdcur1; 1806 1.1 jtc } 1807 1.1 jtc 1808 1.1 jtc static int 1809 1.1 jtc newcol(ch, col) 1810 1.1 jtc int ch, col; 1811 1.1 jtc { 1812 1.1 jtc if (ch == '\t') 1813 1.1 jtc return (col | 7) + 1; 1814 1.1 jtc return col + char_len(ch); 1815 1.1 jtc } 1816 1.1 jtc 1817 1.1 jtc static void 1818 1.1 jtc display(wb1, wb2, leftside) 1819 1.1 jtc char *wb1, *wb2; 1820 1.1 jtc int leftside; 1821 1.1 jtc { 1822 1.1 jtc unsigned char ch; 1823 1.1 jtc char *twb1, *twb2, mc; 1824 1.1 jtc int cur, col, cnt; 1825 1.1 jtc int UNINITIALIZED(ncol); 1826 1.1 jtc int moreright; 1827 1.1 jtc 1828 1.1 jtc col = 0; 1829 1.1 jtc cur = es->winleft; 1830 1.1 jtc moreright = 0; 1831 1.1 jtc twb1 = wb1; 1832 1.1 jtc while (col < winwidth && cur < es->linelen) { 1833 1.1 jtc if (cur == es->cursor && leftside) 1834 1.1 jtc ncol = col + pwidth; 1835 1.1 jtc if ((ch = es->cbuf[cur]) == '\t') { 1836 1.1 jtc do { 1837 1.1 jtc *twb1++ = ' '; 1838 1.1 jtc } while (++col < winwidth && (col & 7) != 0); 1839 1.1 jtc } else { 1840 1.1 jtc if ((ch & 0x80) && Flag(FVISHOW8)) { 1841 1.1 jtc *twb1++ = 'M'; 1842 1.1 jtc if (++col < winwidth) { 1843 1.1 jtc *twb1++ = '-'; 1844 1.1 jtc col++; 1845 1.1 jtc } 1846 1.1 jtc ch &= 0x7f; 1847 1.1 jtc } 1848 1.1 jtc if (col < winwidth) { 1849 1.1 jtc if (ch < ' ' || ch == 0x7f) { 1850 1.1 jtc *twb1++ = '^'; 1851 1.1 jtc if (++col < winwidth) { 1852 1.2 tls *twb1++ = ch ^ '@'; 1853 1.1 jtc col++; 1854 1.1 jtc } 1855 1.1 jtc } else { 1856 1.2 tls *twb1++ = ch; 1857 1.1 jtc col++; 1858 1.1 jtc } 1859 1.1 jtc } 1860 1.1 jtc } 1861 1.1 jtc if (cur == es->cursor && !leftside) 1862 1.1 jtc ncol = col + pwidth - 1; 1863 1.1 jtc cur++; 1864 1.1 jtc } 1865 1.1 jtc if (cur == es->cursor) 1866 1.1 jtc ncol = col + pwidth; 1867 1.1 jtc if (col < winwidth) { 1868 1.1 jtc while (col < winwidth) { 1869 1.1 jtc *twb1++ = ' '; 1870 1.1 jtc col++; 1871 1.1 jtc } 1872 1.1 jtc } else 1873 1.1 jtc moreright++; 1874 1.1 jtc *twb1 = ' '; 1875 1.1 jtc 1876 1.1 jtc col = pwidth; 1877 1.1 jtc cnt = winwidth; 1878 1.1 jtc twb1 = wb1; 1879 1.1 jtc twb2 = wb2; 1880 1.1 jtc while (cnt--) { 1881 1.1 jtc if (*twb1 != *twb2) { 1882 1.1 jtc if (cur_col != col) 1883 1.1 jtc ed_mov_opt(col, wb1); 1884 1.1 jtc x_putc(*twb1); 1885 1.1 jtc cur_col++; 1886 1.1 jtc } 1887 1.1 jtc twb1++; 1888 1.1 jtc twb2++; 1889 1.1 jtc col++; 1890 1.1 jtc } 1891 1.1 jtc if (es->winleft > 0 && moreright) 1892 1.1 jtc /* POSIX says to use * for this but that is a globbing 1893 1.1 jtc * character and may confuse people; + is more innocuous 1894 1.1 jtc */ 1895 1.1 jtc mc = '+'; 1896 1.1 jtc else if (es->winleft > 0) 1897 1.1 jtc mc = '<'; 1898 1.1 jtc else if (moreright) 1899 1.1 jtc mc = '>'; 1900 1.1 jtc else 1901 1.1 jtc mc = ' '; 1902 1.1 jtc if (mc != morec) { 1903 1.1 jtc ed_mov_opt(pwidth + winwidth + 1, wb1); 1904 1.1 jtc x_putc(mc); 1905 1.1 jtc cur_col++; 1906 1.1 jtc morec = mc; 1907 1.1 jtc } 1908 1.1 jtc if (cur_col != ncol) 1909 1.1 jtc ed_mov_opt(ncol, wb1); 1910 1.1 jtc } 1911 1.1 jtc 1912 1.1 jtc static void 1913 1.1 jtc ed_mov_opt(col, wb) 1914 1.1 jtc int col; 1915 1.1 jtc char *wb; 1916 1.1 jtc { 1917 1.1 jtc if (col < cur_col) { 1918 1.1 jtc if (col + 1 < cur_col - col) { 1919 1.1 jtc x_putc('\r'); 1920 1.1 jtc vi_pprompt(0); 1921 1.1 jtc cur_col = pwidth; 1922 1.1 jtc while (cur_col++ < col) 1923 1.1 jtc x_putc(*wb++); 1924 1.1 jtc } else { 1925 1.1 jtc while (cur_col-- > col) 1926 1.1 jtc x_putc('\b'); 1927 1.1 jtc } 1928 1.1 jtc } else { 1929 1.1 jtc wb = &wb[cur_col - pwidth]; 1930 1.1 jtc while (cur_col++ < col) 1931 1.1 jtc x_putc(*wb++); 1932 1.1 jtc } 1933 1.1 jtc cur_col = col; 1934 1.1 jtc } 1935 1.1 jtc 1936 1.1 jtc 1937 1.1 jtc /* replace word with all expansions (ie, expand word*) */ 1938 1.1 jtc static int 1939 1.10 christos expand_word(commandx) 1940 1.10 christos int commandx; 1941 1.1 jtc { 1942 1.1 jtc static struct edstate *buf; 1943 1.1 jtc int rval = 0; 1944 1.1 jtc int nwords; 1945 1.1 jtc int start, end; 1946 1.1 jtc char **words; 1947 1.1 jtc int i; 1948 1.1 jtc 1949 1.1 jtc /* Undo previous expansion */ 1950 1.10 christos if (commandx == 0 && expanded == EXPAND && buf) { 1951 1.1 jtc restore_edstate(es, buf); 1952 1.1 jtc buf = 0; 1953 1.1 jtc expanded = NONE; 1954 1.1 jtc return 0; 1955 1.1 jtc } 1956 1.1 jtc if (buf) { 1957 1.1 jtc free_edstate(buf); 1958 1.1 jtc buf = 0; 1959 1.1 jtc } 1960 1.1 jtc 1961 1.1 jtc nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH, 1962 1.1 jtc es->cbuf, es->linelen, es->cursor, 1963 1.1 jtc &start, &end, &words, (int *) 0); 1964 1.1 jtc if (nwords == 0) { 1965 1.1 jtc vi_error(); 1966 1.1 jtc return -1; 1967 1.1 jtc } 1968 1.1 jtc 1969 1.1 jtc buf = save_edstate(es); 1970 1.1 jtc expanded = EXPAND; 1971 1.1 jtc del_range(start, end); 1972 1.1 jtc es->cursor = start; 1973 1.1 jtc for (i = 0; i < nwords; ) { 1974 1.8 mycroft if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) { 1975 1.1 jtc rval = -1; 1976 1.1 jtc break; 1977 1.1 jtc } 1978 1.1 jtc if (++i < nwords && putbuf(space, 1, 0) != 0) { 1979 1.1 jtc rval = -1; 1980 1.1 jtc break; 1981 1.1 jtc } 1982 1.1 jtc } 1983 1.1 jtc i = buf->cursor - end; 1984 1.1 jtc if (rval == 0 && i > 0) 1985 1.1 jtc es->cursor += i; 1986 1.1 jtc modified = 1; hnum = hlast; 1987 1.1 jtc insert = INSERT; 1988 1.1 jtc lastac = 0; 1989 1.1 jtc refresh(0); 1990 1.1 jtc return rval; 1991 1.1 jtc } 1992 1.1 jtc 1993 1.1 jtc static int 1994 1.10 christos complete_word(commandx, count) 1995 1.10 christos int commandx; 1996 1.1 jtc int count; 1997 1.1 jtc { 1998 1.1 jtc static struct edstate *buf; 1999 1.1 jtc int rval = 0; 2000 1.1 jtc int nwords; 2001 1.1 jtc int start, end; 2002 1.1 jtc char **words; 2003 1.1 jtc char *match; 2004 1.1 jtc int match_len; 2005 1.1 jtc int is_unique; 2006 1.1 jtc int is_command; 2007 1.1 jtc 2008 1.1 jtc /* Undo previous completion */ 2009 1.10 christos if (commandx == 0 && expanded == COMPLETE && buf) { 2010 1.1 jtc print_expansions(buf, 0); 2011 1.1 jtc expanded = PRINT; 2012 1.1 jtc return 0; 2013 1.1 jtc } 2014 1.10 christos if (commandx == 0 && expanded == PRINT && buf) { 2015 1.1 jtc restore_edstate(es, buf); 2016 1.1 jtc buf = 0; 2017 1.1 jtc expanded = NONE; 2018 1.1 jtc return 0; 2019 1.1 jtc } 2020 1.1 jtc if (buf) { 2021 1.1 jtc free_edstate(buf); 2022 1.1 jtc buf = 0; 2023 1.1 jtc } 2024 1.1 jtc 2025 1.1 jtc /* XCF_FULLPATH for count 'cause the menu printed by print_expansions() 2026 1.1 jtc * was done this way. 2027 1.1 jtc */ 2028 1.1 jtc nwords = x_cf_glob(XCF_COMMAND_FILE | (count ? XCF_FULLPATH : 0), 2029 1.1 jtc es->cbuf, es->linelen, es->cursor, 2030 1.1 jtc &start, &end, &words, &is_command); 2031 1.1 jtc if (nwords == 0) { 2032 1.1 jtc vi_error(); 2033 1.1 jtc return -1; 2034 1.1 jtc } 2035 1.1 jtc if (count) { 2036 1.1 jtc int i; 2037 1.1 jtc 2038 1.1 jtc count--; 2039 1.1 jtc if (count >= nwords) { 2040 1.1 jtc vi_error(); 2041 1.1 jtc x_print_expansions(nwords, words, is_command); 2042 1.1 jtc x_free_words(nwords, words); 2043 1.1 jtc redraw_line(0); 2044 1.1 jtc return -1; 2045 1.1 jtc } 2046 1.1 jtc /* 2047 1.1 jtc * Expand the count'th word to its basename 2048 1.1 jtc */ 2049 1.1 jtc if (is_command) { 2050 1.1 jtc match = words[count] 2051 1.1 jtc + x_basename(words[count], (char *) 0); 2052 1.1 jtc /* If more than one possible match, use full path */ 2053 1.1 jtc for (i = 0; i < nwords; i++) 2054 1.1 jtc if (i != count && 2055 1.1 jtc FILECMP(words[i] 2056 1.1 jtc + x_basename(words[i], (char *) 0), 2057 1.1 jtc match) == 0) 2058 1.1 jtc { 2059 1.1 jtc match = words[count]; 2060 1.1 jtc break; 2061 1.1 jtc } 2062 1.1 jtc } else 2063 1.1 jtc match = words[count]; 2064 1.1 jtc match_len = strlen(match); 2065 1.1 jtc is_unique = 1; 2066 1.1 jtc /* expanded = PRINT; next call undo */ 2067 1.1 jtc } else { 2068 1.1 jtc match = words[0]; 2069 1.1 jtc match_len = x_longest_prefix(nwords, words); 2070 1.1 jtc expanded = COMPLETE; /* next call will list completions */ 2071 1.1 jtc is_unique = nwords == 1; 2072 1.1 jtc } 2073 1.1 jtc 2074 1.1 jtc buf = save_edstate(es); 2075 1.1 jtc del_range(start, end); 2076 1.1 jtc es->cursor = start; 2077 1.5 jdolecek 2078 1.5 jdolecek /* escape all shell-sensitive characters and put the result into 2079 1.5 jdolecek * command buffer */ 2080 1.5 jdolecek rval = x_escape(match, match_len, x_vi_putbuf); 2081 1.5 jdolecek 2082 1.5 jdolecek if (rval == 0 && is_unique) { 2083 1.1 jtc /* If exact match, don't undo. Allows directory completions 2084 1.1 jtc * to be used (ie, complete the next portion of the path). 2085 1.1 jtc */ 2086 1.1 jtc expanded = NONE; 2087 1.1 jtc 2088 1.1 jtc /* If not a directory, add a space to the end... */ 2089 1.1 jtc if (match_len > 0 && !ISDIRSEP(match[match_len - 1])) 2090 1.1 jtc rval = putbuf(space, 1, 0); 2091 1.1 jtc } 2092 1.1 jtc x_free_words(nwords, words); 2093 1.1 jtc 2094 1.1 jtc modified = 1; hnum = hlast; 2095 1.1 jtc insert = INSERT; 2096 1.1 jtc lastac = 0; /* prevent this from being redone... */ 2097 1.1 jtc refresh(0); 2098 1.1 jtc 2099 1.1 jtc return rval; 2100 1.1 jtc } 2101 1.1 jtc 2102 1.1 jtc static int 2103 1.10 christos print_expansions(ex, commandx) 2104 1.10 christos struct edstate *ex; 2105 1.10 christos int commandx; 2106 1.1 jtc { 2107 1.1 jtc int nwords; 2108 1.1 jtc int start, end; 2109 1.1 jtc char **words; 2110 1.1 jtc int is_command; 2111 1.1 jtc 2112 1.1 jtc nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH, 2113 1.10 christos ex->cbuf, ex->linelen, ex->cursor, 2114 1.1 jtc &start, &end, &words, &is_command); 2115 1.1 jtc if (nwords == 0) { 2116 1.1 jtc vi_error(); 2117 1.1 jtc return -1; 2118 1.1 jtc } 2119 1.1 jtc x_print_expansions(nwords, words, is_command); 2120 1.1 jtc x_free_words(nwords, words); 2121 1.1 jtc redraw_line(0); 2122 1.1 jtc return 0; 2123 1.1 jtc } 2124 1.1 jtc 2125 1.1 jtc /* How long is char when displayed (not counting tabs) */ 2126 1.1 jtc static int 2127 1.1 jtc char_len(c) 2128 1.1 jtc int c; 2129 1.1 jtc { 2130 1.1 jtc int len = 1; 2131 1.1 jtc 2132 1.1 jtc if ((c & 0x80) && Flag(FVISHOW8)) { 2133 1.1 jtc len += 2; 2134 1.1 jtc c &= 0x7f; 2135 1.1 jtc } 2136 1.1 jtc if (c < ' ' || c == 0x7f) 2137 1.1 jtc len++; 2138 1.1 jtc return len; 2139 1.1 jtc } 2140 1.1 jtc 2141 1.6 wiz /* Similar to x_zotc(emacs.c), but no tab weirdness */ 2142 1.1 jtc static void 2143 1.1 jtc x_vi_zotc(c) 2144 1.1 jtc int c; 2145 1.1 jtc { 2146 1.1 jtc if (Flag(FVISHOW8) && (c & 0x80)) { 2147 1.1 jtc x_puts("M-"); 2148 1.1 jtc c &= 0x7f; 2149 1.1 jtc } 2150 1.1 jtc if (c < ' ' || c == 0x7f) { 2151 1.1 jtc x_putc('^'); 2152 1.1 jtc c ^= '@'; 2153 1.1 jtc } 2154 1.1 jtc x_putc(c); 2155 1.1 jtc } 2156 1.1 jtc 2157 1.1 jtc static void 2158 1.1 jtc vi_pprompt(full) 2159 1.1 jtc int full; 2160 1.1 jtc { 2161 1.1 jtc pprompt(prompt + (full ? 0 : prompt_skip), prompt_trunc); 2162 1.1 jtc } 2163 1.1 jtc 2164 1.1 jtc static void 2165 1.1 jtc vi_error() 2166 1.1 jtc { 2167 1.1 jtc /* Beem out of any macros as soon as an error occurs */ 2168 1.1 jtc vi_macro_reset(); 2169 1.1 jtc x_putc(BEL); 2170 1.1 jtc x_flush(); 2171 1.1 jtc } 2172 1.1 jtc 2173 1.1 jtc static void 2174 1.1 jtc vi_macro_reset() 2175 1.1 jtc { 2176 1.1 jtc if (macro.p) { 2177 1.1 jtc afree(macro.buf, APERM); 2178 1.1 jtc memset((char *) ¯o, 0, sizeof(macro)); 2179 1.1 jtc } 2180 1.1 jtc } 2181 1.1 jtc 2182 1.1 jtc #endif /* VI */ 2183