📄 v_ntext.c
字号:
/* Update the old line. */ if (sp->s_change(sp, ep, tp->lno, LINE_RESET)) goto err; /* * Historic practice was to delete <blank> characters * following the inserted newline. This affected the * 'R', 'c', and 's' commands; 'c' and 's' retained * the insert characters only, 'R' moved overwrite and * insert characters into the next TEXT structure. * All other commands simply deleted the overwrite * characters. We have to keep track of the number of * characters erased for the 'R' command so that we * can get the final resolution of the line correct. */ tp->R_erase = 0; owrite = tp->owrite; insert = tp->insert; if (LF_ISSET(TXT_REPLACE) && owrite != 0) { for (p = tp->lb + sp->cno; owrite > 0 && isblank(*p); ++p, --owrite, ++tp->R_erase); if (owrite == 0) for (; insert > 0 && isblank(*p); ++p, ++tp->R_erase, --insert); } else { for (p = tp->lb + sp->cno + owrite; insert > 0 && isblank(*p); ++p, --insert); owrite = 0; } /* Set up bookkeeping for the new line. */ if ((ntp = text_init(sp, p, insert + owrite, insert + owrite + 32)) == NULL) goto err; ntp->insert = insert; ntp->owrite = owrite; ntp->lno = tp->lno + 1; /* * Reset the autoindent line value. 0^D keeps the ai * line from changing, ^D changes the level, even if * there are no characters in the old line. Note, * if using the current tp structure, use the cursor * as the length, the user may have erased autoindent * characters. */ if (LF_ISSET(TXT_AUTOINDENT)) { if (carat_st == C_NOCHANGE) { if (txt_auto(sp, ep, OOBLNO, &ait, ait.ai, ntp)) goto err; FREE_SPACE(sp, ait.lb, ait.lb_len); } else if (txt_auto(sp, ep, OOBLNO, tp, sp->cno, ntp)) goto err; carat_st = C_NOTSET; } /* New lines are TXT_APPENDEOL. */ if (ntp->owrite == 0 && ntp->insert == 0) { BINC_GOTO(sp, ntp->lb, ntp->lb_len, ntp->len + 1); LF_SET(TXT_APPENDEOL); ntp->lb[ntp->ai] = CH_CURSOR; ++ntp->insert; ++ntp->len; } /* * Swap old and new TEXT's, and insert the new TEXT * into the queue. * * !!! * DON'T insert until the old line has been updated, * or the inserted line count in line.c:file_gline() * will be wrong. */ tp = ntp; CIRCLEQ_INSERT_TAIL(tiqh, tp, q); /* Reset the cursor. */ sp->lno = tp->lno; sp->cno = tp->ai; /* Update the new line. */ if (sp->s_change(sp, ep, tp->lno, LINE_INSERT)) goto err; /* Set the renumber bit. */ F_SET(sp, S_RENUMBER); /* Refresh if nothing waiting. */ if (margin || !KEYS_WAITING(sp)) if (sp->s_refresh(sp, ep)) goto err; goto next_ch; case K_ESCAPE: /* Escape. */ if (!LF_ISSET(TXT_ESCAPE)) goto ins_ch;k_escape: LINE_RESOLVE; /* * Clean up for the 'R' command, restoring overwrite * characters, and making them into insert characters. */ if (LF_ISSET(TXT_REPLACE)) txt_Rcleanup(sp, tiqh, tp, lp, len); /* * If there are any overwrite characters, copy down * any insert characters, and decrement the length. */ if (tp->owrite) { if (tp->insert) memmove(tp->lb + sp->cno, tp->lb + sp->cno + tp->owrite, tp->insert); tp->len -= tp->owrite; } /* * Optionally resolve the lines into the file. Clear * the input flag, the look-aside buffer is no longer * valid. If not resolving the lines into the file, * end it with a nul. * * XXX * This is wrong, should pass back a length. */ if (LF_ISSET(TXT_RESOLVE)) { if (txt_resolve(sp, ep, tiqh, flags)) goto err; F_CLR(sp, S_INPUT); } else { BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1); tp->lb[tp->len] = '\0'; } /* * Set the return cursor position to rest on the last * inserted character. */ if (rp != NULL) { rp->lno = tp->lno; rp->cno = sp->cno ? sp->cno - 1 : 0; if (sp->s_change(sp, ep, rp->lno, LINE_RESET)) goto err; } goto ret; case K_CARAT: /* Delete autoindent chars. */ if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai) carat_st = C_CARATSET; goto ins_ch; case K_ZERO: /* Delete autoindent chars. */ if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai) carat_st = C_ZEROSET; goto ins_ch; case K_CNTRLD: /* Delete autoindent char. */ /* * If in the first column or no characters to erase, * ignore the ^D (this matches historic practice). If * not doing autoindent or already inserted non-ai * characters, it's a literal. The latter test is done * in the switch, as the CARAT forms are N + 1, not N. */ if (!LF_ISSET(TXT_AUTOINDENT)) goto ins_ch; if (sp->cno == 0) break; switch (carat_st) { case C_CARATSET: /* ^^D */ if (sp->cno > tp->ai + tp->offset + 1) goto ins_ch; /* Save the ai string for later. */ ait.lb = NULL; ait.lb_len = 0; BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai); memmove(ait.lb, tp->lb, tp->ai); ait.ai = ait.len = tp->ai; carat_st = C_NOCHANGE; goto leftmargin; case C_ZEROSET: /* 0^D */ if (sp->cno > tp->ai + tp->offset + 1) goto ins_ch; carat_st = C_NOTSET;leftmargin: tp->lb[sp->cno - 1] = ' '; tp->owrite += sp->cno - tp->offset; tp->ai = 0; sp->cno = tp->offset; break; case C_NOTSET: /* ^D */ if (sp->cno > tp->ai + tp->offset) goto ins_ch; (void)txt_outdent(sp, tp); break; default: abort(); } break; case K_VERASE: /* Erase the last character. */ /* * If can erase over the prompt, return. Len is 0 * if backspaced over the prompt, 1 if only CR entered. */ if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) { tp->len = 0; goto ret; } /* * If at the beginning of the line, try and drop back * to a previously inserted line. */ if (sp->cno == 0) { if ((ntp = txt_backup(sp, ep, tiqh, tp, &flags)) == NULL) goto err; tp = ntp; break; } /* If nothing to erase, bell the user. */ if (sp->cno <= tp->offset) { msgq(sp, M_BERR, "No more characters to erase."); break; } /* Drop back one character. */ --sp->cno; /* * Increment overwrite, decrement ai if deleted. * * !!! * Historic vi did not permit users to use erase * characters to delete autoindent characters. */ ++tp->owrite; if (sp->cno < tp->ai) --tp->ai; break; case K_VINTR: if (F_ISSET(sp, S_INTERRUPTIBLE)) { /* * !!! * Historically, <interrupt> exited the user * from editing, and returned to command mode. * It also beeped the terminal, but that seems * excessive. */ F_SET(sp, S_INTERRUPTED); msgq(sp, M_INFO, "Interrupted."); goto k_escape; } goto ins_ch; case K_VWERASE: /* Skip back one word. */ /* * If at the beginning of the line, try and drop back * to a previously inserted line. */ if (sp->cno == 0) { if ((ntp = txt_backup(sp, ep, tiqh, tp, &flags)) == NULL) goto err; tp = ntp; } /* * If at offset, nothing to erase so bell the user. */ if (sp->cno <= tp->offset) { msgq(sp, M_BERR, "No more characters to erase."); break; } /* * First werase goes back to any autoindent * and second werase goes back to the offset. * * !!! * Historic vi did not permit users to use erase * characters to delete autoindent characters. */ if (tp->ai && sp->cno > tp->ai) max = tp->ai; else { tp->ai = 0; max = tp->offset; } /* Skip over trailing space characters. */ while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) { --sp->cno; ++tp->owrite; } if (sp->cno == max) break; /* * There are three types of word erase found on UNIX * systems. They can be identified by how the string * /a/b/c is treated -- as 1, 3, or 6 words. Historic * vi had two classes of characters, and strings were * delimited by them and <blank>'s, so, 6 words. The * historic tty interface used <blank>'s to delimit * strings, so, 1 word. The algorithm offered in the * 4.4BSD tty interface (as stty altwerase) treats it * as 3 words -- there are two classes of characters, * and strings are delimited by them and <blank>'s. * The difference is that the type of the first erased * character erased is ignored, which is exactly right * when erasing pathname components. Here, the options * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD * tty interface and the historic tty driver behavior, * respectively, and the default is the same as the * historic vi behavior. */ if (LF_ISSET(TXT_TTYWERASE)) while (sp->cno > max) { --sp->cno; ++tp->owrite; if (isblank(tp->lb[sp->cno - 1])) break; } else { if (LF_ISSET(TXT_ALTWERASE)) { --sp->cno; ++tp->owrite; if (isblank(tp->lb[sp->cno - 1])) break; } if (sp->cno > max) tmp = inword(tp->lb[sp->cno - 1]); while (sp->cno > max) { --sp->cno; ++tp->owrite; if (tmp != inword(tp->lb[sp->cno - 1]) || isblank(tp->lb[sp->cno - 1])) break; } } break; case K_VKILL: /* Restart this line. */ /* * If at the beginning of the line, try and drop back * to a previously inserted line. */ if (sp->cno == 0) { if ((ntp = txt_backup(sp, ep, tiqh, tp, &flags)) == NULL) goto err; tp = ntp; } /* If at offset, nothing to erase so bell the user. */ if (sp->cno <= tp->offset) { msgq(sp, M_BERR, "No more characters to erase."); break; } /* * First kill goes back to any autoindent * and second kill goes back to the offset. * * !!! * Historic vi did not permit users to use erase * characters to delete autoindent characters. */ if (tp->ai && sp->cno > tp->ai) max = tp->ai; else { tp->ai = 0; max = tp->offset; } tp->owrite += sp->cno - max; sp->cno = max; break; case K_CNTRLT: /* Add autoindent char. */ if (!LF_ISSET(TXT_CNTRLT)) goto ins_ch; if (txt_indent(sp, tp)) goto err; goto ebuf_chk; case K_CNTRLZ: (void)sp->s_suspend(sp); break;#ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT case K_FORMFEED: F_SET(sp, S_REFRESH); break;#endif case K_RIGHTBRACE: case K_RIGHTPAREN: showmatch = LF_ISSET(TXT_SHOWMATCH); goto ins_ch; case K_VLNEXT: /* Quote the next character. */ ch = '^'; quoted = Q_NEXTCHAR; goto insq_ch; case K_HEXCHAR: hex = H_NEXTCHAR; goto insq_ch; default: /* Insert the character. */ins_ch: /* * Historically, vi eliminated nul's out of hand. If * the beautify option was set, it also deleted any * unknown ASCII value less than space (040) and the * del character (0177), except for tabs. Unknown is * a key word here. Most vi documentation claims that * it deleted everything but <tab>, <nl> and <ff>, as * that's what the original 4BSD documentation said. * This is obviously wrong, however, as <esc> would be * included in that list. What we do is eliminate any * unquoted, iscntrl() character that wasn't a replay * and wasn't handled specially, except <tab> or <ff>. */ if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ch) && ikey.value != K_FORMFEED && ikey.value != K_TAB) { msgq(sp, M_BERR, "Illegal character; quote to enter."); break; }insq_ch: /* * If entering a non-word character after a word, check * for abbreviations. If there was one, discard the * replay characters. If entering a blank character, * check for unmap commands, as well. */ if (!inword(ch)) { if (abb == A_INWORD && !replay) { if (txt_abbrev(sp, tp, &ch, LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff)) goto err; if (tmp) { if (LF_ISSET(TXT_RECORD)) rcol -= tmp; goto next_ch; } } if (isblank(ch) && unmap_tst) txt_unmap(sp, tp, &iflags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -