⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 v_ntext.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
			}			/* Check to see if we've crossed the margin. */			if (margin) {				if (sp->s_column(sp, ep, &col))					goto err;				if (col >= margin) {					if (txt_margin(sp, tp, &tmp, &ch))						goto err;					if (tmp)						goto next_ch;				}			}			if (abb != A_NOTSET)				abb = inword(ch) ? A_INWORD : A_NOTWORD;			if (tp->owrite)		/* Overwrite a character. */				--tp->owrite;			else if (tp->insert) {	/* Insert a character. */				++tp->len;				if (tp->insert == 1)					tp->lb[sp->cno + 1] = tp->lb[sp->cno];				else					memmove(tp->lb + sp->cno + 1,					    tp->lb + sp->cno, tp->insert);			}			tp->lb[sp->cno++] = ch;			/*			 * If we've reached the end of the buffer, then we			 * need to switch into insert mode.  This happens			 * when there's a change to a mark and the user puts			 * in more characters than the length of the motion.			 */ebuf_chk:		if (sp->cno >= tp->len) {				BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);				LF_SET(TXT_APPENDEOL);				tp->lb[sp->cno] = CH_CURSOR;				++tp->insert;				++tp->len;			}			if (hex == H_NEXTCHAR)				hex = H_INHEX;			if (quoted == Q_NEXTCHAR)				quoted = Q_THISCHAR;			break;		}#if defined(DEBUG) && 1		if (sp->cno + tp->insert + tp->owrite != tp->len)			msgq(sp, M_ERR,			    "len %u != cno: %u ai: %u insert %u overwrite %u",			    tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);		tp->len = sp->cno + tp->insert + tp->owrite;#endif	}	/* Clear input flag. */ret:	F_CLR(sp, S_INPUT);	if (LF_ISSET(TXT_RECORD))		VIP(sp)->rep_cnt = rcol;	return (eval);err:	/* Error jumps. */binc_err:	eval = 1;	txt_err(sp, ep, tiqh);	goto ret;}/* * txt_abbrev -- *	Handle abbreviations. */static inttxt_abbrev(sp, tp, pushcp, isinfoline, didsubp, turnoffp)	SCR *sp;	TEXT *tp;	CHAR_T *pushcp;	int isinfoline, *didsubp, *turnoffp;{	CHAR_T ch;	SEQ *qp;	size_t len, off;	char *p;	/*	 * Find the start of the "word".  Historically, abbreviations	 * could be preceded by any non-word character.	 */	for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {		if (!inword(*p)) {			++p;			break;		}		++len;		if (off == tp->ai || off == tp->offset)			break;	}	/*	 * !!!	 * Historic vi exploded abbreviations on the command line.  This has	 * obvious problems in that unabbreviating the string can be extremely	 * tricky, particularly if the string has, say, an embedded escape	 * character.  Personally, I think it's a stunningly bad idea.  Other	 * examples of problems this caused in historic vi are:	 *	:ab foo bar	 *	:ab foo baz	 * results in "bar" being abbreviated to "baz", which wasn't what the	 * user had in mind at all.  Also, the commands:	 *	:ab foo bar	 *	:unab foo<space>	 * resulted in an error message that "bar" wasn't mapped.  Finally,	 * since the string was already exploded by the time the unabbreviate	 * command got it, all it knew was that an abbreviation had occurred.	 * Cleverly, it checked the replacement string for its unabbreviation	 * match, which meant that the commands:	 *	:ab foo1 bar	 *	:ab foo2 bar	 *	:unab foo2	 * unabbreviates "foo1", and the commands:	 *	:ab foo bar	 *	:ab bar baz	 * unabbreviates "foo"!	 *	 * Anyway, people neglected to first ask my opinion before they wrote	 * macros that depend on this stuff, so, we make this work as follows.	 * When checking for an abbreviation on the command line, if we get a	 * string which is <blank> terminated and which starts at the beginning	 * of the line, we check to see it is the abbreviate or unabbreviate	 * commands.  If it is, turn abbreviations off and return as if no	 * abbreviation was found.  Note also, minor trickiness, so that if	 * the user erases the line and starts another command, we turn the	 * abbreviations back on.	 *	 * This makes the layering look like a Nachos Supreme.	 */	*didsubp = 0;	if (isinfoline)		if (off == tp->ai || off == tp->offset)			if (ex_is_abbrev(p, len)) {				*turnoffp = 1;				return (0);			} else				*turnoffp = 0;		else			if (*turnoffp)				return (0);	/* Check for any abbreviations. */	if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)		return (0);	/*	 * Push the abbreviation onto the tty stack.  Historically, characters	 * resulting from an abbreviation expansion were themselves subject to	 * map expansions, O_SHOWMATCH matching etc.  This means the expanded	 * characters will be re-tested for abbreviations.  It's difficult to	 * know what historic practice in this case was, since abbreviations	 * were applied to :colon command lines, so entering abbreviations that	 * looped was tricky, although possible.  In addition, obvious loops	 * didn't work as expected.  (The command ':ab a b|ab b c|ab c a' will	 * silently only implement and/or display the last abbreviation.)	 *	 * This implementation doesn't recover well from such abbreviations.	 * The main input loop counts abbreviated characters, and, when it	 * reaches a limit, discards any abbreviated characters on the queue.	 * It's difficult to back up to the original position, as the replay	 * queue would have to be adjusted, and the line state when an initial	 * abbreviated character was received would have to be saved.	 */	ch = *pushcp;	if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))		return (1);	if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))		return (1);	/* Move to the start of the abbreviation, adjust the length. */	sp->cno -= len;	tp->len -= len;	/* Copy any insert characters back. */	if (tp->insert)		memmove(tp->lb + sp->cno + tp->owrite,		    tp->lb + sp->cno + tp->owrite + len, tp->insert);	/*	 * We return the length of the abbreviated characters.  This is so	 * the calling routine can replace the replay characters with the	 * abbreviation.  This means that subsequent '.' commands will produce	 * the same text, regardless of intervening :[un]abbreviate commands.	 * This is historic practice.	 */	*didsubp = len;	return (0);}/* * txt_unmap -- *	Handle the unmap command. */static voidtxt_unmap(sp, tp, iflagsp)	SCR *sp;	TEXT *tp;	u_int *iflagsp;{	size_t len, off;	char *p;	/* Find the beginning of this "word". */	for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {		if (isblank(*p)) {			++p;			break;		}		++len;		if (off == tp->ai || off == tp->offset)			break;	}	/*	 * !!!	 * Historic vi exploded input mappings on the command line.  See the	 * txt_abbrev() routine for an explanation of the problems inherent	 * in this.	 *	 * We make this work as follows.  If we get a string which is <blank>	 * terminated and which starts at the beginning of the line, we check	 * to see it is the unmap command.  If it is, we return that the input	 * mapping should be turned off.  Note also, minor trickiness, so that	 * if the user erases the line and starts another command, we go ahead	 * an turn mapping back on.	 */	if ((off == tp->ai || off == tp->offset) && ex_is_unmap(p, len))		*iflagsp &= ~TXT_MAPINPUT;	else		*iflagsp |= TXT_MAPINPUT;}/* * txt_ai_resolve -- *	When a line is resolved by <esc> or <cr>, review autoindent *	characters. */static voidtxt_ai_resolve(sp, tp)	SCR *sp;	TEXT *tp;{	u_long ts;	int del;	size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;	char *p;	/*	 * If the line is empty, has an offset, or no autoindent	 * characters, we're done.	 */	if (!tp->len || tp->offset || !tp->ai)		return;	/*	 * If the length is less than or equal to the autoindent	 * characters, delete them.	 */	if (tp->len <= tp->ai) {		tp->len = tp->ai = 0;		return;	}	/*	 * The autoindent characters plus any leading <blank> characters	 * in the line are resolved into the minimum number of characters.	 * Historic practice.	 */	ts = O_VAL(sp, O_TABSTOP);	/* Figure out the last <blank> screen column. */	for (p = tp->lb, scno = 0, len = tp->len,	    spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)		if (*p == '\t') {			if (spaces)				tab_after_sp = 1;			scno += STOP_OFF(scno, ts);		} else {			++spaces;			++scno;		}	/*	 * If there are no spaces, or no tabs after spaces and less than	 * ts spaces, it's already minimal.	 */	if (!spaces || !tab_after_sp && spaces < ts)		return;	/* Count up spaces/tabs needed to get to the target. */	for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)		cno += STOP_OFF(cno, ts);	spaces = scno - cno;	/*	 * Figure out how many characters we're dropping -- if we're not	 * dropping any, it's already minimal, we're done.	 */	old = p - tp->lb;	new = spaces + tabs;	if (old == new)		return;	/* Shift the rest of the characters down, adjust the counts. */	del = old - new;	memmove(p - del, p, tp->len - old);	tp->len -= del;	/* If the cursor was on this line, adjust it as well. */	if (sp->lno == tp->lno)		sp->cno -= del;	/* Fill in space/tab characters. */	for (p = tp->lb; tabs--;)		*p++ = '\t';	while (spaces--)		*p++ = ' ';}/* * txt_auto -- *	Handle autoindent.  If aitp isn't NULL, use it, otherwise, *	retrieve the line. */inttxt_auto(sp, ep, lno, aitp, len, tp)	SCR *sp;	EXF *ep;	recno_t lno;	size_t len;	TEXT *aitp, *tp;{	size_t nlen;	char *p, *t;	if (aitp == NULL) {		if ((t = file_gline(sp, ep, lno, &len)) == NULL)			return (0);	} else		t = aitp->lb;	/* Count whitespace characters. */	for (p = t; len > 0; ++p, --len)		if (!isblank(*p))			break;	/* Set count, check for no indentation. */	if ((nlen = (p - t)) == 0)		return (0);	/* Make sure the buffer's big enough. */	BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);	/* Copy the buffer's current contents up. */	if (tp->len != 0)		memmove(tp->lb + nlen, tp->lb, tp->len);	tp->len += nlen;	/* Copy the indentation into the new buffer. */	memmove(tp->lb, t, nlen);	/* Set the autoindent count. */	tp->ai = nlen;	return (0);}/* * txt_backup -- *	Back up to the previously edited line. */static TEXT *txt_backup(sp, ep, tiqh, tp, flagsp)	SCR *sp;	EXF *ep;	TEXTH *tiqh;	TEXT *tp;	u_int *flagsp;{	TEXT *ntp;	u_int flags;	/* Get a handle on the previous TEXT structure. */	if ((ntp = tp->q.cqe_prev) == (void *)tiqh) {		msgq(sp, M_BERR, "Already at the beginning of the insert");		return (tp);	}	/* Reset the cursor, bookkeeping. */	sp->lno = ntp->lno;	sp->cno = ntp->sv_cno;	ntp->len = ntp->sv_len;	/* Handle appending to the line. */	flags = *flagsp;	if (ntp->owrite == 0 && ntp->insert == 0) {		ntp->lb[ntp->len] = CH_CURSOR;		++ntp->insert;		++ntp->len;		LF_SET(TXT_APPENDEOL);	} else		LF_CLR(TXT_APPENDEOL);	*flagsp = flags;	/* Release the current TEXT. */	CIRCLEQ_REMOVE(tiqh, tp, q);	text_free(tp);	/* Update the old line on the screen. */	if (sp->s_change(sp, ep, ntp->lno + 1, LINE_DELETE))		return (NULL);	/* Return the new/current TEXT. */	return (ntp);}/* * txt_err -- *	Handle an error during input processing. */static voidtxt_err(sp, ep, tiqh)	SCR *sp;	EXF *ep;	TEXTH *tiqh;{	recno_t lno;	size_t len;	/*	 * The problem with input processing is that the cursor is at an	 * indeterminate position since some input may have been lost due	 * to a malloc error.  So, try to go back to the place from which	 * the cursor started, knowing that it may no longer be available.	 *	 * We depend on at least one line number being set in the text	 * chain.	 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -