Thingy executenamedcommand(char *prmt) { Thingy cmd, retval = NULL; int l, len, feep = 0, listed = 0, curlist = 0; int ols = (listshown && validlist), olll = lastlistlen; char *cmdbuf, *ptr; char *okeymap = ztrdup(curkeymapname); clearlist = 1; /* prmt may be constant */ prmt = ztrdup(prmt); l = strlen(prmt); cmdbuf = (char *)zhalloc(l + NAMLEN + 2 #ifdef MULTIBYTE_SUPPORT + 2 * MB_CUR_MAX #endif ); strcpy(cmdbuf, prmt); zsfree(prmt); statusline = cmdbuf; selectlocalmap(command_keymap); selectkeymap("main", 1); ptr = cmdbuf += l; len = 0; for (;;) { *ptr = '_'; ptr[1] = '\0'; zrefresh(); if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) { statusline = NULL; selectkeymap(okeymap, 1); zsfree(okeymap); if ((listshown = ols)) { showinglist = -2; lastlistlen = olll; } else if (listed) clearlist = listshown = 1; retval = NULL; goto done; } if(cmd == Th(z_clearscreen)) { clearscreen(zlenoargs); if (curlist) { int zmultsav = zmult; zmult = 1; listlist(namedcmdll); showinglist = 0; zmult = zmultsav; } } else if(cmd == Th(z_redisplay)) { redisplay(zlenoargs); if (curlist) { int zmultsav = zmult; zmult = 1; listlist(namedcmdll); showinglist = 0; zmult = zmultsav; } } else if(cmd == Th(z_viquotedinsert)) { *ptr = '^'; zrefresh(); getfullchar(0); if(LASTFULLCHAR == ZLEEOF || !LASTFULLCHAR || len >= NAMLEN) feep = 1; else { int ret = zlecharasstring(LASTFULLCHAR, ptr); len += ret; ptr += ret; curlist = 0; } } else if(cmd == Th(z_quotedinsert)) { if(getfullchar(0) == ZLEEOF || !LASTFULLCHAR || len == NAMLEN) feep = 1; else { int ret = zlecharasstring(LASTFULLCHAR, ptr); len += ret; ptr += ret; curlist = 0; } } else if(cmd == Th(z_backwarddeletechar) || cmd == Th(z_vibackwarddeletechar)) { if (len) { ptr = backwardmetafiedchar(cmdbuf, ptr, NULL); len = ptr - cmdbuf; curlist = 0; } } else if(cmd == Th(z_killregion) || cmd == Th(z_backwardkillword) || cmd == Th(z_vibackwardkillword)) { if (len) curlist = 0; while (len) { convchar_t cc; ptr = backwardmetafiedchar(cmdbuf, ptr, &cc); len = ptr - cmdbuf; if (cc == ZWC('-')) break; } } else if(cmd == Th(z_killwholeline) || cmd == Th(z_vikillline) || cmd == Th(z_backwardkillline)) { len = 0; ptr = cmdbuf; if (listed) clearlist = listshown = 1; curlist = 0; } else if (cmd == Th(z_bracketedpaste)) { char *insert = bracketedstring(); size_t inslen = strlen(insert); if (len + inslen > NAMLEN) feep = 1; else { strcpy(ptr, insert); len += inslen; ptr += inslen; if (listed) { clearlist = listshown = 1; listed = 0; } else curlist = 0; } free(insert); } else { if(cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) { Thingy r; unambiguous: *ptr = 0; r = rthingy(cmdbuf); if (!(r->flags & DISABLED)) { unrefthingy(r); statusline = NULL; selectkeymap(okeymap, 1); zsfree(okeymap); if ((listshown = ols)) { showinglist = -2; lastlistlen = olll; } else if (listed) clearlist = listshown = 1; retval = r; goto done; } unrefthingy(r); } if(cmd == Th(z_selfinsertunmeta)) { fixunmeta(); cmd = Th(z_selfinsert); } if (cmd == Th(z_listchoices) || cmd == Th(z_deletecharorlist) || cmd == Th(z_expandorcomplete) || cmd == Th(z_completeword) || cmd == Th(z_expandorcompleteprefix) || cmd == Th(z_vicmdmode) || cmd == Th(z_acceptline) || lastchar == ' ' || lastchar == '\t') { namedcmdambig = 100; namedcmdll = newlinklist(); *ptr = '\0'; namedcmdstr = cmdbuf; scanhashtable(thingytab, 1, 0, DISABLED, scancompcmd, 0); namedcmdstr = NULL; if (empty(namedcmdll)) { feep = 1; if (listed) clearlist = listshown = 1; curlist = 0; } else if (cmd == Th(z_listchoices) || cmd == Th(z_deletecharorlist)) { int zmultsav = zmult; *ptr = '_'; ptr[1] = '\0'; zmult = 1; listlist(namedcmdll); listed = curlist = 1; showinglist = 0; zmult = zmultsav; } else if (!nextnode(firstnode(namedcmdll))) { strcpy(ptr = cmdbuf, peekfirst(namedcmdll)); len = strlen(ptr); ptr += len; if (cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) goto unambiguous; } else { strcpy(cmdbuf, peekfirst(namedcmdll)); ptr = cmdbuf + namedcmdambig; *ptr = '_'; ptr[1] = '\0'; if (isset(AUTOLIST) && !(isset(LISTAMBIGUOUS) && namedcmdambig > len)) { int zmultsav = zmult; if (isset(LISTBEEP)) feep = 1; zmult = 1; listlist(namedcmdll); listed = curlist = 1; showinglist = 0; zmult = zmultsav; } len = namedcmdambig; } } else { if (len == NAMLEN || cmd != Th(z_selfinsert)) feep = 1; else { #ifdef MULTIBYTE_SUPPORT if (!lastchar_wide_valid) getrestchar(lastchar, NULL, NULL); if (lastchar_wide == WEOF) feep = 1; else #endif if (ZC_icntrl(LASTFULLCHAR)) feep = 1; else { int ret = zlecharasstring(LASTFULLCHAR, ptr); len += ret; ptr += ret; if (listed) { clearlist = listshown = 1; listed = 0; } else curlist = 0; } } } } if (feep) handlefeep(zlenoargs); feep = 0; } done: selectlocalmap(NULL); return retval; }
char * zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) { char *s, **bracket; int old_errno = errno; int tmout = getiparam("TMOUT"); #if defined(HAVE_POLL) || defined(HAVE_SELECT) /* may not be set, but that's OK since getiparam() returns 0 == off */ baud = getiparam("BAUD"); costmult = (baud) ? 3840000L / baud : 0; #endif /* ZLE doesn't currently work recursively. This is needed in case a * * select loop is used in a function called from ZLE. vared handles * * this differently itself. */ if(zleactive) { char *pptbuf; int pptlen; pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL, &pmpt_attr), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); return shingetline(); } /* * The current status is what we need if we are going * to display a prompt. We'll remember it here for * use further in. */ pre_zle_status = lastval; keytimeout = (time_t)getiparam("KEYTIMEOUT"); if (!shout) { if (SHTTY != -1) init_shout(); if (!shout) return NULL; /* We could be smarter and default to a system read. */ /* If we just got a new shout, make sure the terminal is set up. */ if (termflags & TERM_UNKNOWN) init_term(); } fflush(shout); fflush(stderr); intr(); insmode = unset(OVERSTRIKE); eofsent = 0; resetneeded = 0; fetchttyinfo = 0; trashedzle = 0; raw_lp = lp; lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL, &pmpt_attr); raw_rp = rp; rpmpt_attr = pmpt_attr; rpromptbuf = promptexpand(rp ? *rp : NULL, 1, NULL, NULL, &rpmpt_attr); free_prepostdisplay(); zlereadflags = flags; zlecontext = context; histline = curhist; vistartchange = -1; zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE); *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = 0; vichgflag = 0; viinsbegin = 0; statusline = NULL; selectkeymap("main", 1); initundo(); fixsuffix(); if ((s = getlinknode(bufstack))) { setline(s, ZSL_TOEND); zsfree(s); if (stackcs != -1) { zlecs = stackcs; stackcs = -1; if (zlecs > zlell) zlecs = zlell; CCLEFT(); } if (stackhist != -1) { histline = stackhist; stackhist = -1; } handleundo(); } /* * If main is linked to the viins keymap, we need to register * explicitly that we're now in vi insert mode as there's * no user operation to indicate this. */ if (openkeymap("main") == openkeymap("viins")) viinsert_init(); selectlocalmap(NULL); if (isset(PROMPTCR)) putc('\r', shout); if (tmout) alarm(tmout); /* * On some windowing systems we may enter this function before the * terminal is fully opened and sized, resulting in an infinite * series of SIGWINCH when the handler prints the prompt before we * have done so here. Therefore, hold any such signal until the * first full refresh has completed. The important bit is that the * handler must not see zleactive = 1 until ZLE really is active. * See the end of adjustwinsize() in Src/utils.c */ queue_signals(); zleactive = 1; resetneeded = 1; /* * Start of the main zle read. * Fully reset error conditions, including user interrupt. */ errflag = retflag = 0; lastcol = -1; initmodifier(&zmod); prefixflag = 0; zrefresh(); unqueue_signals(); /* Should now be safe to acknowledge SIGWINCH */ zlecallhook(init, NULL); if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) fputs(*bracket, shout); zrefresh(); zlecore(); if (errflag) setsparam((zlecontext == ZLCON_VARED) ? "ZLE_VARED_ABORTED" : "ZLE_LINE_ABORTED", zlegetline(NULL, NULL)); if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) fputs(bracket[1], shout); if (done && !exit_pending && !errflag) zlecallhook(finish, NULL); statusline = NULL; invalidatelist(); trashzle(); free(lpromptbuf); free(rpromptbuf); zleactive = zlereadflags = lastlistlen = zlecontext = 0; alarm(0); freeundo(); if (eofsent || errflag || exit_pending) { s = NULL; } else { zleline[zlell++] = ZWC('\n'); s = zlegetline(NULL, NULL); } free(zleline); zleline = NULL; forget_edits(); errno = old_errno; /* highlight no longer valid */ set_region_highlight(NULL, NULL); return s; }
static int getvirange(int wf) { int pos = zlecs, mpos = mark, ret = 0; int visual = region_active; /* movement command might set it */ int mult1 = zmult, hist1 = histline; Thingy k2; if (visual) { pos = mark; vilinerange = (visual == 2); region_active = 0; } else { virangeflag = 1; wordflag = wf; mark = -1; /* use operator-pending keymap if one exists */ Keymap km = openkeymap("viopp"); if (km) selectlocalmap(km); /* Now we need to execute the movement command, to see where it * * actually goes. virangeflag here indicates to the movement * * function that it should place the cursor at the end of the * * range, rather than where the cursor would actually go if it * * were executed normally. This makes a difference to some * * commands, but not all. For example, if searching forward * * for a character, under normal circumstances the cursor lands * * on the character. For a range, the range must include the * * character, so the cursor gets placed after the character if * * virangeflag is set. vi-match-bracket needs to change the * * value of virangeflag under some circumstances, meaning that * * we need to change the *starting* position. */ zmod.flags &= ~MOD_TMULT; do { vilinerange = 0; prefixflag = 0; if (!(k2 = getkeycmd()) || (k2->flags & DISABLED) || k2 == Th(z_sendbreak)) { wordflag = 0; virangeflag = 0; mark = mpos; return -1; } /* * With k2 == bindk, the command key is repeated: * a number of lines is used. If the function used * returns 1, we fail. */ if ((k2 == bindk) ? dovilinerange() : execzlefunc(k2, zlenoargs, 1)) ret = -1; if(vichgrepeat) zmult = mult1; else zmult = mult1 * zmod.tmult; } while(prefixflag && !ret); wordflag = 0; selectlocalmap(NULL); /* It is an error to use a non-movement command to delimit the * * range. We here reject the case where the command modified * * the line, or selected a different history line. */ if (histline != hist1 || zlell != lastll || memcmp(zleline, lastline, zlell)) { histline = hist1; ZS_memcpy(zleline, lastline, zlell = lastll); zlecs = pos; mark = mpos; return -1; } /* Can't handle an empty file. Also, if the movement command * * failed, or didn't move, it is an error. */ if (!zlell || (zlecs == pos && mark == -1 && virangeflag != 2) || ret == -1) { mark = mpos; return -1; } /* vi-match-bracket changes the value of virangeflag when * * moving to the opening bracket, meaning that we need to * * change the *starting* position. */ if (virangeflag == -1) INCPOS(pos); virangeflag = 0; /* if the mark has moved, ignore the original cursor position * * and use the mark. */ if (mark != -1) pos = mark; } mark = mpos; /* Get the range the right way round. zlecs is placed at the * * start of the range, and pos (the return value of this * * function) is the end. */ if (zlecs > pos) { int tmp = zlecs; zlecs = pos; pos = tmp; } /* visual selection mode needs to include additional position */ if (visual == 1 && invicmdmode()) INCPOS(pos); /* Was it a line-oriented move? If so, the command will have set * * the vilinerange flag. In this case, entire lines are taken, * * rather than just the sequence of characters delimited by pos * * and zlecs. The terminating newline is left out of the range, * * which the real command must deal with appropriately. At this * * point we just need to make the range encompass entire lines. */ if(vilinerange) { int newcs = findbol(); lastcol = zlecs - newcs; zlecs = pos; pos = findeol(); zlecs = newcs; } return pos; }
void zlecore(void) { Keymap km; #if !defined(HAVE_POLL) && defined(HAVE_SELECT) struct timeval tv; fd_set foofd; FD_ZERO(&foofd); #endif pushheap(); /* * A widget function may decide to exit the shell. * We never exit directly from functions, to allow * the shell to tidy up, so we have to test for * that explicitly. */ while (!done && !errflag && !exit_pending) { UNMETACHECK(); statusline = NULL; vilinerange = 0; reselectkeymap(); selectlocalmap(invicmdmode() && region_active && (km = openkeymap("visual")) ? km : NULL); bindk = getkeycmd(); selectlocalmap(NULL); if (bindk) { if (!zlell && isfirstln && !(zlereadflags & ZLRF_IGNOREEOF) && lastchar == eofchar) { /* * Slight hack: this relies on getkeycmd returning * a value for the EOF character. However, * undefined-key is fine. That's necessary because * otherwise we can't distinguish this case from * a ^C. */ eofsent = 1; break; } if (execzlefunc(bindk, zlenoargs, 0)) { handlefeep(zlenoargs); if (eofsent) break; } handleprefixes(); /* for vi mode, make sure the cursor isn't somewhere illegal */ if (invicmdmode() && zlecs > findbol() && (zlecs == zlell || zleline[zlecs] == ZWC('\n'))) DECCS(); handleundo(); } else { errflag |= ERRFLAG_ERROR; break; } #ifdef HAVE_POLL if (baud && !(lastcmd & ZLE_MENUCMP)) { struct pollfd pfd; int to = cost * costmult / 1000; /* milliseconds */ if (to > 500) to = 500; pfd.fd = SHTTY; pfd.events = POLLIN; if (!kungetct && poll(&pfd, 1, to) <= 0) zrefresh(); } else #else # ifdef HAVE_SELECT if (baud && !(lastcmd & ZLE_MENUCMP)) { FD_SET(SHTTY, &foofd); tv.tv_sec = 0; if ((tv.tv_usec = cost * costmult) > 500000) tv.tv_usec = 500000; if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd, NULL, NULL, &tv) <= 0) zrefresh(); } else # endif #endif if (!kungetct) zrefresh(); freeheap(); } region_active = 0; popheap(); }
char * zleread(char **lp, char **rp, int flags, int context) { char *s; int old_errno = errno; int tmout = getiparam("TMOUT"); #if defined(HAVE_POLL) || defined(HAVE_SELECT) /* may not be set, but that's OK since getiparam() returns 0 == off */ baud = getiparam("BAUD"); costmult = (baud) ? 3840000L / baud : 0; #endif /* ZLE doesn't currently work recursively. This is needed in case a * * select loop is used in a function called from ZLE. vared handles * * this differently itself. */ if(zleactive) { char *pptbuf; int pptlen; pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL, &pmpt_attr), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); return shingetline(); } /* * The current status is what we need if we are going * to display a prompt. We'll remember it here for * use further in. */ pre_zle_status = lastval; keytimeout = (time_t)getiparam("KEYTIMEOUT"); if (!shout) { if (SHTTY != -1) init_shout(); if (!shout) return NULL; /* We could be smarter and default to a system read. */ /* If we just got a new shout, make sure the terminal is set up. */ if (termflags & TERM_UNKNOWN) init_term(); } fflush(shout); fflush(stderr); intr(); insmode = unset(OVERSTRIKE); eofsent = 0; resetneeded = 0; fetchttyinfo = 0; trashedzle = 0; raw_lp = lp; lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL, &pmpt_attr); raw_rp = rp; rpmpt_attr = pmpt_attr; rpromptbuf = promptexpand(rp ? *rp : NULL, 1, NULL, NULL, &rpmpt_attr); free_prepostdisplay(); zlereadflags = flags; zlecontext = context; histline = curhist; undoing = 1; zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE); *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = 0; vichgflag = 0; viinsbegin = 0; statusline = NULL; selectkeymap("main", 1); selectlocalmap(NULL); fixsuffix(); if ((s = getlinknode(bufstack))) { setline(s, ZSL_TOEND); zsfree(s); if (stackcs != -1) { zlecs = stackcs; stackcs = -1; if (zlecs > zlell) zlecs = zlell; CCLEFT(); } if (stackhist != -1) { histline = stackhist; stackhist = -1; } } initundo(); if (isset(PROMPTCR)) putc('\r', shout); if (tmout) alarm(tmout); zleactive = 1; resetneeded = 1; errflag = retflag = 0; lastcol = -1; initmodifier(&zmod); prefixflag = 0; zrefresh(); zlecallhook("zle-line-init", NULL); zlecore(); if (errflag) setsparam("ZLE_LINE_ABORTED", zlegetline(NULL, NULL)); if (done && !exit_pending && !errflag) zlecallhook("zle-line-finish", NULL); statusline = NULL; invalidatelist(); trashzle(); free(lpromptbuf); free(rpromptbuf); zleactive = zlereadflags = lastlistlen = zlecontext = 0; alarm(0); freeundo(); if (eofsent) { s = NULL; } else { zleline[zlell++] = ZWC('\n'); s = zlegetline(NULL, NULL); } free(zleline); zleline = NULL; forget_edits(); errno = old_errno; /* highlight no longer valid */ set_region_highlight(NULL, NULL); return s; }