aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/vi.c162
1 files changed, 73 insertions, 89 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 7a7247c10..ccf2870ab 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -254,6 +254,9 @@ enum {
254 BACK = -1, // code depends on "-1" for array index 254 BACK = -1, // code depends on "-1" for array index
255 LIMITED = 0, // char_search() only current line 255 LIMITED = 0, // char_search() only current line
256 FULL = 1, // char_search() to the end/beginning of entire text 256 FULL = 1, // char_search() to the end/beginning of entire text
257 PARTIAL = 0, // buffer contains partial line
258 WHOLE = 1, // buffer contains whole lines
259 MULTI = 2, // buffer may include newlines
257 260
258 S_BEFORE_WS = 1, // used in skip_thing() for moving "dot" 261 S_BEFORE_WS = 1, // used in skip_thing() for moving "dot"
259 S_TO_WS = 2, // used in skip_thing() for moving "dot" 262 S_TO_WS = 2, // used in skip_thing() for moving "dot"
@@ -343,6 +346,7 @@ struct globals {
343 smalluint YDreg;//,Ureg;// default delete register and orig line for "U" 346 smalluint YDreg;//,Ureg;// default delete register and orig line for "U"
344#define Ureg 27 347#define Ureg 27
345 char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 348 char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27
349 char regtype[28]; // buffer type: WHOLE, MULTI or PARTIAL
346 char *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' 350 char *mark[28]; // user marks points somewhere in text[]- a-z and previous context ''
347 char *context_start, *context_end; 351 char *context_start, *context_end;
348#endif 352#endif
@@ -452,6 +456,7 @@ struct globals {
452 456
453#define YDreg (G.YDreg ) 457#define YDreg (G.YDreg )
454//#define Ureg (G.Ureg ) 458//#define Ureg (G.Ureg )
459#define regtype (G.regtype )
455#define mark (G.mark ) 460#define mark (G.mark )
456#define context_start (G.context_start ) 461#define context_start (G.context_start )
457#define context_end (G.context_end ) 462#define context_end (G.context_end )
@@ -1314,7 +1319,8 @@ static void not_implemented(const char *s)
1314 1319
1315//----- Block insert/delete, undo ops -------------------------- 1320//----- Block insert/delete, undo ops --------------------------
1316#if ENABLE_FEATURE_VI_YANKMARK 1321#if ENABLE_FEATURE_VI_YANKMARK
1317static char *text_yank(char *p, char *q, int dest) // copy text into a register 1322// copy text into a register
1323static char *text_yank(char *p, char *q, int dest, int buftype)
1318{ 1324{
1319 int cnt = q - p; 1325 int cnt = q - p;
1320 if (cnt < 0) { // they are backwards- reverse them 1326 if (cnt < 0) { // they are backwards- reverse them
@@ -1323,6 +1329,7 @@ static char *text_yank(char *p, char *q, int dest) // copy text into a register
1323 } 1329 }
1324 free(reg[dest]); // if already a yank register, free it 1330 free(reg[dest]); // if already a yank register, free it
1325 reg[dest] = xstrndup(p, cnt + 1); 1331 reg[dest] = xstrndup(p, cnt + 1);
1332 regtype[dest] = buftype;
1326 return p; 1333 return p;
1327} 1334}
1328 1335
@@ -1819,12 +1826,11 @@ static void end_cmd_q(void)
1819#endif /* FEATURE_VI_DOT_CMD */ 1826#endif /* FEATURE_VI_DOT_CMD */
1820 1827
1821// copy text into register, then delete text. 1828// copy text into register, then delete text.
1822// if dist <= 0, do not include, or go past, a NewLine
1823// 1829//
1824#if !ENABLE_FEATURE_VI_UNDO 1830#if !ENABLE_FEATURE_VI_UNDO
1825#define yank_delete(a,b,c,d,e) yank_delete(a,b,c,d) 1831#define yank_delete(a,b,c,d,e) yank_delete(a,b,c,d)
1826#endif 1832#endif
1827static char *yank_delete(char *start, char *stop, int dist, int yf, int undo) 1833static char *yank_delete(char *start, char *stop, int buftype, int yf, int undo)
1828{ 1834{
1829 char *p; 1835 char *p;
1830 1836
@@ -1835,22 +1841,11 @@ static char *yank_delete(char *start, char *stop, int dist, int yf, int undo)
1835 start = stop; 1841 start = stop;
1836 stop = p; 1842 stop = p;
1837 } 1843 }
1838 if (dist <= 0) { 1844 if (buftype == PARTIAL && *start == '\n')
1839 // we cannot cross NL boundaries 1845 return start;
1840 p = start;
1841 if (*p == '\n')
1842 return p;
1843 // dont go past a NewLine
1844 for (; p + 1 <= stop; p++) {
1845 if (p[1] == '\n') {
1846 stop = p; // "stop" just before NewLine
1847 break;
1848 }
1849 }
1850 }
1851 p = start; 1846 p = start;
1852#if ENABLE_FEATURE_VI_YANKMARK 1847#if ENABLE_FEATURE_VI_YANKMARK
1853 text_yank(start, stop, YDreg); 1848 text_yank(start, stop, YDreg, buftype);
1854#endif 1849#endif
1855 if (yf == YANKDEL) { 1850 if (yf == YANKDEL) {
1856 p = text_hole_delete(start, stop, undo); 1851 p = text_hole_delete(start, stop, undo);
@@ -2521,7 +2516,7 @@ static void colon(char *buf)
2521 q = begin_line(dot); // assume .,. for the range 2516 q = begin_line(dot); // assume .,. for the range
2522 r = end_line(dot); 2517 r = end_line(dot);
2523 } 2518 }
2524 dot = yank_delete(q, r, 1, YANKDEL, ALLOW_UNDO); // save, then delete lines 2519 dot = yank_delete(q, r, WHOLE, YANKDEL, ALLOW_UNDO); // save, then delete lines
2525 dot_skip_over_ws(); 2520 dot_skip_over_ws();
2526 } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file 2521 } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file
2527 int size; 2522 int size;
@@ -2874,7 +2869,7 @@ static void colon(char *buf)
2874 q = begin_line(dot); // assume .,. for the range 2869 q = begin_line(dot); // assume .,. for the range
2875 r = end_line(dot); 2870 r = end_line(dot);
2876 } 2871 }
2877 text_yank(q, r, YDreg); 2872 text_yank(q, r, YDreg, WHOLE);
2878 li = count_lines(q, r); 2873 li = count_lines(q, r);
2879 status_line("Yank %d lines (%d chars) into [%c]", 2874 status_line("Yank %d lines (%d chars) into [%c]",
2880 li, strlen(reg[YDreg]), what_reg()); 2875 li, strlen(reg[YDreg]), what_reg());
@@ -3000,74 +2995,65 @@ static void do_cmd(int c);
3000static int find_range(char **start, char **stop, char c) 2995static int find_range(char **start, char **stop, char c)
3001{ 2996{
3002 char *save_dot, *p, *q, *t; 2997 char *save_dot, *p, *q, *t;
3003 int cnt, multiline = 0, forward; 2998 int buftype = -1;
3004 2999
3005 save_dot = dot; 3000 save_dot = dot;
3006 p = q = dot; 3001 p = q = dot;
3007 3002
3008 // will a 'G' command move forwards or backwards?
3009 forward = cmdcnt == 0 || cmdcnt > count_lines(text, dot);
3010
3011 if (strchr("cdy><", c)) { 3003 if (strchr("cdy><", c)) {
3012 // these cmds operate on whole lines 3004 // these cmds operate on whole lines
3013 p = q = begin_line(p); 3005 buftype = WHOLE;
3014 for (cnt = 1; cnt < cmdcnt; cnt++) { 3006 if (--cmdcnt > 0)
3015 q = next_line(q); 3007 do_cmd('j');
3016 }
3017 q = end_line(q);
3018 } else if (strchr("^%$0bBeEfth\b\177", c)) { 3008 } else if (strchr("^%$0bBeEfth\b\177", c)) {
3019 // These cmds operate on char positions 3009 // These cmds operate on char positions
3010 buftype = PARTIAL;
3020 do_cmd(c); // execute movement cmd 3011 do_cmd(c); // execute movement cmd
3021 q = dot; 3012 if (p == dot) // no movement is an error
3013 buftype = -1;
3022 } else if (strchr("wW", c)) { 3014 } else if (strchr("wW", c)) {
3015 buftype = MULTI;
3023 do_cmd(c); // execute movement cmd 3016 do_cmd(c); // execute movement cmd
3024 // step back one char, but not if we're at end of file 3017 // step back one char, but not if we're at end of file
3025 if (dot > p && !((dot == end - 2 && end[-1] == '\n') || dot == end - 1)) 3018 if (dot > p && !((dot == end - 2 && end[-1] == '\n') || dot == end - 1))
3026 dot--; 3019 dot--;
3027 q = dot; 3020 } else if (strchr("GHL+-jk{}\r\n", c)) {
3028 } else if (strchr("H-k{", c) || (c == 'G' && !forward)) { 3021 // these operate on whole lines
3029 // these operate on multi-lines backwards 3022 buftype = WHOLE;
3030 q = end_line(dot); // find NL
3031 do_cmd(c); // execute movement cmd
3032 dot_begin();
3033 p = dot;
3034 } else if (strchr("L+j}\r\n", c) || (c == 'G' && forward)) {
3035 // these operate on multi-lines forwards
3036 p = begin_line(dot);
3037 do_cmd(c); // execute movement cmd 3023 do_cmd(c); // execute movement cmd
3038 dot_end(); // find NL 3024 } else if (c == ' ' || c == 'l') {
3039 q = dot;
3040 } else /* if (c == ' ' || c == 'l') */ {
3041 // forward motion by character 3025 // forward motion by character
3042 int tmpcnt = (cmdcnt ?: 1); 3026 int tmpcnt = (cmdcnt ?: 1);
3027 buftype = PARTIAL;
3043 do_cmd(c); // execute movement cmd 3028 do_cmd(c); // execute movement cmd
3044 // exclude last char unless range isn't what we expected 3029 // exclude last char unless range isn't what we expected
3045 // this indicates we've hit EOL 3030 // this indicates we've hit EOL
3046 if (tmpcnt == dot - p) 3031 if (tmpcnt == dot - p)
3047 dot--; 3032 dot--;
3048 q = dot;
3049 } 3033 }
3034
3035 if (buftype == -1)
3036 return buftype;
3037
3038 q = dot;
3050 if (q < p) { 3039 if (q < p) {
3051 t = q; 3040 t = q;
3052 q = p; 3041 q = p;
3053 p = t; 3042 p = t;
3054 } 3043 }
3055 3044
3045 if (buftype == WHOLE) {
3046 p = begin_line(p);
3047 q = end_line(q);
3048 }
3049
3056 // backward char movements don't include start position 3050 // backward char movements don't include start position
3057 if (q > p && strchr("^0bBh\b\177", c)) q--; 3051 if (q > p && strchr("^0bBh\b\177", c)) q--;
3058 3052
3059 multiline = 0;
3060 for (t = p; t <= q; t++) {
3061 if (*t == '\n') {
3062 multiline = 1;
3063 break;
3064 }
3065 }
3066
3067 *start = p; 3053 *start = p;
3068 *stop = q; 3054 *stop = q;
3069 dot = save_dot; 3055 dot = save_dot;
3070 return multiline; 3056 return buftype;
3071} 3057}
3072 3058
3073//--------------------------------------------------------------------- 3059//---------------------------------------------------------------------
@@ -3132,7 +3118,7 @@ static void do_cmd(int c)
3132 } else { 3118 } else {
3133 if (1 <= c || Isprint(c)) { 3119 if (1 <= c || Isprint(c)) {
3134 if (c != 27) 3120 if (c != 27)
3135 dot = yank_delete(dot, dot, 0, YANKDEL, ALLOW_UNDO); // delete char 3121 dot = yank_delete(dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO); // delete char
3136 dot = char_insert(dot, c, ALLOW_UNDO_CHAIN); // insert new char 3122 dot = char_insert(dot, c, ALLOW_UNDO_CHAIN); // insert new char
3137 } 3123 }
3138 goto dc1; 3124 goto dc1;
@@ -3312,7 +3298,7 @@ static void do_cmd(int c)
3312 break; 3298 break;
3313 } 3299 }
3314 // are we putting whole lines or strings 3300 // are we putting whole lines or strings
3315 if (strchr(p, '\n') != NULL) { 3301 if (regtype[YDreg] == WHOLE) {
3316 if (c == 'P') { 3302 if (c == 'P') {
3317 dot_begin(); // putting lines- Put above 3303 dot_begin(); // putting lines- Put above
3318 } 3304 }
@@ -3523,7 +3509,7 @@ static void do_cmd(int c)
3523 cnt = count_lines(text, dot); // remember what line we are on 3509 cnt = count_lines(text, dot); // remember what line we are on
3524 c1 = get_one_char(); // get the type of thing to delete 3510 c1 = get_one_char(); // get the type of thing to delete
3525 find_range(&p, &q, c1); 3511 find_range(&p, &q, c1);
3526 yank_delete(p, q, 1, YANKONLY, NO_UNDO); // save copy before change 3512 yank_delete(p, q, WHOLE, YANKONLY, NO_UNDO); // save copy before change
3527 p = begin_line(p); 3513 p = begin_line(p);
3528 q = end_line(q); 3514 q = end_line(q);
3529 i = count_lines(p, q); // # of lines we are shifting 3515 i = count_lines(p, q); // # of lines we are shifting
@@ -3576,7 +3562,7 @@ static void do_cmd(int c)
3576 save_dot = dot; 3562 save_dot = dot;
3577 dot = dollar_line(dot); // move to before NL 3563 dot = dollar_line(dot); // move to before NL
3578 // copy text into a register and delete 3564 // copy text into a register and delete
3579 dot = yank_delete(save_dot, dot, 0, YANKDEL, ALLOW_UNDO); // delete to e-o-l 3565 dot = yank_delete(save_dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO); // delete to e-o-l
3580 if (c == 'C') 3566 if (c == 'C')
3581 goto dc_i; // start inserting 3567 goto dc_i; // start inserting
3582#if ENABLE_FEATURE_VI_DOT_CMD 3568#if ENABLE_FEATURE_VI_DOT_CMD
@@ -3682,7 +3668,7 @@ static void do_cmd(int c)
3682 break; 3668 break;
3683 case KEYCODE_DELETE: 3669 case KEYCODE_DELETE:
3684 if (dot < end - 1) 3670 if (dot < end - 1)
3685 dot = yank_delete(dot, dot, 1, YANKDEL, ALLOW_UNDO); 3671 dot = yank_delete(dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO);
3686 break; 3672 break;
3687 case 'X': // X- delete char before dot 3673 case 'X': // X- delete char before dot
3688 case 'x': // x- delete the current char 3674 case 'x': // x- delete the current char
@@ -3694,7 +3680,7 @@ static void do_cmd(int c)
3694 if (dot[dir] != '\n') { 3680 if (dot[dir] != '\n') {
3695 if (c == 'X') 3681 if (c == 'X')
3696 dot--; // delete prev char 3682 dot--; // delete prev char
3697 dot = yank_delete(dot, dot, 0, YANKDEL, ALLOW_UNDO); // delete char 3683 dot = yank_delete(dot, dot, PARTIAL, YANKDEL, ALLOW_UNDO); // delete char
3698 } 3684 }
3699 } while (--cmdcnt > 0); 3685 } while (--cmdcnt > 0);
3700 end_cmd_q(); // stop adding to q 3686 end_cmd_q(); // stop adding to q
@@ -3754,21 +3740,29 @@ static void do_cmd(int c)
3754 case 'Y': // Y- Yank a line 3740 case 'Y': // Y- Yank a line
3755#endif 3741#endif
3756 { 3742 {
3757 int yf, ml, whole = 0; 3743#if ENABLE_FEATURE_VI_YANKMARK
3744 char *savereg = reg[YDreg];
3745#endif
3746 int yf, buftype = 0;
3758 yf = YANKDEL; // assume either "c" or "d" 3747 yf = YANKDEL; // assume either "c" or "d"
3759#if ENABLE_FEATURE_VI_YANKMARK 3748#if ENABLE_FEATURE_VI_YANKMARK
3760 if (c == 'y' || c == 'Y') 3749 if (c == 'y' || c == 'Y')
3761 yf = YANKONLY; 3750 yf = YANKONLY;
3762#endif 3751#endif
3763 c1 = 'y'; 3752 c1 = 'y';
3764 if (c != 'Y') 3753 if (c != 'Y') {
3765 c1 = get_one_char(); // get the type of thing to delete 3754 c1 = get_one_char(); // get the type of thing to delete
3755 if (c1 == 27) // ESC- user changed mind and wants out
3756 goto dc6;
3757 }
3766 // determine range, and whether it spans lines 3758 // determine range, and whether it spans lines
3767 ml = find_range(&p, &q, c1); 3759 buftype = find_range(&p, &q, c1);
3768 place_cursor(0, 0); 3760 place_cursor(0, 0);
3769 if (c1 == 27) { // ESC- user changed mind and wants out 3761 if (buftype == -1) { // invalid range
3770 c = c1 = 27; // Escape- do nothing 3762 indicate_error();
3771 } else if (c1 == 'w' || c1 == 'W') { 3763 goto dc6;
3764 }
3765 if (c1 == 'w' || c1 == 'W') {
3772 char *q0 = q; 3766 char *q0 = q;
3773 // don't include trailing WS as part of word 3767 // don't include trailing WS as part of word
3774 while (q > p && isspace(*q)) { 3768 while (q > p && isspace(*q)) {
@@ -3778,25 +3772,13 @@ static void do_cmd(int c)
3778 // for non-change operations WS after NL is not part of word 3772 // for non-change operations WS after NL is not part of word
3779 if (c != 'c' && q != p && *q != '\n') 3773 if (c != 'c' && q != p && *q != '\n')
3780 q = q0; 3774 q = q0;
3781 dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete word
3782 } else if (strchr("^0bBeEft%$ lh\b\177", c1)) {
3783 // partial line copy text into a register and delete
3784 dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete word
3785 } else if (strchr("cdykjGHL+-{}\r\n", c1)) {
3786 // whole line copy text into a register and delete
3787 dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete lines
3788 whole = 1;
3789 } else {
3790 // could not recognize object
3791 c = c1 = 27; // error-
3792 ml = 0;
3793 indicate_error();
3794 } 3775 }
3795 if (ml && whole) { 3776 dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word
3777 if (buftype == WHOLE) {
3796 if (c == 'c') { 3778 if (c == 'c') {
3797 dot = char_insert(dot, '\n', ALLOW_UNDO_CHAIN); 3779 dot = char_insert(dot, '\n', ALLOW_UNDO_CHAIN);
3798 // on the last line of file don't move to prev line 3780 // on the last line of file don't move to prev line
3799 if (whole && dot != (end-1)) { 3781 if (dot != (end-1)) {
3800 dot_prev(); 3782 dot_prev();
3801 } 3783 }
3802 } else if (c == 'd') { 3784 } else if (c == 'd') {
@@ -3804,16 +3786,17 @@ static void do_cmd(int c)
3804 dot_skip_over_ws(); 3786 dot_skip_over_ws();
3805 } 3787 }
3806 } 3788 }
3807 if (c1 != 27) { 3789 // if CHANGING, not deleting, start inserting after the delete
3808 // if CHANGING, not deleting, start inserting after the delete 3790 if (c == 'c') {
3809 if (c == 'c') { 3791 //strcpy(buf, "Change");
3810 strcpy(buf, "Change"); 3792 goto dc_i; // start inserting
3811 goto dc_i; // start inserting 3793 }
3812 } 3794#if ENABLE_FEATURE_VI_YANKMARK
3795 // only update status if a yank has actually happened
3796 if (reg[YDreg] != savereg) {
3813 if (c == 'd') { 3797 if (c == 'd') {
3814 strcpy(buf, "Delete"); 3798 strcpy(buf, "Delete");
3815 } 3799 }
3816#if ENABLE_FEATURE_VI_YANKMARK
3817 if (c == 'y' || c == 'Y') { 3800 if (c == 'y' || c == 'Y') {
3818 strcpy(buf, "Yank"); 3801 strcpy(buf, "Yank");
3819 } 3802 }
@@ -3825,9 +3808,10 @@ static void do_cmd(int c)
3825 } 3808 }
3826 status_line("%s %u lines (%u chars) using [%c]", 3809 status_line("%s %u lines (%u chars) using [%c]",
3827 buf, cnt, (unsigned)strlen(reg[YDreg]), what_reg()); 3810 buf, cnt, (unsigned)strlen(reg[YDreg]), what_reg());
3828#endif
3829 end_cmd_q(); // stop adding to q
3830 } 3811 }
3812#endif
3813 dc6:
3814 end_cmd_q(); // stop adding to q
3831 break; 3815 break;
3832 } 3816 }
3833 case 'k': // k- goto prev line, same col 3817 case 'k': // k- goto prev line, same col
@@ -4271,7 +4255,7 @@ static void edit_file(char *fn)
4271 // save a copy of the current line- for the 'U" command 4255 // save a copy of the current line- for the 'U" command
4272 if (begin_line(dot) != cur_line) { 4256 if (begin_line(dot) != cur_line) {
4273 cur_line = begin_line(dot); 4257 cur_line = begin_line(dot);
4274 text_yank(begin_line(dot), end_line(dot), Ureg); 4258 text_yank(begin_line(dot), end_line(dot), Ureg, PARTIAL);
4275 } 4259 }
4276#endif 4260#endif
4277#if ENABLE_FEATURE_VI_DOT_CMD 4261#if ENABLE_FEATURE_VI_DOT_CMD