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; }
// // sequence::insert_worker // bool sequence::insert_worker (size_w index, const seqchar *buf, size_w length, action act) { span * sptr; size_w spanindex; size_t modbuf_offset; span_range newspans; size_w insoffset; if(index > sequence_length) return false; // find the span that the insertion starts at if((sptr = spanfromindex(index, &spanindex)) == 0) return false; // ensure there is room in the modify buffer... // allocate a new buffer if necessary and then invalidate span cache // to prevent a span using two buffers of data if(!import_buffer(buf, length, &modbuf_offset)) return false; debug("Inserting: idx=%d len=%d %.*s\n", index, length, length, buf); clearstack(redostack); insoffset = index - spanindex; // special-case #1: inserting at the end of a prior insertion, at a span-boundary if(insoffset == 0 && can_optimize(act, index)) { // simply extend the last span's length span_range *event = undostack.back(); sptr->prev->length += length; event->length += length; } // general-case #1: inserting at a span boundary? else if(insoffset == 0) { // // Create a new undo event; because we are inserting at a span // boundary there are no spans to replace, so use a "span boundary" // span_range *oldspans = initundo(index, length, act); oldspans->spanboundary(sptr->prev, sptr); // allocate new span in the modify buffer newspans.append(new span( modbuf_offset, length, modifybuffer_id) ); // link the span into the sequence swap_spanrange(oldspans, &newspans); } // general-case #2: inserting in the middle of a span else { // // Create a new undo event and add the span // that we will be "splitting" in half // span_range *oldspans = initundo(index, length, act); oldspans->append(sptr); // span for the existing data before the insertion newspans.append(new span( sptr->offset, insoffset, sptr->buffer) ); // make a span for the inserted data newspans.append(new span( modbuf_offset, length, modifybuffer_id) ); // span for the existing data after the insertion newspans.append(new span( sptr->offset + insoffset, sptr->length - insoffset, sptr->buffer) ); swap_spanrange(oldspans, &newspans); } sequence_length += length; return true; }
// // sequence::erase_worker // bool sequence::erase_worker (size_w index, size_w length, action act) { span *sptr; span_range oldspans; span_range newspans; span_range *event; size_w spanindex; size_w remoffset; size_w removelen; bool append_spanrange; debug("Erasing: idx=%d len=%d\n", index, length); // make sure we stay within the range of the sequence if(length == 0 || length > sequence_length || index > sequence_length - length) return false; // find the span that the deletion starts at if((sptr = spanfromindex(index, &spanindex)) == 0) return false; // work out the offset relative to the start of the *span* remoffset = index - spanindex; removelen = length; // // can we optimize? // // special-case 1: 'forward-delete' // erase+replace operations will pass through here // if(index == spanindex && can_optimize(act, index)) { event = stackback(undostack, act == action_replace ? 1 : 0); event->length += length; append_spanrange = true; if(frag2 != 0) { if(length < frag2->length) { frag2->length -= length; frag2->offset += length; sequence_length -= length; return true; } else { if(act == action_replace) stackback(undostack, 0)->last = frag2->next; removelen -= sptr->length; sptr = sptr->next; deletefromsequence(&frag2); } } } // // special-case 2: 'backward-delete' // only erase operations can pass through here // else if(index + length == spanindex + sptr->length && can_optimize(action_erase, index+length)) { event = undostack.back(); event->length += length; event->index -= length; append_spanrange = false; if(frag1 != 0) { if(length < frag1->length) { frag1->length -= length; frag1->offset += 0; sequence_length -= length; return true; } else { removelen -= frag1->length; deletefromsequence(&frag1); } } } else { append_spanrange = true; frag1 = frag2 = 0; if((event = initundo(index, length, act)) == 0) return false; } // // general-case 2+3 // clearstack(redostack); // does the deletion *start* mid-way through a span? if(remoffset != 0) { // split the span - keep the first "half" newspans.append(new span(sptr->offset, remoffset, sptr->buffer)); frag1 = newspans.first; // have we split a single span into two? // i.e. the deletion is completely within a single span if(remoffset + removelen < sptr->length) { // make a second span for the second half of the split newspans.append(new span( sptr->offset + remoffset + removelen, sptr->length - remoffset - removelen, sptr->buffer) ); frag2 = newspans.last; } removelen -= min(removelen, (sptr->length - remoffset)); // archive the span we are going to replace oldspans.append(sptr); sptr = sptr->next; } // we are now on a proper span boundary, so remove // any further spans that the erase-range encompasses while(removelen > 0 && sptr != tail) { // will the entire span be removed? if(removelen < sptr->length) { // split the span, keeping the last "half" newspans.append(new span( sptr->offset + removelen, sptr->length - removelen, sptr->buffer) ); frag2 = newspans.last; } removelen -= min(removelen, sptr->length); // archive the span we are replacing oldspans.append(sptr); sptr = sptr->next; } // for replace operations, update the undo-event for the // insertion so that it knows about the newly removed spans if(act == action_replace && !oldspans.boundary) stackback(undostack, 0)->last = oldspans.last->next; swap_spanrange(&oldspans, &newspans); sequence_length -= length; if(append_spanrange) event->append(&oldspans); else event->prepend(&oldspans); return true; }
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; }