Esempio n. 1
0
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;
}
Esempio n. 2
0
//
//	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;
}
Esempio n. 3
0
//
//	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;
}
Esempio n. 4
0
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;
}