From a7eef3d87fa36d527d1cfc749b400df1e69dcb3d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 15 Apr 2018 22:25:54 +0200 Subject: [PATCH 01/15] patch 8.0.1721: no test for using the 'termsize' option Problem: No test for using the 'termsize' option. Solution: Add a test. --- src/testdir/screendump.vim | 7 ++++++- src/testdir/test_terminal.vim | 33 +++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/testdir/screendump.vim b/src/testdir/screendump.vim index 9812e7e6de..af9e371488 100644 --- a/src/testdir/screendump.vim +++ b/src/testdir/screendump.vim @@ -57,7 +57,12 @@ func RunVimInTerminal(arguments, options) " Add -v to have gvim run in the terminal (if possible) let cmd .= ' -v ' . a:arguments let buf = term_start(cmd, {'curwin': 1, 'term_rows': rows, 'term_cols': cols}) - call assert_equal([rows, cols], term_getsize(buf)) + if &termsize == '' + call assert_equal([rows, cols], term_getsize(buf)) + else + let rows = term_getsize(buf)[0] + let cols = term_getsize(buf)[1] + endif " Wait for "All" of the ruler in the status line to be shown. " This can be quite slow (e.g. when using valgrind). diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 5f330f7b19..eb22b0f0c9 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1356,3 +1356,36 @@ func Test_terminal_ansicolors_func() call term_wait(buf) exe buf . 'bwipe' endfunc + +func Test_terminal_termsize_option() + if !CanRunVimInTerminal() + return + endif + set termsize=6x40 + let text = [] + for n in range(10) + call add(text, repeat(n, 50)) + endfor + call writefile(text, 'Xwinsize') + let buf = RunVimInTerminal('Xwinsize', {}) + let win = bufwinid(buf) + call assert_equal([6, 40], term_getsize(buf)) + call assert_equal(6, winheight(win)) + call assert_equal(40, winwidth(win)) + + " resizing the window doesn't resize the terminal. + resize 10 + vertical resize 60 + call assert_equal([6, 40], term_getsize(buf)) + call assert_equal(10, winheight(win)) + call assert_equal(60, winwidth(win)) + + call StopVimInTerminal(buf) + call delete('Xwinsize') + + call assert_fails('set termsize=40', 'E474') + call assert_fails('set termsize=10+40', 'E474') + call assert_fails('set termsize=abc', 'E474') + + set termsize= +endfunc diff --git a/src/version.c b/src/version.c index 2d28206981..851f050220 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1721, /**/ 1720, /**/ From 498c2562e1bcc72492fe8da8a76504f893e9b5fe Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 15 Apr 2018 23:45:15 +0200 Subject: [PATCH 02/15] patch 8.0.1722: cannot specify a minimal size for a terminal window Problem: Cannot specify a minimal size for a terminal window. Solution: Support the "rows*cols" format for 'winsize'. --- runtime/doc/options.txt | 24 +++++--- src/option.c | 4 +- src/terminal.c | 109 ++++++++++++++++++++-------------- src/testdir/test_terminal.vim | 68 ++++++++++++++++++++- src/version.c | 2 + 5 files changed, 152 insertions(+), 55 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 0820699c67..fe400a5fa1 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -7960,15 +7960,23 @@ A jump table for the options with a short description can be found at |Q_op|. 'termsize' 'tms' string (default "") local to window {not in Vi} - Size of the |terminal| window. Format: {rows}x{columns}. + Size of the |terminal| window. Format: {rows}x{columns} or + {rows}*{columns}. - When empty the terminal gets the size from the window. - - When set (e.g., "24x80") the terminal size is not adjusted to the - window size. If the window is smaller only the top-left part is - displayed. - When rows is zero then use the height of the window. - When columns is zero then use the width of the window. - For example: "30x0" uses 30 rows with the current window width. - Using "0x0" is the same as empty. + - When set with a "x" (e.g., "24x80") the terminal size is not + adjusted to the window size. If the window is smaller only the + top-left part is displayed. + - When set with a "*" (e.g., "10*50") the terminal size follows the + window size, but will not be smaller than the specified rows and/or + columns. + - When rows is zero then use the height of the window. + - When columns is zero then use the width of the window. + - Using "0x0" or "0*0" is the same as empty. + + Examples: + "30x0" uses 30 rows and the current window width. + "20*0" uses at least 20 rows and the current window width. + "0*40" uses the current window height and at least 40 columns. Note that the command running in the terminal window may still change the size of the terminal. In that case the Vim window will be adjusted to that size, if possible. diff --git a/src/option.c b/src/option.c index 9ebc511833..ea8c6af9bb 100644 --- a/src/option.c +++ b/src/option.c @@ -7464,7 +7464,9 @@ did_set_string_option( if (*curwin->w_p_tms != NUL) { p = skipdigits(curwin->w_p_tms); - if (p == curwin->w_p_tms || *p != 'x' || *skipdigits(p + 1) != NUL) + if (p == curwin->w_p_tms + || (*p != 'x' && *p != '*') + || *skipdigits(p + 1) != NUL) errmsg = e_invarg; } } diff --git a/src/terminal.c b/src/terminal.c index 0d2dab8ab7..9a551a7844 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -42,26 +42,20 @@ * redirection. Probably in call to channel_set_pipes(). * - Win32: Redirecting output does not work, Test_terminal_redir_file() * is disabled. - * - Copy text in the vterm to the Vim buffer once in a while, so that - * completion works. * - When starting terminal window with shell in terminal, then using :gui to * switch to GUI, shell stops working. Scrollback seems wrong, command * running in shell is still running. - * - in GUI vertical split causes problems. Cursor is flickering. (Hirohito - * Higashi, 2017 Sep 19) - * - after resizing windows overlap. (Boris Staletic, #2164) - * - cursor blinks in terminal on widows with a timer. (xtal8, #2142) - * - Termdebug does not work when Vim build with mzscheme. gdb hangs. - * - After executing a shell command the status line isn't redraw. - * - add test for giving error for invalid 'termsize' value. - * - support minimal size when 'termsize' is "rows*cols". - * - support minimal size when 'termsize' is empty? * - GUI: when using tabs, focus in terminal, click on tab does not work. + * - Copy text in the vterm to the Vim buffer once in a while, so that + * completion works. * - Redrawing is slow with Athena and Motif. Also other GUI? (Ramel Eshed) * - For the GUI fill termios with default values, perhaps like pangoterm: * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134 * - When 'encoding' is not utf-8, or the job is using another encoding, setup * conversions. + * - Termdebug does not work when Vim build with mzscheme: gdb hangs just after + * "run". Everything else works, including communication channel. Not + * initializing mzscheme avoid the problem, thus it's not some #ifdef. */ #include "vim.h" @@ -133,9 +127,6 @@ struct terminal_S { /* last known vterm size */ int tl_rows; int tl_cols; - /* vterm size does not follow window size */ - int tl_rows_fixed; - int tl_cols_fixed; char_u *tl_title; /* NULL or allocated */ char_u *tl_status_text; /* NULL or allocated */ @@ -207,9 +198,38 @@ static int desired_cursor_blink = -1; * 1. Generic code for all systems. */ +/* + * Parse 'termsize' and set "rows" and "cols" for the terminal size in the + * current window. + * Sets "rows" and/or "cols" to zero when it should follow the window size. + * Return TRUE if the size is the minimum size: "24*80". + */ + static int +parse_termsize(win_T *wp, int *rows, int *cols) +{ + int minsize = FALSE; + + *rows = 0; + *cols = 0; + + if (*wp->w_p_tms != NUL) + { + char_u *p = vim_strchr(wp->w_p_tms, 'x'); + + /* Syntax of value was already checked when it's set. */ + if (p == NULL) + { + minsize = TRUE; + p = vim_strchr(wp->w_p_tms, '*'); + } + *rows = atoi((char *)wp->w_p_tms); + *cols = atoi((char *)p + 1); + } + return minsize; +} + /* * Determine the terminal size from 'termsize' and the current window. - * Assumes term->tl_rows and term->tl_cols are zero. */ static void set_term_and_win_size(term_T *term) @@ -224,27 +244,21 @@ set_term_and_win_size(term_T *term) return; } #endif - if (*curwin->w_p_tms != NUL) + if (parse_termsize(curwin, &term->tl_rows, &term->tl_cols)) { - char_u *p = vim_strchr(curwin->w_p_tms, 'x') + 1; - - term->tl_rows = atoi((char *)curwin->w_p_tms); - term->tl_cols = atoi((char *)p); + if (term->tl_rows != 0) + term->tl_rows = MAX(term->tl_rows, curwin->w_height); + if (term->tl_cols != 0) + term->tl_cols = MAX(term->tl_cols, curwin->w_width); } if (term->tl_rows == 0) term->tl_rows = curwin->w_height; else - { win_setheight_win(term->tl_rows, curwin); - term->tl_rows_fixed = TRUE; - } if (term->tl_cols == 0) term->tl_cols = curwin->w_width; else - { win_setwidth_win(term->tl_cols, curwin); - term->tl_cols_fixed = TRUE; - } } /* @@ -2853,6 +2867,10 @@ term_update_window(win_T *wp) VTermScreen *screen; VTermState *state; VTermPos pos; + int rows, cols; + int newrows, newcols; + int minsize; + win_T *twp; if (term == NULL || term->tl_vterm == NULL || term->tl_normal_mode) return FAIL; @@ -2871,31 +2889,32 @@ term_update_window(win_T *wp) * If the window was resized a redraw will be triggered and we get here. * Adjust the size of the vterm unless 'termsize' specifies a fixed size. */ - if ((!term->tl_rows_fixed && term->tl_rows != wp->w_height) - || (!term->tl_cols_fixed && term->tl_cols != wp->w_width)) - { - int rows = term->tl_rows_fixed ? term->tl_rows : wp->w_height; - int cols = term->tl_cols_fixed ? term->tl_cols : wp->w_width; - win_T *twp; + minsize = parse_termsize(wp, &rows, &cols); - FOR_ALL_WINDOWS(twp) + newrows = 99999; + newcols = 99999; + FOR_ALL_WINDOWS(twp) + { + /* When more than one window shows the same terminal, use the + * smallest size. */ + if (twp->w_buffer == term->tl_buffer) { - /* When more than one window shows the same terminal, use the - * smallest size. */ - if (twp->w_buffer == term->tl_buffer) - { - if (!term->tl_rows_fixed && rows > twp->w_height) - rows = twp->w_height; - if (!term->tl_cols_fixed && cols > twp->w_width) - cols = twp->w_width; - } + newrows = MIN(newrows, twp->w_height); + newcols = MIN(newcols, twp->w_width); } + } + newrows = rows == 0 ? newrows : minsize ? MAX(rows, newrows) : rows; + newcols = cols == 0 ? newcols : minsize ? MAX(cols, newcols) : cols; + + if (term->tl_rows != newrows || term->tl_cols != newcols) + { + term->tl_vterm_size_changed = TRUE; - vterm_set_size(vterm, rows, cols); + vterm_set_size(vterm, newrows, newcols); ch_log(term->tl_job->jv_channel, "Resizing terminal to %d lines", - rows); - term_report_winsize(term, rows, cols); + newrows); + term_report_winsize(term, newrows, newcols); } /* The cursor may have been moved when resizing. */ diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index eb22b0f0c9..5aa7597e37 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1357,7 +1357,7 @@ func Test_terminal_ansicolors_func() exe buf . 'bwipe' endfunc -func Test_terminal_termsize_option() +func Test_terminal_termsize_option_fixed() if !CanRunVimInTerminal() return endif @@ -1389,3 +1389,69 @@ func Test_terminal_termsize_option() set termsize= endfunc + +func Test_terminal_termsize_option_zero() + set termsize=0x0 + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize=7x0 + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_equal([7, winwidth(win)], term_getsize(buf)) + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize=0x33 + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_equal([winheight(win), 33], term_getsize(buf)) + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize= +endfunc + +func Test_terminal_termsize_mininmum() + set termsize=10*50 + vsplit + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_inrange(10, 1000, winheight(win)) + call assert_inrange(50, 1000, winwidth(win)) + call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) + + resize 15 + vertical resize 60 + redraw + call assert_equal([15, 60], term_getsize(buf)) + call assert_equal(15, winheight(win)) + call assert_equal(60, winwidth(win)) + + resize 7 + vertical resize 30 + redraw + call assert_equal([10, 50], term_getsize(buf)) + call assert_equal(7, winheight(win)) + call assert_equal(30, winwidth(win)) + + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize=0*0 + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize= +endfunc diff --git a/src/version.c b/src/version.c index 851f050220..9989f9fdb6 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1722, /**/ 1721, /**/ From f3a411783c9736645d6ba480c5ff9d861164c040 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 16 Apr 2018 14:45:45 +0200 Subject: [PATCH 03/15] patch 8.0.1723: using one item array size declaration is misleading Problem: Using one item array size declaration is misleading. Solution: Instead of using "[1]" and actually using a larger array, use "[]". This is to verify that this C99 feature works for all compilers. --- src/getchar.c | 88 ++++++++++++++++++++++++++++----------------------- src/structs.h | 4 +-- src/version.c | 2 ++ 3 files changed, 53 insertions(+), 41 deletions(-) diff --git a/src/getchar.c b/src/getchar.c index 285d5d5d06..5a5041a65f 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -40,9 +40,9 @@ #define MINIMAL_SIZE 20 /* minimal size for b_str */ -static buffheader_T redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -static buffheader_T old_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; -static buffheader_T recordbuff = {{NULL, {NUL}}, NULL, 0, 0}; +static buffheader_T redobuff = {NULL, NULL, 0, 0}; +static buffheader_T old_redobuff = {NULL, NULL, 0, 0}; +static buffheader_T recordbuff = {NULL, NULL, 0, 0}; static int typeahead_char = 0; /* typeahead char that's not flushed */ @@ -138,12 +138,13 @@ free_buff(buffheader_T *buf) { buffblock_T *p, *np; - for (p = buf->bh_first.b_next; p != NULL; p = np) + for (p = buf->bh_first; p != NULL; p = np) { np = p->b_next; vim_free(p); } - buf->bh_first.b_next = NULL; + buf->bh_first = NULL; + buf->bh_curr = NULL; } /* @@ -159,16 +160,16 @@ get_buffcont( char_u *p = NULL; char_u *p2; char_u *str; - buffblock_T *bp; + buffblock_T *bp; /* compute the total length of the string */ - for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) + for (bp = buffer->bh_first; bp != NULL; bp = bp->b_next) count += (long_u)STRLEN(bp->b_str); if ((count || dozero) && (p = lalloc(count + 1, TRUE)) != NULL) { p2 = p; - for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) + for (bp = buffer->bh_first; bp != NULL; bp = bp->b_next) for (str = bp->b_str; *str; ) *p2++ = *str++; *p2 = NUL; @@ -232,17 +233,17 @@ add_buff( long slen) /* length of "s" or -1 */ { buffblock_T *p; - long_u len; + long_u len; if (slen < 0) slen = (long)STRLEN(s); if (slen == 0) /* don't add empty strings */ return; - if (buf->bh_first.b_next == NULL) /* first add to list */ + if (buf->bh_first == NULL) /* first add to list */ { buf->bh_space = 0; - buf->bh_curr = &(buf->bh_first); + buf->bh_curr = NULL; } else if (buf->bh_curr == NULL) /* buffer has already been read */ { @@ -250,9 +251,9 @@ add_buff( return; } else if (buf->bh_index != 0) - mch_memmove(buf->bh_first.b_next->b_str, - buf->bh_first.b_next->b_str + buf->bh_index, - STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1); + mch_memmove(buf->bh_first->b_str, + buf->bh_first->b_str + buf->bh_index, + STRLEN(buf->bh_first->b_str + buf->bh_index) + 1); buf->bh_index = 0; if (buf->bh_space >= (int)slen) @@ -267,16 +268,25 @@ add_buff( len = MINIMAL_SIZE; else len = slen; - p = (buffblock_T *)lalloc((long_u)(sizeof(buffblock_T) + len), - TRUE); + p = (buffblock_T *)lalloc((long_u)(sizeof(buffblock_T) + len + 1), + TRUE); if (p == NULL) return; /* no space, just forget it */ buf->bh_space = (int)(len - slen); vim_strncpy(p->b_str, s, (size_t)slen); - p->b_next = buf->bh_curr->b_next; - buf->bh_curr->b_next = p; - buf->bh_curr = p; + if (buf->bh_curr == NULL) + { + p->b_next = NULL; + buf->bh_first = p; + buf->bh_curr = p; + } + else + { + p->b_next = buf->bh_curr->b_next; + buf->bh_curr->b_next = p; + buf->bh_curr = p; + } } return; } @@ -348,10 +358,10 @@ add_char_buff(buffheader_T *buf, int c) } /* First read ahead buffer. Used for translated commands. */ -static buffheader_T readbuf1 = {{NULL, {NUL}}, NULL, 0, 0}; +static buffheader_T readbuf1 = {NULL, NULL, 0, 0}; /* Second read ahead buffer. Used for redo. */ -static buffheader_T readbuf2 = {{NULL, {NUL}}, NULL, 0, 0}; +static buffheader_T readbuf2 = {NULL, NULL, 0, 0}; /* * Get one byte from the read buffers. Use readbuf1 one first, use readbuf2 @@ -376,17 +386,17 @@ read_readbuf(buffheader_T *buf, int advance) char_u c; buffblock_T *curr; - if (buf->bh_first.b_next == NULL) /* buffer is empty */ + if (buf->bh_first == NULL) /* buffer is empty */ return NUL; - curr = buf->bh_first.b_next; + curr = buf->bh_first; c = curr->b_str[buf->bh_index]; if (advance) { if (curr->b_str[++buf->bh_index] == NUL) { - buf->bh_first.b_next = curr->b_next; + buf->bh_first = curr->b_next; vim_free(curr); buf->bh_index = 0; } @@ -400,14 +410,14 @@ read_readbuf(buffheader_T *buf, int advance) static void start_stuff(void) { - if (readbuf1.bh_first.b_next != NULL) + if (readbuf1.bh_first != NULL) { - readbuf1.bh_curr = &(readbuf1.bh_first); + readbuf1.bh_curr = readbuf1.bh_first; readbuf1.bh_space = 0; } - if (readbuf2.bh_first.b_next != NULL) + if (readbuf2.bh_first != NULL) { - readbuf2.bh_curr = &(readbuf2.bh_first); + readbuf2.bh_curr = readbuf2.bh_first; readbuf2.bh_space = 0; } } @@ -418,8 +428,8 @@ start_stuff(void) int stuff_empty(void) { - return (readbuf1.bh_first.b_next == NULL - && readbuf2.bh_first.b_next == NULL); + return (readbuf1.bh_first == NULL + && readbuf2.bh_first == NULL); } /* @@ -429,7 +439,7 @@ stuff_empty(void) int readbuf1_empty(void) { - return (readbuf1.bh_first.b_next == NULL); + return (readbuf1.bh_first == NULL); } /* @@ -494,7 +504,7 @@ ResetRedobuff(void) { free_buff(&old_redobuff); old_redobuff = redobuff; - redobuff.bh_first.b_next = NULL; + redobuff.bh_first = NULL; } } @@ -509,7 +519,7 @@ CancelRedo(void) { free_buff(&redobuff); redobuff = old_redobuff; - old_redobuff.bh_first.b_next = NULL; + old_redobuff.bh_first = NULL; start_stuff(); while (read_readbuffers(TRUE) != NUL) ; @@ -526,9 +536,9 @@ saveRedobuff(save_redo_T *save_redo) char_u *s; save_redo->sr_redobuff = redobuff; - redobuff.bh_first.b_next = NULL; + redobuff.bh_first = NULL; save_redo->sr_old_redobuff = old_redobuff; - old_redobuff.bh_first.b_next = NULL; + old_redobuff.bh_first = NULL; /* Make a copy, so that ":normal ." in a function works. */ s = get_buffcont(&save_redo->sr_redobuff, FALSE); @@ -747,9 +757,9 @@ read_redo(int init, int old_redo) if (init) { if (old_redo) - bp = old_redobuff.bh_first.b_next; + bp = old_redobuff.bh_first; else - bp = redobuff.bh_first.b_next; + bp = redobuff.bh_first; if (bp == NULL) return FAIL; p = bp->b_str; @@ -1372,9 +1382,9 @@ save_typeahead(tasave_T *tp) old_char = -1; tp->save_readbuf1 = readbuf1; - readbuf1.bh_first.b_next = NULL; + readbuf1.bh_first = NULL; tp->save_readbuf2 = readbuf2; - readbuf2.bh_first.b_next = NULL; + readbuf2.bh_first = NULL; # ifdef USE_INPUT_BUF tp->save_inputbuf = get_input_buf(); # endif diff --git a/src/structs.h b/src/structs.h index d3f98ac12f..92025274ec 100644 --- a/src/structs.h +++ b/src/structs.h @@ -511,7 +511,7 @@ typedef struct buffheader buffheader_T; struct buffblock { buffblock_T *b_next; /* pointer to next buffblock */ - char_u b_str[1]; /* contents (actually longer) */ + char_u b_str[]; /* contents (flexible array) */ }; /* @@ -519,7 +519,7 @@ struct buffblock */ struct buffheader { - buffblock_T bh_first; /* first (dummy) block of list */ + buffblock_T *bh_first; /* first block of the list */ buffblock_T *bh_curr; /* buffblock for appending */ int bh_index; /* index for reading */ int bh_space; /* space in bh_curr for appending */ diff --git a/src/version.c b/src/version.c index 9989f9fdb6..bdd1a3d7e5 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1723, /**/ 1722, /**/ From 06965b838f3677251668dca726b07c5ad2499341 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 16 Apr 2018 15:40:50 +0200 Subject: [PATCH 04/15] patch 8.0.1724: declarations cannot be halfway a block Problem: Declarations cannot be halfway a block. Solution: Move one declaration to check if this works for all compilers. --- src/main.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 6d351b6ff3..a773122a89 100644 --- a/src/main.c +++ b/src/main.c @@ -1056,7 +1056,6 @@ main_loop( int cmdwin, /* TRUE when working in the command-line window */ int noexmode) /* TRUE when return on entering Ex mode */ { - oparg_T oa; /* operator arguments */ volatile int previous_got_int = FALSE; /* "got_int" was TRUE */ #ifdef FEAT_CONCEAL /* these are static to avoid a compiler warning */ @@ -1096,6 +1095,7 @@ main_loop( } #endif + oparg_T oa; /* operator arguments */ clear_oparg(&oa); while (!cmdwin #ifdef FEAT_CMDWIN diff --git a/src/version.c b/src/version.c index bdd1a3d7e5..f81bcfab94 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1724, /**/ 1723, /**/ From 32c67ba733abcd4f2d729595fdccb2295445636a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 16 Apr 2018 16:21:49 +0200 Subject: [PATCH 05/15] patch 8.0.1725: terminal debugger doesn't handle command arguments Problem: Terminal debugger doesn't handle command arguments. Solution: Add the :TermdebugCommand command. Use a ! to execute right away. (Christian Brabandt) --- runtime/doc/terminal.txt | 49 +++++++++++++------ .../dist/opt/termdebug/plugin/termdebug.vim | 33 +++++++++++-- src/version.c | 2 + 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index 8deba3922d..cce087f7a4 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -623,7 +623,8 @@ Starting ~ Load the plugin with this command: > packadd termdebug < *:Termdebug* -To start debugging use `:Termdebug` followed by the command name, for example: > +To start debugging use `:Termdebug` or `:TermdebugCommand`` followed by the +command name, for example: > :Termdebug vim This opens two windows: @@ -641,7 +642,8 @@ source file location will be displayed, if possible. A sign is used to highlight the current position, using highlight group debugPC. If the buffer in the current window is modified, another window will be opened -to display the current gdb position. +to display the current gdb position. You can use `:Winbar` to add a window +toolbar there. Focus the terminal of the executed program to interact with it. This works the same as any command running in a terminal window. @@ -650,12 +652,25 @@ When the debugger ends, typically by typing "quit" in the gdb window, the two opened windows are closed. Only one debugger can be active at a time. + *:TermdebugCommand* +If you want to give specific commands to the command being debugged, you can +use the `:TermdebugCommand` command followed by the command name and +additional parameters. > + :TermdebugCommand vim --clean -c ':set nu' -To attach gdb to an already running executable, or use a core file, pass extra +Both the `:Termdebug` and `:TermdebugCommand` support an optional "!" bang +argument to start the command right away, without pausing at the gdb window +(and cursor will be in the debugged window). For example: > + :TermdebugCommand! vim --clean + +To attach gdb to an already running executable or use a core file, pass extra arguments. E.g.: > :Termdebug vim core :Termdebug vim 98343 +If no argument is given, you'll end up in a gdb window, in which you need to +specify which command to run using e.g. the gdb `file` command. + Example session ~ *termdebug-example* @@ -728,18 +743,20 @@ Put focus on the gdb window to type commands there. Some common ones are: - frame N go to the Nth stack frame - continue continue execution -In the window showing the source code these commands can be used to control gdb: + *:Run* *:Arguments* +In the window showing the source code these commands can be used to control +gdb: `:Run` [args] run the program with [args] or the previous arguments `:Arguments` {args} set arguments for the next `:Run` - `:Break` set a breakpoint at the current line; a sign will be displayed - `:Clear` delete the breakpoint at the current line + *:Break* set a breakpoint at the current line; a sign will be displayed + *:Clear* delete the breakpoint at the current line - `:Step` execute the gdb "step" command - `:Over` execute the gdb "next" command (`:Next` is a Vim command) - `:Finish` execute the gdb "finish" command - `:Continue` execute the gdb "continue" command - `:Stop` interrupt the program + *:Step* execute the gdb "step" command + *:Over* execute the gdb "next" command (`:Next` is a Vim command) + *:Finish* execute the gdb "finish" command + *:Continue* execute the gdb "continue" command + *:Stop* interrupt the program If 'mouse' is set the plugin adds a window toolbar with these entries: Step `:Step` @@ -750,7 +767,7 @@ If 'mouse' is set the plugin adds a window toolbar with these entries: Eval `:Evaluate` This way you can use the mouse to perform the most common commands. You need to have the 'mouse' option set to enable mouse clicks. - + *:Winbar* You can add the window toolbar in other windows you open with: > :Winbar @@ -761,7 +778,7 @@ abandoned. Inspecting variables ~ - *termdebug-variables* + *termdebug-variables* *:Evaluate* `:Evaluate` evaluate the expression under the cursor `K` same `:Evaluate` {expr} evaluate {expr} @@ -773,9 +790,9 @@ You can usually shorten `:Evaluate` to `:Ev`. Other commands ~ *termdebug-commands* - :Gdb jump to the gdb window - :Program jump to the window with the running program - :Source jump to the window with the source code, create it if there + *:Gdb* jump to the gdb window + *:Program* jump to the window with the running program + *:Source* jump to the window with the source code, create it if there isn't one diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index ded114a2d7..f2f0f0944d 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -25,7 +25,8 @@ endif " The command that starts debugging, e.g. ":Termdebug vim". " To end type "quit" in the gdb window. -command -nargs=* -complete=file Termdebug call s:StartDebug() +command -nargs=* -complete=file -bang Termdebug call s:StartDebug(0, ) +command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(0, ) " Name of the gdb command, defaults to "gdb". if !exists('termdebugger') @@ -43,7 +44,17 @@ else endif hi default debugBreakpoint term=reverse ctermbg=red guibg=red -func s:StartDebug(...) +func s:StartDebug(bang, ...) + " First argument is the command to debug, second core file or process ID. + call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang}) +endfunc + +func s:StartDebugCommand(bang, ...) + " First argument is the command to debug, rest are run arguments. + call s:StartDebug_internal({'gdb_args': [a:1], 'proc_args': a:000[1:], 'bang': a:bang}) +endfunc + +func s:StartDebug_internal(dict) if exists('s:gdbwin') echoerr 'Terminal debugger already running' return @@ -95,7 +106,10 @@ func s:StartDebug(...) " Open a terminal window to run the debugger. " Add -quiet to avoid the intro message causing a hit-enter prompt. - let cmd = [g:termdebugger, '-quiet', '-tty', pty] + a:000 + let gdb_args = get(a:dict, 'gdb_args', []) + let proc_args = get(a:dict, 'proc_args', []) + + let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args echomsg 'executing "' . join(cmd) . '"' let s:gdbbuf = term_start(cmd, { \ 'exit_cb': function('s:EndDebug'), @@ -109,6 +123,11 @@ func s:StartDebug(...) endif let s:gdbwin = win_getid(winnr()) + " Set arguments to be run + if len(proc_args) + call term_sendkeys(s:gdbbuf, 'set args ' . join(proc_args) . "\r") + endif + " Connect gdb to the communication pty, using the GDB/MI interface call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r") @@ -182,6 +201,14 @@ func s:StartDebug(...) au BufRead * call s:BufRead() au BufUnload * call s:BufUnloaded() augroup END + + " Run the command if the bang attribute was given + " and got to the window + if get(a:dict, 'bang', 0) + call s:SendCommand('-exec-run') + call win_gotoid(s:ptywin) + endif + endfunc func s:EndDebug(job, status) diff --git a/src/version.c b/src/version.c index f81bcfab94..f3143fe97b 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1725, /**/ 1724, /**/ From df2c774ded4c2ed169390a352099c23b6db657c4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 16 Apr 2018 17:06:09 +0200 Subject: [PATCH 06/15] patch 8.0.1726: older MSVC doesn't support declarations halfway a block Problem: Older MSVC doesn't support declarations halfway a block. Solution: Move the declaration back to the start of the block. --- src/main.c | 12 ++++++------ src/version.c | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index a773122a89..3b366b507d 100644 --- a/src/main.c +++ b/src/main.c @@ -1056,6 +1056,7 @@ main_loop( int cmdwin, /* TRUE when working in the command-line window */ int noexmode) /* TRUE when return on entering Ex mode */ { + oparg_T oa; /* operator arguments */ volatile int previous_got_int = FALSE; /* "got_int" was TRUE */ #ifdef FEAT_CONCEAL /* these are static to avoid a compiler warning */ @@ -1095,7 +1096,6 @@ main_loop( } #endif - oparg_T oa; /* operator arguments */ clear_oparg(&oa); while (!cmdwin #ifdef FEAT_CMDWIN @@ -1383,11 +1383,6 @@ getout_preserve_modified(int exitval) void getout(int exitval) { - tabpage_T *tp; - tabpage_T *next_tp; - buf_T *buf; - win_T *wp; - exiting = TRUE; #if defined(FEAT_JOB_CHANNEL) ch_log(NULL, "Exiting..."); @@ -1416,6 +1411,11 @@ getout(int exitval) if (v_dying <= 1) { + tabpage_T *tp; + tabpage_T *next_tp; + buf_T *buf; + win_T *wp; + /* Trigger BufWinLeave for all windows, but only once per buffer. */ for (tp = first_tabpage; tp != NULL; tp = next_tp) { diff --git a/src/version.c b/src/version.c index f3143fe97b..ba093c56f1 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1726, /**/ 1725, /**/ From 353eeeaca269ed5e83900bd4a24dc6dc80bb4880 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 16 Apr 2018 18:04:57 +0200 Subject: [PATCH 07/15] patch 8.0.1727: qf_get_properties() function is too long Problem: qf_get_properties() function is too long. Solution: Refactor the code. (Yegappan Lakshmanan, closes #2807) --- src/quickfix.c | 330 ++++++++++++++++++++++++++++++------------------- src/version.c | 2 + 2 files changed, 203 insertions(+), 129 deletions(-) diff --git a/src/quickfix.c b/src/quickfix.c index c370761bf2..39e3913c09 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -1183,7 +1183,8 @@ qf_init_ext( fields.errmsglen = CMDBUFFSIZE + 1; fields.errmsg = alloc_id(fields.errmsglen, aid_qf_errmsg); fields.pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern); - if (fields.namebuf == NULL || fields.errmsg == NULL || fields.pattern == NULL) + if (fields.namebuf == NULL || fields.errmsg == NULL + || fields.pattern == NULL) goto qf_init_end; if (efile != NULL && (state.fd = mch_fopen((char *)efile, "r")) == NULL) @@ -1817,7 +1818,6 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack) } } - /* * pop dirbuf from the directory stack and return previous directory or NULL if * stack is empty @@ -4948,7 +4948,8 @@ enum { }; /* - * Parse text from 'di' and return the quickfix list items + * Parse text from 'di' and return the quickfix list items. + * Existing quickfix lists are not modified. */ static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict) @@ -5017,25 +5018,13 @@ qf_winid(qf_info_T *qi) } /* - * Return quickfix/location list details (title) as a - * dictionary. 'what' contains the details to return. If 'list_idx' is -1, - * then current list is used. Otherwise the specified list is used. + * Convert the keys in 'what' to quickfix list property flags. */ - int -qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict) + static int +qf_getprop_keys2flags(dict_T *what) { - qf_info_T *qi = &ql_info; - int status = OK; - int qf_idx; - dictitem_T *di; int flags = QF_GETLIST_NONE; - if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL) - return qf_get_list_from_lines(what, di, retdict); - - if (wp != NULL) - qi = GET_LOC_LIST(wp); - if (dict_find(what, (char_u *)"all", -1) != NULL) flags |= QF_GETLIST_ALL; @@ -5066,140 +5055,223 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict) if (dict_find(what, (char_u *)"changedtick", -1) != NULL) flags |= QF_GETLIST_TICK; - if (qi != NULL && qi->qf_listcount != 0) - { - qf_idx = qi->qf_curlist; /* default is the current list */ - if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL) - { - /* Use the specified quickfix/location list */ - if (di->di_tv.v_type == VAR_NUMBER) - { - /* for zero use the current list */ - if (di->di_tv.vval.v_number != 0) - { - qf_idx = di->di_tv.vval.v_number - 1; - if (qf_idx < 0 || qf_idx >= qi->qf_listcount) - qf_idx = -1; - } - } - else if (di->di_tv.v_type == VAR_STRING - && di->di_tv.vval.v_string != NULL - && STRCMP(di->di_tv.vval.v_string, "$") == 0) - /* Get the last quickfix list number */ - qf_idx = qi->qf_listcount - 1; - else - qf_idx = -1; - flags |= QF_GETLIST_NR; - } + return flags; +} - if ((di = dict_find(what, (char_u *)"id", -1)) != NULL) +/* + * Return the quickfix list index based on 'nr' or 'id' in 'what'. + * If 'nr' and 'id' are not present in 'what' then return the current + * quickfix list index. + * If 'nr' is zero then return the current quickfix list index. + * If 'nr' is '$' then return the last quickfix list index. + * If 'id' is present then return the index of the quickfix list with that id. + * If 'id' is zero then return the quickfix list index specified by 'nr'. + * Return -1, if quickfix list is not present or if the stack is empty. + */ + static int +qf_getprop_qfidx(qf_info_T *qi, dict_T *what) +{ + int qf_idx; + dictitem_T *di; + + qf_idx = qi->qf_curlist; /* default is the current list */ + if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL) + { + /* Use the specified quickfix/location list */ + if (di->di_tv.v_type == VAR_NUMBER) { - /* Look for a list with the specified id */ - if (di->di_tv.v_type == VAR_NUMBER) + /* for zero use the current list */ + if (di->di_tv.vval.v_number != 0) { - /* - * For zero, use the current list or the list specifed by 'nr' - */ - if (di->di_tv.vval.v_number != 0) - qf_idx = qf_id2nr(qi, di->di_tv.vval.v_number); - flags |= QF_GETLIST_ID; + qf_idx = di->di_tv.vval.v_number - 1; + if (qf_idx < 0 || qf_idx >= qi->qf_listcount) + qf_idx = -1; } - else - qf_idx = -1; } + else if (di->di_tv.v_type == VAR_STRING + && di->di_tv.vval.v_string != NULL + && STRCMP(di->di_tv.vval.v_string, "$") == 0) + /* Get the last quickfix list number */ + qf_idx = qi->qf_listcount - 1; + else + qf_idx = -1; } + if ((di = dict_find(what, (char_u *)"id", -1)) != NULL) + { + /* Look for a list with the specified id */ + if (di->di_tv.v_type == VAR_NUMBER) + { + /* + * For zero, use the current list or the list specified by 'nr' + */ + if (di->di_tv.vval.v_number != 0) + qf_idx = qf_id2nr(qi, di->di_tv.vval.v_number); + } + else + qf_idx = -1; + } + + return qf_idx; +} + +/* + * Return default values for quickfix list properties in retdict. + */ + static int +qf_getprop_defaults(qf_info_T *qi, int flags, dict_T *retdict) +{ + int status = OK; + + if (flags & QF_GETLIST_TITLE) + status = dict_add_nr_str(retdict, "title", 0L, (char_u *)""); + if ((status == OK) && (flags & QF_GETLIST_ITEMS)) + { + list_T *l = list_alloc(); + if (l != NULL) + status = dict_add_list(retdict, "items", l); + else + status = FAIL; + } + if ((status == OK) && (flags & QF_GETLIST_NR)) + status = dict_add_nr_str(retdict, "nr", 0L, NULL); + if ((status == OK) && (flags & QF_GETLIST_WINID)) + status = dict_add_nr_str(retdict, "winid", qf_winid(qi), NULL); + if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) + status = dict_add_nr_str(retdict, "context", 0L, (char_u *)""); + if ((status == OK) && (flags & QF_GETLIST_ID)) + status = dict_add_nr_str(retdict, "id", 0L, NULL); + if ((status == OK) && (flags & QF_GETLIST_IDX)) + status = dict_add_nr_str(retdict, "idx", 0L, NULL); + if ((status == OK) && (flags & QF_GETLIST_SIZE)) + status = dict_add_nr_str(retdict, "size", 0L, NULL); + if ((status == OK) && (flags & QF_GETLIST_TICK)) + status = dict_add_nr_str(retdict, "changedtick", 0L, NULL); + + return status; +} + +/* + * Return the quickfix list title as 'title' in retdict + */ + static int +qf_getprop_title(qf_info_T *qi, int qf_idx, dict_T *retdict) +{ + char_u *t; + + t = qi->qf_lists[qf_idx].qf_title; + if (t == NULL) + t = (char_u *)""; + return dict_add_nr_str(retdict, "title", 0L, t); +} + +/* + * Return the quickfix list items/entries as 'items' in retdict + */ + static int +qf_getprop_items(qf_info_T *qi, int qf_idx, dict_T *retdict) +{ + int status = OK; + list_T *l = list_alloc(); + if (l != NULL) + { + (void)get_errorlist(qi, NULL, qf_idx, l); + dict_add_list(retdict, "items", l); + } + else + status = FAIL; + + return status; +} + +/* + * Return the quickfix list context (if any) as 'context' in retdict. + */ + static int +qf_getprop_ctx(qf_info_T *qi, int qf_idx, dict_T *retdict) +{ + int status; + dictitem_T *di; + + if (qi->qf_lists[qf_idx].qf_ctx != NULL) + { + di = dictitem_alloc((char_u *)"context"); + if (di != NULL) + { + copy_tv(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv); + status = dict_add(retdict, di); + if (status == FAIL) + dictitem_free(di); + } + else + status = FAIL; + } + else + status = dict_add_nr_str(retdict, "context", 0L, (char_u *)""); + + return status; +} + +/* + * Return the quickfix list index as 'idx' in retdict + */ + static int +qf_getprop_idx(qf_info_T *qi, int qf_idx, dict_T *retdict) +{ + int idx = qi->qf_lists[qf_idx].qf_index; + if (qi->qf_lists[qf_idx].qf_count == 0) + /* For empty lists, qf_index is set to 1 */ + idx = 0; + return dict_add_nr_str(retdict, "idx", idx, NULL); +} + +/* + * Return quickfix/location list details (title) as a + * dictionary. 'what' contains the details to return. If 'list_idx' is -1, + * then current list is used. Otherwise the specified list is used. + */ + int +qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict) +{ + qf_info_T *qi = &ql_info; + int status = OK; + int qf_idx; + dictitem_T *di; + int flags = QF_GETLIST_NONE; + + if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL) + return qf_get_list_from_lines(what, di, retdict); + + if (wp != NULL) + qi = GET_LOC_LIST(wp); + + flags = qf_getprop_keys2flags(what); + + if (qi != NULL && qi->qf_listcount != 0) + qf_idx = qf_getprop_qfidx(qi, what); + /* List is not present or is empty */ if (qi == NULL || qi->qf_listcount == 0 || qf_idx == -1) - { - if (flags & QF_GETLIST_TITLE) - status = dict_add_nr_str(retdict, "title", 0L, (char_u *)""); - if ((status == OK) && (flags & QF_GETLIST_ITEMS)) - { - list_T *l = list_alloc(); - if (l != NULL) - status = dict_add_list(retdict, "items", l); - else - status = FAIL; - } - if ((status == OK) && (flags & QF_GETLIST_NR)) - status = dict_add_nr_str(retdict, "nr", 0L, NULL); - if ((status == OK) && (flags & QF_GETLIST_WINID)) - status = dict_add_nr_str(retdict, "winid", qf_winid(qi), NULL); - if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) - status = dict_add_nr_str(retdict, "context", 0L, (char_u *)""); - if ((status == OK) && (flags & QF_GETLIST_ID)) - status = dict_add_nr_str(retdict, "id", 0L, NULL); - if ((status == OK) && (flags & QF_GETLIST_IDX)) - status = dict_add_nr_str(retdict, "idx", 0L, NULL); - if ((status == OK) && (flags & QF_GETLIST_SIZE)) - status = dict_add_nr_str(retdict, "size", 0L, NULL); - if ((status == OK) && (flags & QF_GETLIST_TICK)) - status = dict_add_nr_str(retdict, "changedtick", 0L, NULL); - - return status; - } + return qf_getprop_defaults(qi, flags, retdict); if (flags & QF_GETLIST_TITLE) - { - char_u *t; - t = qi->qf_lists[qf_idx].qf_title; - if (t == NULL) - t = (char_u *)""; - status = dict_add_nr_str(retdict, "title", 0L, t); - } + status = qf_getprop_title(qi, qf_idx, retdict); if ((status == OK) && (flags & QF_GETLIST_NR)) status = dict_add_nr_str(retdict, "nr", qf_idx + 1, NULL); if ((status == OK) && (flags & QF_GETLIST_WINID)) status = dict_add_nr_str(retdict, "winid", qf_winid(qi), NULL); if ((status == OK) && (flags & QF_GETLIST_ITEMS)) - { - list_T *l = list_alloc(); - if (l != NULL) - { - (void)get_errorlist(qi, NULL, qf_idx, l); - dict_add_list(retdict, "items", l); - } - else - status = FAIL; - } - + status = qf_getprop_items(qi, qf_idx, retdict); if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) - { - if (qi->qf_lists[qf_idx].qf_ctx != NULL) - { - di = dictitem_alloc((char_u *)"context"); - if (di != NULL) - { - copy_tv(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv); - status = dict_add(retdict, di); - if (status == FAIL) - dictitem_free(di); - } - else - status = FAIL; - } - else - status = dict_add_nr_str(retdict, "context", 0L, (char_u *)""); - } - + status = qf_getprop_ctx(qi, qf_idx, retdict); if ((status == OK) && (flags & QF_GETLIST_ID)) status = dict_add_nr_str(retdict, "id", qi->qf_lists[qf_idx].qf_id, NULL); - if ((status == OK) && (flags & QF_GETLIST_IDX)) - { - int idx = qi->qf_lists[qf_idx].qf_index; - if (qi->qf_lists[qf_idx].qf_count == 0) - /* For empty lists, qf_index is set to 1 */ - idx = 0; - status = dict_add_nr_str(retdict, "idx", idx, NULL); - } - + status = qf_getprop_idx(qi, qf_idx, retdict); if ((status == OK) && (flags & QF_GETLIST_SIZE)) status = dict_add_nr_str(retdict, "size", qi->qf_lists[qf_idx].qf_count, NULL); - if ((status == OK) && (flags & QF_GETLIST_TICK)) status = dict_add_nr_str(retdict, "changedtick", qi->qf_lists[qf_idx].qf_changedtick, NULL); @@ -5609,7 +5681,7 @@ mark_quickfix_ctx(qf_info_T *qi, int copyID) /* * Mark the context of the quickfix list and the location lists (if present) as - * "in use". So that garabage collection doesn't free the context. + * "in use". So that garbage collection doesn't free the context. */ int set_ref_in_quickfix(int copyID) diff --git a/src/version.c b/src/version.c index ba093c56f1..ec58863888 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1727, /**/ 1726, /**/ From 1feab2b9cc355edc2f24814c35b72ae5e74eb2ae Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 17 Apr 2018 20:12:08 +0200 Subject: [PATCH 08/15] patch 8.0.1728: condition always false, useless code Problem: Condition always false, useless code. Solution: Remove the code. (Nikolai Pavlov, closes #2808) --- src/message.c | 2 -- src/version.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/message.c b/src/message.c index 71965852f2..25c22f63e5 100644 --- a/src/message.c +++ b/src/message.c @@ -1703,8 +1703,6 @@ str2special( { c = TO_SPECIAL(str[1], str[2]); str += 2; - if (c == KS_ZERO) /* display as ^@ or */ - c = NUL; } if (IS_SPECIAL(c) || modifiers) /* special key */ special = TRUE; diff --git a/src/version.c b/src/version.c index ec58863888..edbe2ae16b 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1728, /**/ 1727, /**/ From ea3ece405ab55f44018257bd2f5021231af8e87f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 17 Apr 2018 20:14:39 +0200 Subject: [PATCH 09/15] patch 8.0.1729: no comma after last enum item Problem: No comma after last enum item. Solution: Add a few commas to check if this works for all compilers. Also add a few // comments. --- src/structs.h | 54 +++++++++++++++++++++++++-------------------------- src/version.c | 2 ++ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/structs.h b/src/structs.h index 92025274ec..e3ad867dbf 100644 --- a/src/structs.h +++ b/src/structs.h @@ -827,9 +827,9 @@ struct msglist */ typedef enum { - ET_USER, /* exception caused by ":throw" command */ - ET_ERROR, /* error exception */ - ET_INTERRUPT /* interrupt exception triggered by Ctrl-C */ + ET_USER, // exception caused by ":throw" command + ET_ERROR, // error exception + ET_INTERRUPT, // interrupt exception triggered by Ctrl-C } except_type_T; /* @@ -1190,16 +1190,16 @@ typedef struct channel_S channel_T; typedef enum { VAR_UNKNOWN = 0, - VAR_NUMBER, /* "v_number" is used */ - VAR_STRING, /* "v_string" is used */ - VAR_FUNC, /* "v_string" is function name */ - VAR_PARTIAL, /* "v_partial" is used */ - VAR_LIST, /* "v_list" is used */ - VAR_DICT, /* "v_dict" is used */ - VAR_FLOAT, /* "v_float" is used */ - VAR_SPECIAL, /* "v_number" is used */ - VAR_JOB, /* "v_job" is used */ - VAR_CHANNEL /* "v_channel" is used */ + VAR_NUMBER, // "v_number" is used + VAR_STRING, // "v_string" is used + VAR_FUNC, // "v_string" is function name + VAR_PARTIAL, // "v_partial" is used + VAR_LIST, // "v_list" is used + VAR_DICT, // "v_dict" is used + VAR_FLOAT, // "v_float" is used + VAR_SPECIAL, // "v_number" is used + VAR_JOB, // "v_job" is used + VAR_CHANNEL, // "v_channel" is used } vartype_T; /* @@ -1456,8 +1456,8 @@ typedef enum { JOB_FAILED, JOB_STARTED, - JOB_ENDED, /* detected job done */ - JOB_FINISHED /* job done and cleanup done */ + JOB_ENDED, // detected job done + JOB_FINISHED, // job done and cleanup done } jobstatus_T; /* @@ -1531,11 +1531,11 @@ typedef enum MODE_NL = 0, MODE_RAW, MODE_JSON, - MODE_JS + MODE_JS, } ch_mode_T; typedef enum { - JIO_PIPE, /* default */ + JIO_PIPE, // default JIO_NULL, JIO_FILE, JIO_BUFFER, @@ -1557,7 +1557,7 @@ typedef enum { PART_IN, # define CH_IN_FD CH_PART_FD(PART_IN) #endif - PART_COUNT + PART_COUNT, } ch_part_T; #define INVALID_FD (-1) @@ -3252,15 +3252,15 @@ typedef struct { */ typedef enum { - TYPE_UNKNOWN = 0 - , TYPE_EQUAL /* == */ - , TYPE_NEQUAL /* != */ - , TYPE_GREATER /* > */ - , TYPE_GEQUAL /* >= */ - , TYPE_SMALLER /* < */ - , TYPE_SEQUAL /* <= */ - , TYPE_MATCH /* =~ */ - , TYPE_NOMATCH /* !~ */ + TYPE_UNKNOWN = 0, + TYPE_EQUAL, // == + TYPE_NEQUAL, // != + TYPE_GREATER, // > + TYPE_GEQUAL, // >= + TYPE_SMALLER, // < + TYPE_SEQUAL, // <= + TYPE_MATCH, // =~ + TYPE_NOMATCH, // !~ } exptype_T; /* diff --git a/src/version.c b/src/version.c index edbe2ae16b..aa1e93fdd1 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1729, /**/ 1728, /**/ From 561f8a5a4612751c2a4ebd6bf918cbc3be867350 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 17 Apr 2018 22:02:45 +0200 Subject: [PATCH 10/15] patch 8.0.1730: no configure check for the used C99 features Problem: No configure check for the used C99 features. Solution: Add a compilation check. Tentatively document C99 features. --- runtime/doc/develop.txt | 46 ++++++++++++++++++++++++++++++++++++++--- src/auto/configure | 34 ++++++++++++++++++++++++++++++ src/configure.ac | 23 +++++++++++++++++++++ src/version.c | 2 ++ 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index ed4e9e38ba..d90e4a3dd2 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -1,4 +1,4 @@ -*develop.txt* For Vim version 8.0. Last change: 2017 Jul 31 +*develop.txt* For Vim version 8.0. Last change: 2018 Apr 17 VIM REFERENCE MANUAL by Bram Moolenaar @@ -185,9 +185,49 @@ The basic steps to make changes to the code: C COMPILER *style-compiler* The minimal C compiler version supported is C89, also known as ANSI C. -Later standards don't add much and C89 is the widest supported. +Later standards, such as C99, are not widely supported, or at least not 100% +supported. Therefore we use only some of the C99 features and disallow some +(at least for now). -One restriction that this implies: no // comments, only /* comments */. +Please don't make changes everywhere to use the C99 features, it causes merge +problems for existing patches. Only use them for new and changed code. + +Comments ~ + +Traditionally Vim uses /* comments */. We intend to keep it that way, +especially for file and function headers. For new code or lines of code that +change, it is allowed to use // comments. Especially when it comes after +code: + int some_var; // single line comment useful here + +Enums ~ + +The last item in an enum may have a trailing comma. C89 didn't allow this. + +Types ~ + +"long long" is allowed and can be expected to be 64 bits. Use %lld in printf +formats. Also "long long unsigned" with %llu. + +Flexible array members ~ + +This is an array without size, used as the last member of a struct. Vim used +to have an array of size one, which causes trouble with FORTIFY_SOURCE. Using +an "unsized array" is the intended use, we will change all of them. + struct some_stuff { + size_t length; + char payload[]; // will have size "length" + }; + +Not to be used ~ + +These C99 features are not to be used, because not enough compilers support +them: +- Declaration after Statements (MSVC 2012 does not support it). All + declarations need to be at the start of the block. +- Variable length arrays (even in C11 this is an optional feature). +- _Bool and _Complex types. +- "inline" (it's hardly ever needed, let the optimizer do its work) USE OF COMMON FUNCTIONS *style-functions* diff --git a/src/auto/configure b/src/auto/configure index 8ecff53a7d..6673de85a2 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -4179,6 +4179,40 @@ $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler can handle Vim code" >&5 +$as_echo_n "checking if the compiler can handle Vim code... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + struct with_flexible_member { + int count; // comment + char text[]; // another comment + }; + enum { + one, + two, + three, + }; + long long int a = 1; + long long unsigned b = 2; + printf("a %lld and a %llu", a, b); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + as_fn_error $? "compiler does not work properly - see auto/config.log" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-fail-if-missing argument" >&5 $as_echo_n "checking --enable-fail-if-missing argument... " >&6; } diff --git a/src/configure.ac b/src/configure.ac index e37a26790f..4ae21a110e 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -29,6 +29,29 @@ dnl in autoconf needs it, where it uses STDC_HEADERS. AC_HEADER_STDC AC_HEADER_SYS_WAIT +dnl Check that the C99 features that Vim uses are supported: +dnl - // commands +dnl - comma after last enum item +dnl - "long long int" and "long long unsigned" +dnl - flexible array member +AC_MSG_CHECKING(if the compiler can handle Vim code) +AC_TRY_COMPILE([#include ], [ + struct with_flexible_member { + int count; // comment + char text[]; // another comment + }; + enum { + one, + two, + three, + }; + long long int a = 1; + long long unsigned b = 2; + printf("a %lld and a %llu", a, b); + ], +AC_MSG_RESULT(yes), +AC_MSG_ERROR([compiler does not work properly - see auto/config.log])) + dnl Check for the flag that fails if stuff are missing. AC_MSG_CHECKING(--enable-fail-if-missing argument) diff --git a/src/version.c b/src/version.c index aa1e93fdd1..8d5c73a771 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1730, /**/ 1729, /**/ From e87edf3b85f607632e5431640071fdbc36b685b2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 17 Apr 2018 22:14:32 +0200 Subject: [PATCH 11/15] patch 8.0.1731: characters deleted on completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Characters deleted on completion. (Adrià Farrés) Solution: Also check the last item for the ORIGINAL_TEXT flag. (Christian Brabandt, closes #1645) --- src/edit.c | 14 +++++++++++++- src/testdir/test_popup.vim | 9 +++++++++ src/version.c | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/edit.c b/src/edit.c index 21941cb3d0..8746436fba 100644 --- a/src/edit.c +++ b/src/edit.c @@ -3656,7 +3656,9 @@ ins_compl_set_original_text(char_u *str) { char_u *p; - /* Replace the original text entry. */ + /* Replace the original text entry. + * The ORIGINAL_TEXT flag is either at the first item or might possibly be + * at the last item for backward completion */ if (compl_first_match->cp_flags & ORIGINAL_TEXT) /* safety check */ { p = vim_strsave(str); @@ -3666,6 +3668,16 @@ ins_compl_set_original_text(char_u *str) compl_first_match->cp_str = p; } } + else if (compl_first_match->cp_prev != NULL + && (compl_first_match->cp_prev->cp_flags & ORIGINAL_TEXT)) + { + p = vim_strsave(str); + if (p != NULL) + { + vim_free(compl_first_match->cp_prev->cp_str); + compl_first_match->cp_prev->cp_str = p; + } + } } /* diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index 8294febe6a..a2e86d7037 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -814,5 +814,14 @@ func Test_popup_command() call delete('Xtest') endfunc +func Test_popup_complete_backwards() + new + call setline(1, ['Post', 'Port', 'Po']) + let expected=['Post', 'Port', 'Port'] + call cursor(3,2) + call feedkeys("A\". repeat("\", 3). "rt\", 'tx') + call assert_equal(expected, getline(1,'$')) + bwipe! +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 8d5c73a771..c3add51446 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1731, /**/ 1730, /**/ From a997b45c7e350ea5b378ca0c52ed3d4cc610975c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 17 Apr 2018 23:24:06 +0200 Subject: [PATCH 12/15] patch 8.0.1732: crash when terminal API call deletes the buffer Problem: Crash when terminal API call deletes the buffer. Solution: Lock the buffer while calling a function. (closes #2813) --- src/buffer.c | 17 ++++++++++++++++- src/terminal.c | 8 ++++++++ src/testdir/test_autocmd.vim | 11 +++++++---- src/testdir/test_terminal.vim | 24 ++++++++++++++++++++++++ src/version.c | 2 ++ 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index 4563736b4d..c3d3d77b0f 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -417,6 +417,8 @@ buf_hashtab_remove(buf_T *buf) hash_remove(&buf_hashtab, hi); } +static char *e_buflocked = N_("E937: Attempt to delete a buffer that is in use"); + /* * Close the link to a buffer. * "action" is used when there is no longer a window for the buffer. @@ -476,8 +478,15 @@ close_buffer( if (term_job_running(buf->b_term)) { if (wipe_buf || unload_buf) + { + if (buf->b_locked) + { + EMSG(_(e_buflocked)); + return; + } /* Wiping out or unloading a terminal buffer kills the job. */ free_terminal(buf); + } else { /* The job keeps running, hide the buffer. */ @@ -499,7 +508,7 @@ close_buffer( * halfway a command that relies on it). Unloading is allowed. */ if (buf->b_locked > 0 && (del_buf || wipe_buf)) { - EMSG(_("E937: Attempt to delete a buffer that is in use")); + EMSG(_(e_buflocked)); return; } @@ -1356,6 +1365,12 @@ do_buffer( int forward; bufref_T bufref; + if (buf->b_locked) + { + EMSG(_(e_buflocked)); + return FAIL; + } + set_bufref(&bufref, buf); /* When unloading or deleting a buffer that's already unloaded and diff --git a/src/terminal.c b/src/terminal.c index 9a551a7844..7f6e48db64 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -46,6 +46,9 @@ * switch to GUI, shell stops working. Scrollback seems wrong, command * running in shell is still running. * - GUI: when using tabs, focus in terminal, click on tab does not work. + * - handle_moverect() scrolls one line at a time. Postpone scrolling, count + * the number of lines, until a redraw happens. Then if scrolling many lines + * a redraw is faster. * - Copy text in the vterm to the Vim buffer once in a while, so that * completion works. * - Redrawing is slow with Athena and Motif. Also other GUI? (Ramel Eshed) @@ -3433,6 +3436,10 @@ parse_osc(const char *command, size_t cmdlen, void *user) { char_u *cmd = get_tv_string(&item->li_tv); + /* Make sure an invoked command doesn't delete the buffer (and the + * terminal) under our fingers. */ + ++term->tl_buffer->b_locked; + item = item->li_next; if (item == NULL) ch_log(channel, "Missing argument for %s", cmd); @@ -3442,6 +3449,7 @@ parse_osc(const char *command, size_t cmdlen, void *user) handle_call_command(term, channel, item); else ch_log(channel, "Invalid command received: %s", cmd); + --term->tl_buffer->b_locked; } } else diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 61adcae33f..2d7956f45d 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -119,7 +119,9 @@ func Test_autocmd_bufunload_avoiding_SEGV_01() exe 'autocmd BufUnload ' . (lastbuf + 1) . 'bwipeout!' augroup END - call assert_fails('edit bb.txt', 'E937:') + " Todo: check for E937 generated first + " call assert_fails('edit bb.txt', 'E937:') + call assert_fails('edit bb.txt', 'E517:') autocmd! test_autocmd_bufunload augroup! test_autocmd_bufunload @@ -316,7 +318,7 @@ func Test_three_windows() e Xtestje2 sp Xtestje1 call assert_fails('e', 'E937:') - call assert_equal('Xtestje2', expand('%')) + call assert_equal('Xtestje1', expand('%')) " Test changing buffers in a BufWipeout autocommand. If this goes wrong " there are ml_line errors and/or a Crash. @@ -338,7 +340,6 @@ func Test_three_windows() au! enew - bwipe! Xtestje1 call delete('Xtestje1') call delete('Xtestje2') call delete('Xtestje3') @@ -1181,7 +1182,9 @@ endfunc func Test_nocatch_wipe_all_buffers() " Real nasty autocommand: wipe all buffers on any event. au * * bwipe * - call assert_fails('next x', 'E93') + " Get E93 first? + " call assert_fails('next x', 'E93:') + call assert_fails('next x', 'E517:') bwipe au! endfunc diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 5aa7597e37..5137659738 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1287,6 +1287,30 @@ func Test_terminal_api_call_fails() call delete('Xlog') endfunc +let s:caught_e937 = 0 + +func Tapi_Delete(bufnum, arg) + try + execute 'bdelete!' a:bufnum + catch /E937:/ + let s:caught_e937 = 1 + endtry +endfunc + +func Test_terminal_api_call_fail_delete() + if !CanRunVimInTerminal() + return + endif + + call WriteApiCall('Tapi_Delete') + let buf = RunVimInTerminal('-S Xscript', {}) + call WaitFor({-> s:caught_e937 == 1}) + + call StopVimInTerminal(buf) + call delete('Xscript') + call ch_logfile('', '') +endfunc + func Test_terminal_ansicolors_default() let colors = [ \ '#000000', '#e00000', diff --git a/src/version.c b/src/version.c index c3add51446..5647b6e4b2 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1732, /**/ 1731, /**/ From bad0ce7b26be5eed8524347018f4c835b212f8d1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 17 Apr 2018 23:31:05 +0200 Subject: [PATCH 13/15] patch 8.0.1733: incomplete testing for completion fix Problem: Incomplete testing for completion fix. (Lifepillar) Solution: Add a test with CTRL-P. --- src/testdir/test_popup.vim | 10 ++++++++++ src/version.c | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index a2e86d7037..ed31985856 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -824,4 +824,14 @@ func Test_popup_complete_backwards() bwipe! endfunc +func Test_popup_complete_backwards_ctrl_p() + new + call setline(1, ['Post', 'Port', 'Po']) + let expected=['Post', 'Port', 'Port'] + call cursor(3,2) + call feedkeys("A\\rt\", 'tx') + call assert_equal(expected, getline(1,'$')) + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 5647b6e4b2..2cdd9e313f 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1733, /**/ 1732, /**/ From f98a39ca57d001ba3e24831bae1e375790fb41f0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 18 Apr 2018 22:18:23 +0200 Subject: [PATCH 14/15] patch 8.0.1734: package directory not added to 'rtp' if prefix matches Problem: Package directory not added to 'rtp' if prefix matches. Solution: Check the match is a full match. (Ozaki Kiichi, closes #2817) Also handle different ways of spelling a path. --- src/ex_cmds2.c | 26 +++++++++++++++++++++++--- src/testdir/test_packadd.vim | 9 +++++++++ src/version.c | 2 ++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index 83f09661cc..3946627416 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -3821,10 +3821,30 @@ static int APP_BOTH; static void add_pack_plugin(char_u *fname, void *cookie) { - if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)fname) == NULL) - /* directory is not yet in 'runtimepath', add it */ - if (add_pack_dir_to_rtp(fname) == FAIL) + if (cookie != &APP_LOAD) + { + char_u *buf = alloc(MAXPATHL); + char_u *p; + int found = FALSE; + + if (buf == NULL) return; + p = p_rtp; + while (*p != NUL) + { + copy_option_part(&p, buf, MAXPATHL, ","); + if (pathcmp((char *)buf, (char *)fname, -1) == 0) + { + found = TRUE; + break; + } + } + vim_free(buf); + if (!found) + /* directory is not yet in 'runtimepath', add it */ + if (add_pack_dir_to_rtp(fname) == FAIL) + return; + } if (cookie != &APP_ADD_DIR) load_pack_plugin(fname); diff --git a/src/testdir/test_packadd.vim b/src/testdir/test_packadd.vim index 889d77f414..64bd8d2b23 100644 --- a/src/testdir/test_packadd.vim +++ b/src/testdir/test_packadd.vim @@ -40,6 +40,15 @@ func Test_packadd() call assert_match('/testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp) call assert_match('/testdir/Xdir/pack/mine/opt/mytest/after$', &rtp) + " NOTE: '/.../opt/myte' forwardly matches with '/.../opt/mytest' + call mkdir(fnamemodify(s:plugdir, ':h') . '/myte', 'p') + let rtp = &rtp + packadd myte + + " Check the path of 'myte' is added + call assert_true(len(&rtp) > len(rtp)) + call assert_match('/testdir/Xdir/pack/mine/opt/myte\($\|,\)', &rtp) + " Check exception call assert_fails("packadd directorynotfound", 'E919:') call assert_fails("packadd", 'E471:') diff --git a/src/version.c b/src/version.c index 2cdd9e313f..3abe29a65c 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1734, /**/ 1733, /**/ From 285e3358696b1bc6296e5d4c53425680ce8fbd54 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 18 Apr 2018 23:01:13 +0200 Subject: [PATCH 15/15] patch 8.0.1735: flexible array member feature not supported by HP-UX Problem: Flexible array member feature not supported by HP-UX. (John Marriott) Solution: Do not use the flexible array member feature of C99. --- runtime/doc/develop.txt | 11 +----- src/auto/configure | 10 ++--- src/configure.ac | 10 ++--- src/getchar.c | 88 ++++++++++++++++++----------------------- src/structs.h | 4 +- src/version.c | 2 + 6 files changed, 50 insertions(+), 75 deletions(-) diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index d90e4a3dd2..2e00ccfa94 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -209,16 +209,6 @@ Types ~ "long long" is allowed and can be expected to be 64 bits. Use %lld in printf formats. Also "long long unsigned" with %llu. -Flexible array members ~ - -This is an array without size, used as the last member of a struct. Vim used -to have an array of size one, which causes trouble with FORTIFY_SOURCE. Using -an "unsized array" is the intended use, we will change all of them. - struct some_stuff { - size_t length; - char payload[]; // will have size "length" - }; - Not to be used ~ These C99 features are not to be used, because not enough compilers support @@ -228,6 +218,7 @@ them: - Variable length arrays (even in C11 this is an optional feature). - _Bool and _Complex types. - "inline" (it's hardly ever needed, let the optimizer do its work) +- flexible array members: Not supported by HP-UX C compiler (John Marriott) USE OF COMMON FUNCTIONS *style-functions* diff --git a/src/auto/configure b/src/auto/configure index 6673de85a2..7a65bec0aa 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -4188,14 +4188,10 @@ int main () { - struct with_flexible_member { - int count; // comment - char text[]; // another comment - }; enum { - one, - two, - three, + one, // one comment + two, // two comments + three, // three comments }; long long int a = 1; long long unsigned b = 2; diff --git a/src/configure.ac b/src/configure.ac index 4ae21a110e..78023ad226 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -36,14 +36,10 @@ dnl - "long long int" and "long long unsigned" dnl - flexible array member AC_MSG_CHECKING(if the compiler can handle Vim code) AC_TRY_COMPILE([#include ], [ - struct with_flexible_member { - int count; // comment - char text[]; // another comment - }; enum { - one, - two, - three, + one, // one comment + two, // two comments + three, // three comments }; long long int a = 1; long long unsigned b = 2; diff --git a/src/getchar.c b/src/getchar.c index 5a5041a65f..285d5d5d06 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -40,9 +40,9 @@ #define MINIMAL_SIZE 20 /* minimal size for b_str */ -static buffheader_T redobuff = {NULL, NULL, 0, 0}; -static buffheader_T old_redobuff = {NULL, NULL, 0, 0}; -static buffheader_T recordbuff = {NULL, NULL, 0, 0}; +static buffheader_T redobuff = {{NULL, {NUL}}, NULL, 0, 0}; +static buffheader_T old_redobuff = {{NULL, {NUL}}, NULL, 0, 0}; +static buffheader_T recordbuff = {{NULL, {NUL}}, NULL, 0, 0}; static int typeahead_char = 0; /* typeahead char that's not flushed */ @@ -138,13 +138,12 @@ free_buff(buffheader_T *buf) { buffblock_T *p, *np; - for (p = buf->bh_first; p != NULL; p = np) + for (p = buf->bh_first.b_next; p != NULL; p = np) { np = p->b_next; vim_free(p); } - buf->bh_first = NULL; - buf->bh_curr = NULL; + buf->bh_first.b_next = NULL; } /* @@ -160,16 +159,16 @@ get_buffcont( char_u *p = NULL; char_u *p2; char_u *str; - buffblock_T *bp; + buffblock_T *bp; /* compute the total length of the string */ - for (bp = buffer->bh_first; bp != NULL; bp = bp->b_next) + for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) count += (long_u)STRLEN(bp->b_str); if ((count || dozero) && (p = lalloc(count + 1, TRUE)) != NULL) { p2 = p; - for (bp = buffer->bh_first; bp != NULL; bp = bp->b_next) + for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) for (str = bp->b_str; *str; ) *p2++ = *str++; *p2 = NUL; @@ -233,17 +232,17 @@ add_buff( long slen) /* length of "s" or -1 */ { buffblock_T *p; - long_u len; + long_u len; if (slen < 0) slen = (long)STRLEN(s); if (slen == 0) /* don't add empty strings */ return; - if (buf->bh_first == NULL) /* first add to list */ + if (buf->bh_first.b_next == NULL) /* first add to list */ { buf->bh_space = 0; - buf->bh_curr = NULL; + buf->bh_curr = &(buf->bh_first); } else if (buf->bh_curr == NULL) /* buffer has already been read */ { @@ -251,9 +250,9 @@ add_buff( return; } else if (buf->bh_index != 0) - mch_memmove(buf->bh_first->b_str, - buf->bh_first->b_str + buf->bh_index, - STRLEN(buf->bh_first->b_str + buf->bh_index) + 1); + mch_memmove(buf->bh_first.b_next->b_str, + buf->bh_first.b_next->b_str + buf->bh_index, + STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1); buf->bh_index = 0; if (buf->bh_space >= (int)slen) @@ -268,25 +267,16 @@ add_buff( len = MINIMAL_SIZE; else len = slen; - p = (buffblock_T *)lalloc((long_u)(sizeof(buffblock_T) + len + 1), - TRUE); + p = (buffblock_T *)lalloc((long_u)(sizeof(buffblock_T) + len), + TRUE); if (p == NULL) return; /* no space, just forget it */ buf->bh_space = (int)(len - slen); vim_strncpy(p->b_str, s, (size_t)slen); - if (buf->bh_curr == NULL) - { - p->b_next = NULL; - buf->bh_first = p; - buf->bh_curr = p; - } - else - { - p->b_next = buf->bh_curr->b_next; - buf->bh_curr->b_next = p; - buf->bh_curr = p; - } + p->b_next = buf->bh_curr->b_next; + buf->bh_curr->b_next = p; + buf->bh_curr = p; } return; } @@ -358,10 +348,10 @@ add_char_buff(buffheader_T *buf, int c) } /* First read ahead buffer. Used for translated commands. */ -static buffheader_T readbuf1 = {NULL, NULL, 0, 0}; +static buffheader_T readbuf1 = {{NULL, {NUL}}, NULL, 0, 0}; /* Second read ahead buffer. Used for redo. */ -static buffheader_T readbuf2 = {NULL, NULL, 0, 0}; +static buffheader_T readbuf2 = {{NULL, {NUL}}, NULL, 0, 0}; /* * Get one byte from the read buffers. Use readbuf1 one first, use readbuf2 @@ -386,17 +376,17 @@ read_readbuf(buffheader_T *buf, int advance) char_u c; buffblock_T *curr; - if (buf->bh_first == NULL) /* buffer is empty */ + if (buf->bh_first.b_next == NULL) /* buffer is empty */ return NUL; - curr = buf->bh_first; + curr = buf->bh_first.b_next; c = curr->b_str[buf->bh_index]; if (advance) { if (curr->b_str[++buf->bh_index] == NUL) { - buf->bh_first = curr->b_next; + buf->bh_first.b_next = curr->b_next; vim_free(curr); buf->bh_index = 0; } @@ -410,14 +400,14 @@ read_readbuf(buffheader_T *buf, int advance) static void start_stuff(void) { - if (readbuf1.bh_first != NULL) + if (readbuf1.bh_first.b_next != NULL) { - readbuf1.bh_curr = readbuf1.bh_first; + readbuf1.bh_curr = &(readbuf1.bh_first); readbuf1.bh_space = 0; } - if (readbuf2.bh_first != NULL) + if (readbuf2.bh_first.b_next != NULL) { - readbuf2.bh_curr = readbuf2.bh_first; + readbuf2.bh_curr = &(readbuf2.bh_first); readbuf2.bh_space = 0; } } @@ -428,8 +418,8 @@ start_stuff(void) int stuff_empty(void) { - return (readbuf1.bh_first == NULL - && readbuf2.bh_first == NULL); + return (readbuf1.bh_first.b_next == NULL + && readbuf2.bh_first.b_next == NULL); } /* @@ -439,7 +429,7 @@ stuff_empty(void) int readbuf1_empty(void) { - return (readbuf1.bh_first == NULL); + return (readbuf1.bh_first.b_next == NULL); } /* @@ -504,7 +494,7 @@ ResetRedobuff(void) { free_buff(&old_redobuff); old_redobuff = redobuff; - redobuff.bh_first = NULL; + redobuff.bh_first.b_next = NULL; } } @@ -519,7 +509,7 @@ CancelRedo(void) { free_buff(&redobuff); redobuff = old_redobuff; - old_redobuff.bh_first = NULL; + old_redobuff.bh_first.b_next = NULL; start_stuff(); while (read_readbuffers(TRUE) != NUL) ; @@ -536,9 +526,9 @@ saveRedobuff(save_redo_T *save_redo) char_u *s; save_redo->sr_redobuff = redobuff; - redobuff.bh_first = NULL; + redobuff.bh_first.b_next = NULL; save_redo->sr_old_redobuff = old_redobuff; - old_redobuff.bh_first = NULL; + old_redobuff.bh_first.b_next = NULL; /* Make a copy, so that ":normal ." in a function works. */ s = get_buffcont(&save_redo->sr_redobuff, FALSE); @@ -757,9 +747,9 @@ read_redo(int init, int old_redo) if (init) { if (old_redo) - bp = old_redobuff.bh_first; + bp = old_redobuff.bh_first.b_next; else - bp = redobuff.bh_first; + bp = redobuff.bh_first.b_next; if (bp == NULL) return FAIL; p = bp->b_str; @@ -1382,9 +1372,9 @@ save_typeahead(tasave_T *tp) old_char = -1; tp->save_readbuf1 = readbuf1; - readbuf1.bh_first = NULL; + readbuf1.bh_first.b_next = NULL; tp->save_readbuf2 = readbuf2; - readbuf2.bh_first = NULL; + readbuf2.bh_first.b_next = NULL; # ifdef USE_INPUT_BUF tp->save_inputbuf = get_input_buf(); # endif diff --git a/src/structs.h b/src/structs.h index e3ad867dbf..35433b1b24 100644 --- a/src/structs.h +++ b/src/structs.h @@ -511,7 +511,7 @@ typedef struct buffheader buffheader_T; struct buffblock { buffblock_T *b_next; /* pointer to next buffblock */ - char_u b_str[]; /* contents (flexible array) */ + char_u b_str[1]; /* contents (actually longer) */ }; /* @@ -519,7 +519,7 @@ struct buffblock */ struct buffheader { - buffblock_T *bh_first; /* first block of the list */ + buffblock_T bh_first; /* first (dummy) block of list */ buffblock_T *bh_curr; /* buffblock for appending */ int bh_index; /* index for reading */ int bh_space; /* space in bh_curr for appending */ diff --git a/src/version.c b/src/version.c index 3abe29a65c..c2fc3f3bc7 100644 --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1735, /**/ 1734, /**/