📄 v_ntext.c
字号:
for (lno = tiqh->cqh_first->lno; file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno); sp->lno = lno == 0 ? 1 : lno; sp->cno = 0; /* Redraw the screen, just in case. */ F_SET(sp, S_REDRAW);}/* * txt_hex -- * Let the user insert any character value they want. * * !!! * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way * for the user to specify a character value which their keyboard * may not be able to enter. */static inttxt_hex(sp, tp) SCR *sp; TEXT *tp;{ CHAR_T savec; size_t len, off; u_long value; char *p, *wp; /* * Null-terminate the string. Since nul isn't a legal hex value, * this should be okay, and lets us use a local routine, which * presumably understands the character set, to convert the value. */ savec = tp->lb[sp->cno]; tp->lb[sp->cno] = 0; /* Find the previous CH_HEX character. */ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off, ++len) { if (*p == CH_HEX) { wp = p + 1; break; } /* Not on this line? Shouldn't happen. */ if (off == tp->ai || off == tp->offset) goto nothex; } /* If length of 0, then it wasn't a hex value. */ if (len == 0) goto nothex; /* Get the value. */ errno = 0; value = strtol(wp, NULL, 16); if (errno || value > MAX_CHAR_T) {nothex: tp->lb[sp->cno] = savec; return (0); } /* Restore the original character. */ tp->lb[sp->cno] = savec; /* Adjust the bookkeeping. */ sp->cno -= len; tp->len -= len; tp->lb[sp->cno - 1] = value; /* Copy down any overwrite characters. */ if (tp->owrite) memmove(tp->lb + sp->cno, tp->lb + sp->cno + len, tp->owrite); /* Copy down any insert characters. */ if (tp->insert) memmove(tp->lb + sp->cno + tp->owrite, tp->lb + sp->cno + tp->owrite + len, tp->insert); return (0);}/* * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements * to the next or previous shiftwidth value, i.e. for a 1-based numbering, * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to * the 10th column, and ^D moves it back. * * !!! * The ^T and ^D characters in historical vi only had special meaning when * they were the first characters typed after entering text input mode. * Since normal erase characters couldn't erase autoindent (in this case * ^T) characters, this meant that inserting text into previously existing * text was quite strange, ^T only worked if it was the first keystroke, * and then it could only be erased by using ^D. This implementation treats * ^T specially anywhere it occurs in the input, and permits the standard * erase characters to erase characters inserted using it. * * XXX * Technically, txt_indent, txt_outdent should part of the screen interface, * as they require knowledge of the size of a space character on the screen. * (Not the size of tabs, because tabs are logically composed of spaces.) * They're left in the text code because they're complicated, not to mention * the gruesome awareness that if spaces aren't a single column on the screen * for any language, we're into some serious, ah, for lack of a better word, * "issues". *//* * txt_indent -- * Handle ^T indents. */static inttxt_indent(sp, tp) SCR *sp; TEXT *tp;{ u_long sw, ts; size_t cno, off, scno, spaces, tabs; ts = O_VAL(sp, O_TABSTOP); sw = O_VAL(sp, O_SHIFTWIDTH); /* Get the current screen column. */ for (off = scno = 0; off < sp->cno; ++off) if (tp->lb[off] == '\t') scno += STOP_OFF(scno, ts); else ++scno; /* Count up spaces/tabs needed to get to the target. */ for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs) cno += STOP_OFF(cno, ts); spaces = scno - cno; /* Put space/tab characters in place of any overwrite characters. */ for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai) tp->lb[sp->cno++] = '\t'; for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai) tp->lb[sp->cno++] = ' '; if (!tabs && !spaces) return (0); /* Make sure there's enough room. */ BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs); /* Move the insert characters out of the way. */ if (tp->insert) memmove(tp->lb + sp->cno + spaces + tabs, tp->lb + sp->cno, tp->insert); /* Add new space/tab characters. */ for (; tabs--; ++tp->len, ++tp->ai) tp->lb[sp->cno++] = '\t'; for (; spaces--; ++tp->len, ++tp->ai) tp->lb[sp->cno++] = ' '; return (0);}/* * txt_outdent -- * Handle ^D outdents. * */static inttxt_outdent(sp, tp) SCR *sp; TEXT *tp;{ u_long sw, ts; size_t cno, off, scno, spaces; ts = O_VAL(sp, O_TABSTOP); sw = O_VAL(sp, O_SHIFTWIDTH); /* Get the current screen column. */ for (off = scno = 0; off < sp->cno; ++off) if (tp->lb[off] == '\t') scno += STOP_OFF(scno, ts); else ++scno; /* Get the previous shiftwidth column. */ for (cno = scno; --scno % sw != 0;); /* Decrement characters until less than or equal to that slot. */ for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite) if (tp->lb[--off] == '\t') cno -= STOP_OFF(cno, ts); else --cno; /* Spaces needed to get to the target. */ spaces = scno - cno; /* Maybe just a delete. */ if (spaces == 0) return (0); /* Make sure there's enough room. */ BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces); /* Use up any overwrite characters. */ for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite) tp->lb[sp->cno++] = ' '; /* Maybe that was enough. */ if (spaces == 0) return (0); /* Move the insert characters out of the way. */ if (tp->insert) memmove(tp->lb + sp->cno + spaces, tp->lb + sp->cno, tp->insert); /* Add new space characters. */ for (; spaces--; ++tp->len, ++tp->ai) tp->lb[sp->cno++] = ' '; return (0);}/* * txt_resolve -- * Resolve the input text chain into the file. */static inttxt_resolve(sp, ep, tiqh, flags) SCR *sp; EXF *ep; TEXTH *tiqh; u_int flags;{ TEXT *tp; recno_t lno; /* * The first line replaces a current line, and all subsequent lines * are appended into the file. Resolve autoindented characters for * each line before committing it. */ tp = tiqh->cqh_first; if (LF_ISSET(TXT_AUTOINDENT)) txt_ai_resolve(sp, tp); if (file_sline(sp, ep, tp->lno, tp->lb, tp->len)) return (1); for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)sp->tiqp; ++lno) { if (LF_ISSET(TXT_AUTOINDENT)) txt_ai_resolve(sp, tp); if (file_aline(sp, ep, 0, lno, tp->lb, tp->len)) return (1); } return (0);}/* * txt_showmatch -- * Show a character match. * * !!! * Historic vi tried to display matches even in the :colon command line. * I think not. */static voidtxt_showmatch(sp, ep) SCR *sp; EXF *ep;{ struct timeval second; VCS cs; MARK m; fd_set zero; int cnt, endc, startc; /* * Do a refresh first, in case the v_ntext() code hasn't done * one in awhile, so the user can see what we're complaining * about. */ if (sp->s_refresh(sp, ep)) return; /* * We don't display the match if it's not on the screen. Find * out what the first character on the screen is. */ if (sp->s_position(sp, ep, &m, 0, P_TOP)) return; /* Initialize the getc() interface. */ cs.cs_lno = sp->lno; cs.cs_cno = sp->cno - 1; if (cs_init(sp, ep, &cs)) return; startc = (endc = cs.cs_ch) == ')' ? '(' : '{'; /* Search for the match. */ for (cnt = 1;;) { if (cs_prev(sp, ep, &cs)) return; if (cs.cs_lno < m.lno || cs.cs_lno == m.lno && cs.cs_cno < m.cno) return; if (cs.cs_flags != 0) { if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) { (void)sp->s_bell(sp); return; } continue; } if (cs.cs_ch == endc) ++cnt; else if (cs.cs_ch == startc && --cnt == 0) break; } /* Move to the match. */ m.lno = sp->lno; m.cno = sp->cno; sp->lno = cs.cs_lno; sp->cno = cs.cs_cno; (void)sp->s_refresh(sp, ep); /* * Sleep(3) is eight system calls. Do it fast -- besides, * I don't want to wait an entire second. */ FD_ZERO(&zero); second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10; second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L; (void)select(0, &zero, &zero, &zero, &second); /* Return to the current location. */ sp->lno = m.lno; sp->cno = m.cno; (void)sp->s_refresh(sp, ep);}/* * txt_margin -- * Handle margin wrap. * * !!! * Historic vi belled the user each time a character was entered after * crossing the margin until a space was entered which could be used to * break the line. I don't, it tends to wake the cats. */static inttxt_margin(sp, tp, didbreak, pushcp) SCR *sp; TEXT *tp; int *didbreak; CHAR_T *pushcp;{ CHAR_T ch; size_t len, off, tlen; char *p, *wp; /* Find the closest previous blank. */ for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) { if (isblank(*p)) { wp = p + 1; break; } ++len; /* If it's the beginning of the line, there's nothing to do. */ if (off == tp->ai || off == tp->offset) { *didbreak = 0; return (0); } } /* * Historic practice is to delete any trailing whitespace * from the previous line. */ for (tlen = len;; --p, --off) { if (!isblank(*p)) break; ++tlen; if (off == tp->ai || off == tp->offset) break; } ch = *pushcp; if (term_push(sp, &ch, 1, 0, CH_NOMAP)) return (1); if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED)) return (1); ch = '\n'; if (term_push(sp, &ch, 1, 0, CH_NOMAP)) return (1); sp->cno -= tlen; tp->owrite += tlen; *didbreak = 1; return (0);}/* * txt_Rcleanup -- * Resolve the input line for the 'R' command. */static voidtxt_Rcleanup(sp, tiqh, tp, lp, olen) SCR *sp; TEXTH *tiqh; TEXT *tp; const char *lp; const size_t olen;{ TEXT *ttp; size_t ilen, tmp; /* * Check to make sure that the cursor hasn't moved beyond * the end of the line. */ if (tp->owrite == 0) return; /* * Calculate how many characters the user has entered, * plus the blanks erased by <carriage-return>/<newline>s. */ for (ttp = tiqh->cqh_first, ilen = 0;;) { ilen += ttp == tp ? sp->cno : ttp->len + ttp->R_erase; if ((ttp = ttp->q.cqe_next) == (void *)sp->tiqp) break; } /* * If the user has entered less characters than the original line * was long, restore any overwriteable characters to the original * characters, and make them insert characters. We don't copy them * anywhere, because the 'R' command doesn't have insert characters. */ if (ilen < olen) { tmp = MIN(tp->owrite, olen - ilen); memmove(tp->lb + sp->cno, lp + ilen, tmp); tp->owrite -= tmp; tp->insert += tmp; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -