📄 v_ntext.c
字号:
} /* 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 + -