📄 vi.c
字号:
#endif /* CONFIG_FEATURE_VI_COLON */ break; case '<': // <- Left shift something case '>': // >- Right shift something cnt = count_lines(text, dot); // remember what line we are on c1 = get_one_char(); // get the type of thing to delete find_range(&p, &q, c1); (void) yank_delete(p, q, 1, YANKONLY); // save copy before change p = begin_line(p); q = end_line(q); i = count_lines(p, q); // # of lines we are shifting for ( ; i > 0; i--, p = next_line(p)) { if (c == '<') { // shift left- remove tab or 8 spaces if (*p == '\t') { // shrink buffer 1 char (void) text_hole_delete(p, p); } else if (*p == ' ') { // we should be calculating columns, not just SPACE for (j = 0; *p == ' ' && j < tabstop; j++) { (void) text_hole_delete(p, p); } } } else if (c == '>') { // shift right -- add tab or 8 spaces (void) char_insert(p, '\t'); } } dot = find_line(cnt); // what line were we on dot_skip_over_ws(); end_cmd_q(); // stop adding to q break; case 'A': // A- append at e-o-l dot_end(); // go to e-o-l //**** fall thru to ... 'a' case 'a': // a- append after current char if (*dot != '\n') dot++; goto dc_i; break; case 'B': // B- back a blank-delimited Word case 'E': // E- end of a blank-delimited word case 'W': // W- forward a blank-delimited word if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt dir = FORWARD; if (c == 'B') dir = BACK; if (c == 'W' || isspace(dot[dir])) { dot = skip_thing(dot, 1, dir, S_TO_WS); dot = skip_thing(dot, 2, dir, S_OVER_WS); } if (c != 'W') dot = skip_thing(dot, 1, dir, S_BEFORE_WS); break; case 'C': // C- Change to e-o-l case 'D': // D- delete to e-o-l save_dot = dot; dot = dollar_line(dot); // move to before NL // copy text into a register and delete dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l if (c == 'C') goto dc_i; // start inserting#ifdef CONFIG_FEATURE_VI_DOT_CMD if (c == 'D') end_cmd_q(); // stop adding to q#endif /* CONFIG_FEATURE_VI_DOT_CMD */ break; case 'G': // G- goto to a line number (default= E-O-F) dot = end - 1; // assume E-O-F if (cmdcnt > 0) { dot = find_line(cmdcnt); // what line is #cmdcnt } dot_skip_over_ws(); break; case 'H': // H- goto top line on screen dot = screenbegin; if (cmdcnt > (rows - 1)) { cmdcnt = (rows - 1); } if (cmdcnt-- > 1) { do_cmd('+'); } // repeat cnt dot_skip_over_ws(); break; case 'I': // I- insert before first non-blank dot_begin(); // 0 dot_skip_over_ws(); //**** fall thru to ... 'i' case 'i': // i- insert before current char case VI_K_INSERT: // Cursor Key Insert dc_i: cmd_mode = 1; // start insrting psb("-- Insert --"); break; case 'J': // J- join current and next lines together if (cmdcnt-- > 2) { do_cmd(c); } // repeat cnt dot_end(); // move to NL if (dot < end - 1) { // make sure not last char in text[] *dot++ = ' '; // replace NL with space while (isblnk(*dot)) { // delete leading WS dot_delete(); } } end_cmd_q(); // stop adding to q break; case 'L': // L- goto bottom line on screen dot = end_screen(); if (cmdcnt > (rows - 1)) { cmdcnt = (rows - 1); } if (cmdcnt-- > 1) { do_cmd('-'); } // repeat cnt dot_begin(); dot_skip_over_ws(); break; case 'M': // M- goto middle line on screen dot = screenbegin; for (cnt = 0; cnt < (rows-1) / 2; cnt++) dot = next_line(dot); break; case 'O': // O- open a empty line above // 0i\n ESC -i p = begin_line(dot); if (p[-1] == '\n') { dot_prev(); case 'o': // o- open a empty line below; Yes, I know it is in the middle of the "if (..." dot_end(); dot = char_insert(dot, '\n'); } else { dot_begin(); // 0 dot = char_insert(dot, '\n'); // i\n ESC dot_prev(); // - } goto dc_i; break; case 'R': // R- continuous Replace char dc5: cmd_mode = 2; psb("-- Replace --"); break; case 'X': // X- delete char before dot case 'x': // x- delete the current char case 's': // s- substitute the current char if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt dir = 0; if (c == 'X') dir = -1; if (dot[dir] != '\n') { if (c == 'X') dot--; // delete prev char dot = yank_delete(dot, dot, 0, YANKDEL); // delete char } if (c == 's') goto dc_i; // start insrting end_cmd_q(); // stop adding to q break; case 'Z': // Z- if modified, {write}; exit // ZZ means to save file (if necessary), then exit c1 = get_one_char(); if (c1 != 'Z') { indicate_error(c); break; } if (file_modified#ifdef CONFIG_FEATURE_VI_READONLY && ! vi_readonly && ! readonly#endif /* CONFIG_FEATURE_VI_READONLY */ ) { cnt = file_write(cfn, text, end - 1); if (cnt == (end - 1 - text + 1)) { editing = 0; } } else { editing = 0; } break; case '^': // ^- move to first non-blank on line dot_begin(); dot_skip_over_ws(); break; case 'b': // b- back a word case 'e': // e- end of word if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt dir = FORWARD; if (c == 'b') dir = BACK; if ((dot + dir) < text || (dot + dir) > end - 1) break; dot += dir; if (isspace(*dot)) { dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); } if (isalnum(*dot) || *dot == '_') { dot = skip_thing(dot, 1, dir, S_END_ALNUM); } else if (ispunct(*dot)) { dot = skip_thing(dot, 1, dir, S_END_PUNCT); } break; case 'c': // c- change something case 'd': // d- delete something#ifdef CONFIG_FEATURE_VI_YANKMARK case 'y': // y- yank something case 'Y': // Y- Yank a line#endif /* CONFIG_FEATURE_VI_YANKMARK */ yf = YANKDEL; // assume either "c" or "d"#ifdef CONFIG_FEATURE_VI_YANKMARK if (c == 'y' || c == 'Y') yf = YANKONLY;#endif /* CONFIG_FEATURE_VI_YANKMARK */ c1 = 'y'; if (c != 'Y') c1 = get_one_char(); // get the type of thing to delete find_range(&p, &q, c1); if (c1 == 27) { // ESC- user changed mind and wants out c = c1 = 27; // Escape- do nothing } else if (strchr("wW", c1)) { if (c == 'c') { // don't include trailing WS as part of word while (isblnk(*q)) { if (q <= text || q[-1] == '\n') break; q--; } } dot = yank_delete(p, q, 0, yf); // delete word } else if (strchr("^0bBeEft$", c1)) { // single line copy text into a register and delete dot = yank_delete(p, q, 0, yf); // delete word } else if (strchr("cdykjHL%+-{}\r\n", c1)) { // multiple line copy text into a register and delete dot = yank_delete(p, q, 1, yf); // delete lines if (c == 'c') { dot = char_insert(dot, '\n'); // on the last line of file don't move to prev line if (dot != (end-1)) { dot_prev(); } } else if (c == 'd') { dot_begin(); dot_skip_over_ws(); } } else { // could not recognize object c = c1 = 27; // error- indicate_error(c); } if (c1 != 27) { // if CHANGING, not deleting, start inserting after the delete if (c == 'c') { strcpy((char *) buf, "Change"); goto dc_i; // start inserting } if (c == 'd') { strcpy((char *) buf, "Delete"); }#ifdef CONFIG_FEATURE_VI_YANKMARK if (c == 'y' || c == 'Y') { strcpy((char *) buf, "Yank"); } p = reg[YDreg]; q = p + strlen((char *) p); for (cnt = 0; p <= q; p++) { if (*p == '\n') cnt++; } psb("%s %d lines (%d chars) using [%c]", buf, cnt, strlen((char *) reg[YDreg]), what_reg());#endif /* CONFIG_FEATURE_VI_YANKMARK */ end_cmd_q(); // stop adding to q } break; case 'k': // k- goto prev line, same col case VI_K_UP: // cursor key Up if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt dot_prev(); dot = move_to_col(dot, ccol + offset); // try stay in same col break; case 'r': // r- replace the current char with user input c1 = get_one_char(); // get the replacement char if (*dot != '\n') { *dot = c1; file_modified = TRUE; // has the file been modified } end_cmd_q(); // stop adding to q break; case 't': // t- move to char prior to next x last_forward_char = get_one_char(); do_cmd(';'); if (*dot == last_forward_char) dot_left(); last_forward_char= 0; break; case 'w': // w- forward a word if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt if (isalnum(*dot) || *dot == '_') { // we are on ALNUM dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); } else if (ispunct(*dot)) { // we are on PUNCT dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); } if (dot < end - 1) dot++; // move over word if (isspace(*dot)) { dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); } break; case 'z': // z- c1 = get_one_char(); // get the replacement char cnt = 0; if (c1 == '.') cnt = (rows - 2) / 2; // put dot at center if (c1 == '-') cnt = rows - 2; // put dot at bottom screenbegin = begin_line(dot); // start dot at top dot_scroll(cnt, -1); break; case '|': // |- move to column "cmdcnt" dot = move_to_col(dot, cmdcnt - 1); // try to move to column break; case '~': // ~- flip the case of letters a-z -> A-Z if (cmdcnt-- > 1) { do_cmd(c); } // repeat cnt if (islower(*dot)) { *dot = toupper(*dot); file_modified = TRUE; // has the file been modified } else if (isupper(*dot)) { *dot = tolower(*dot); file_modified = TRUE; // has the file been modified } dot_right(); end_cmd_q(); // stop adding to q break; //----- The Cursor and Function Keys ----------------------------- case VI_K_HOME: // Cursor Key Home dot_begin(); break; // The Fn keys could point to do_macro which could translate them case VI_K_FUN1: // Function Key F1 case VI_K_FUN2: // Function Key F2 case VI_K_FUN3: // Function Key F3 case VI_K_FUN4: // Function Key F4 case VI_K_FUN5: // Function Key F5 case VI_K_FUN6: // Function Key F6 case VI_K_FUN7: // Function Key F7 case VI_K_FUN8: // Function Key F8 case VI_K_FUN9: // Function Key F9 case VI_K_FUN10: // Function Key F10 case VI_K_FUN11: // Function Key F11 case VI_K_FUN12: // Function Key F12 break; } dc1: // if text[] just became empty, add back an empty line if (end == text) { (void) char_insert(text, '\n'); // start empty buf with dummy line dot = text; } // it is OK for dot to exactly equal to end, otherwise check dot validity if (dot != end) { dot = bound_dot(dot); // make sure "dot" is valid }#ifdef CONFIG_FEATURE_VI_YANKMARK check_context(c); // update the current context#endif /* CONFIG_FEATURE_VI_YANKMARK */ if (!isdigit(c)) cmdcnt = 0; // cmd was not a number, reset cmdcnt cnt = dot - begin_line(dot); // Try to stay off of the Newline if (*dot == '\n' && cnt > 0 && cmd_mode == 0) dot--;}//----- The Colon commands -------------------------------------#ifdef CONFIG_FEATURE_VI_COLONstatic Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present{ int st; Byte *q;#ifdef CONFIG_FEATURE_VI_YANKMARK Byte c;#endif /* CONFIG_FEATURE_VI_YANKMARK */#ifdef CONFIG_FEATURE_VI_SEARCH Byte *pat, buf[BUFSIZ];#endif /* CONFIG_FEATURE_VI_SEARCH */ *addr = -1; // assume no addr if (*p == '.') { // the current line p++; q = begin_line(dot); *addr = count_lines(text, q);#ifdef CONFIG_FEATURE_VI_YANKMARK } else if (*p == '\'') { // is this a mark addr p++; c = tolower(*p); p++; if (c >= 'a' && c <= 'z') { // we have a mark
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -