📄 vi.c
字号:
* !!! * If a '.' is immediately entered after an undo command, we * replay the log instead of redoing the last command. This * is necessary because 'u' can't set the dot command -- see * vi/v_undo.c:v_undo for details. */ if (VIP(sp)->u_ccnt == sp->ccnt) { vp->kp = &vikeys['u']; F_SET(vp, VC_ISDOT); return (0); } /* Set new count/buffer, if any, and return. */ if (F_ISSET(vp, VC_C1SET)) { F_SET(dp, VC_C1SET); dp->count = vp->count; } if (F_ISSET(vp, VC_BUFFER)) dp->buffer = vp->buffer; *vp = *dp; return (0); } flags = kp->flags; /* Check for illegal count. */ if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT)) goto usage; /* Illegal motion command. */ if (ismotion == NULL) { /* Illegal buffer. */ if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER)) goto usage; /* Required buffer. */ if (LF_ISSET(V_RBUF)) KEY(vp->buffer, 0); } /* * Special case: '[', ']' and 'Z' commands. Doesn't the fact that * the *single* characters don't mean anything but the *doubled* * characters do just frost your shorts? */ if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') { KEY(key, TXT_MAPCOMMAND); if (vp->key != key) {usage: msgq(sp, M_ERR, "Usage: %s", ismotion != NULL ? vikeys[ismotion->key].usage : kp->usage); return (1); } } /* Special case: 'z' command. */ if (vp->key == 'z') { KEY(vp->character, 0); if (isdigit(vp->character)) { if (getcount(sp, vp->character, &vp->count2)) return (1); F_SET(vp, VC_C2SET); KEY(vp->character, 0); } } /* * Commands that have motion components can be doubled to * imply the current line. */ if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) { msgq(sp, M_ERR, "%s may not be used as a motion command.", KEY_NAME(sp, key)); return (1); } /* Required character. */ if (LF_ISSET(V_CHAR)) KEY(vp->character, 0); return (0);}/* * getmotion -- * * Get resulting motion mark. */static intgetmotion(sp, ep, dm, vp) SCR *sp; EXF *ep; VICMDARG *dm, *vp;{ MARK m; VICMDARG motion; size_t len; u_long cnt; int notused; /* If '.' command, use the dot motion, else get the motion command. */ if (F_ISSET(vp, VC_ISDOT)) { motion = *dm; F_SET(&motion, VC_ISDOT); } else if (getcmd(sp, ep, NULL, &motion, vp, ¬used)) return (1); /* * A count may be provided both to the command and to the motion, in * which case the count is multiplicative. For example, "3y4y" is the * same as "12yy". This count is provided to the motion command and * not to the regular function. */ cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1; if (F_ISSET(vp, VC_C1SET)) { motion.count *= vp->count; F_SET(&motion, VC_C1SET); /* * Set flags to restore the original values of the command * structure so dot commands can change the count values, * e.g. "2dw" "3." deletes a total of five words. */ F_CLR(vp, VC_C1SET); F_SET(vp, VC_C1RESET); } /* * Some commands can be repeated to indicate the current line. In * this case, or if the command is a "line command", set the flags * appropriately. If not a doubled command, run the function to get * the resulting mark. */ if (vp->key == motion.key) { F_SET(vp, VM_LDOUBLE | VM_LMODE); /* Set the origin of the command. */ vp->m_start.lno = sp->lno; vp->m_start.cno = 0; /* * Set the end of the command. * * If the current line is missing, i.e. the file is empty, * historic vi permitted a "cc" or "!!" command to insert * text. */ vp->m_stop.lno = sp->lno + motion.count - 1; if (file_gline(sp, ep, vp->m_stop.lno, &len) == NULL) { if (vp->m_stop.lno != 1 || vp->key != 'c' && vp->key != '!') { m.lno = sp->lno; m.cno = sp->cno; v_eof(sp, ep, &m); return (1); } vp->m_stop.cno = 0; } else vp->m_stop.cno = len ? len - 1 : 0; } else { /* * Motion commands change the underlying movement (*snarl*). * For example, "l" is illegal at the end of a line, but "dl" * is not. Set flags so the function knows the situation. */ F_SET(&motion, vp->kp->flags & VC_COMMASK); /* Copy the key flags into the local structure. */ F_SET(&motion, motion.kp->flags); /* * Set the three cursor locations to the current cursor. This * permits commands like 'j' and 'k', that are line oriented * motions and have special cursor suck semantics when they are * used as standalone commands, to ignore column positioning. */ motion.m_final.lno = motion.m_stop.lno = motion.m_start.lno = sp->lno; motion.m_final.cno = motion.m_stop.cno = motion.m_start.cno = sp->cno; /* Run the function. */ if ((motion.kp->func)(sp, ep, &motion)) return (1); /* * Copy line mode and cursor position information from the * motion command structure. The commands can flag the * movement as a line motion (see v_sentence) as well as set * the VM_RCM_* flags explicitly. */ F_SET(vp, F_ISSET(&motion, VM_LMODE | VM_NOMOTION | VM_RCM_MASK)); /* * Motion commands can reset all of the cursor information. * If the motion is in the reverse direction, switch the * from and to MARK's so that it's in a forward direction. * Motions are from the from MARK to the to MARK (inclusive). */ if (motion.m_start.lno > motion.m_stop.lno || motion.m_start.lno == motion.m_stop.lno && motion.m_start.cno > motion.m_stop.cno) { vp->m_start = motion.m_stop; vp->m_stop = motion.m_start; } else { vp->m_start = motion.m_start; vp->m_stop = motion.m_stop; } vp->m_final = motion.m_final; } /* * If the command sets dot, save the motion structure. The motion * count was changed above and needs to be reset, that's why this * is done here, and not in the calling routine. */ if (F_ISSET(vp->kp, V_DOT)) { *dm = motion; dm->count = cnt; } return (0);}#define innum(c) (isdigit(c) || strchr("abcdefABCDEF", c))/* * getkeyword -- * Get the "word" the cursor is on. */static intgetkeyword(sp, ep, kp, flags) SCR *sp; EXF *ep; VICMDARG *kp; u_int flags;{ recno_t lno; size_t beg, end, len; char *p; if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) { if (file_lline(sp, ep, &lno)) return (1); if (lno == 0) v_eof(sp, ep, NULL); else GETLINE_ERR(sp, sp->lno); return (1); } beg = sp->cno; /* May not be a keyword at all. */ if (p == NULL || len == 0 || LF_ISSET(V_KEYW) && !inword(p[beg]) || LF_ISSET(V_KEYNUM) && !innum(p[beg]) && p[beg] != '-' && p[beg] != '+') {noword: msgq(sp, M_BERR, "Cursor not in a %s", LF_ISSET(V_KEYW) ? "word" : "number"); return (1); } /* * !!! * Find the beginning/end of the keyword. Keywords (V_KEYW) are * used for cursor-word searching and for tags. Historical vi * only used the word in a tag search from the cursor to the end * of the word, i.e. if the cursor was on the 'b' in " abc ", the * tag was "bc". For no particular reason, we make cursor word * searches follow the same rule. */ if (beg != 0) if (LF_ISSET(V_KEYW)) {#ifdef MOVE_TO_KEYWORD_BEGINNING for (;;) { --beg; if (!inword(p[beg])) { ++beg; break; } if (beg == 0) break; }#endif } else { for (;;) { --beg; if (!innum(p[beg])) { if (beg > 0 && p[beg - 1] == '0' && (p[beg] == 'X' || p[beg] == 'x')) --beg; else ++beg; break; } if (beg == 0) break; } /* Skip possible leading sign. */ if (beg != 0 && p[beg] != '0' && (p[beg - 1] == '+' || p[beg - 1] == '-')) --beg; } if (LF_ISSET(V_KEYW)) { for (end = sp->cno; ++end < len && inword(p[end]);); --end; } else { for (end = sp->cno; ++end < len;) { if (p[end] == 'X' || p[end] == 'x') { if (end != beg + 1 || p[beg] != '0') break; continue; } if (!innum(p[end])) break; } /* Just a sign isn't a number. */ if (end == beg && (p[beg] == '+' || p[beg] == '-')) goto noword; --end; } /* * Getting a keyword implies moving the cursor to its beginning. * Refresh now. */ if (beg != sp->cno) { sp->cno = beg; sp->s_refresh(sp, ep); } /* * XXX * 8-bit clean problem. Numeric keywords are handled using strtol(3) * and friends. This would have to be fixed in v_increment and here * to not depend on a trailing NULL. */ len = (end - beg) + 2; /* XXX */ kp->klen = (end - beg) + 1; BINC_RET(sp, kp->keyword, kp->kbuflen, len); memmove(kp->keyword, p + beg, kp->klen); kp->keyword[kp->klen] = '\0'; /* XXX */ return (0);}/* * getcount -- * Return the next count. */static inline intgetcount(sp, fkey, countp) SCR *sp; ARG_CHAR_T fkey; u_long *countp;{ u_long count, tc; CH ikey; ikey.ch = fkey; count = tc = 0; do { /* Assume that overflow results in a smaller number. */ tc = count * 10 + ikey.ch - '0'; if (count > tc) { /* Toss to the next non-digit. */ do { if (getkey(sp, &ikey, TXT_MAPCOMMAND | TXT_MAPNODIGIT)) return (1); } while (isdigit(ikey.ch)); msgq(sp, M_ERR, "Number larger than %lu", ULONG_MAX); return (1); } count = tc; if (getkey(sp, &ikey, TXT_MAPCOMMAND | TXT_MAPNODIGIT)) return (1); } while (isdigit(ikey.ch)); *countp = count; return (0);}/* * getkey -- * Return the next key. */static inline intgetkey(sp, ikeyp, map) SCR *sp; CH *ikeyp; u_int map;{ switch (term_key(sp, ikeyp, map)) { case INP_OK: break; case INP_EOF: case INP_ERR: F_SET(sp, S_EXIT_FORCE); return (1); } return (ikeyp->value == K_ESCAPE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -