From 0f9c90e0edd27d2db04d48e7bd98bb46d2c4a918 Mon Sep 17 00:00:00 2001 From: Matt Widmann Date: Sat, 25 Nov 2017 13:59:07 -0800 Subject: io: retry fgets on EINTR (#7632) The calls to `fgets` in `src/nvim/if_cscope.c` (and elsewhere) can show communication errors to the user if a signal is delivered during its system calls. For plugins that proxy subprocess output into cscope requests, a `SIGCHLD` might *always* interfere with calls into `fgets`. To see this in a debugger, put a breakpoint on `cs_reading_emsg` and watch signals come in (with lldb, using `process handle --notify true --pass true`). Next, run a subcommand from neovim that calls through cscope when it returns. A tag picker plugin, like vim-picker and fzy, with `cscopetag` and `cscopetagorder=0` set, reproduced this reliably. The breakpoint will hit after a `SIGCHLD` is delivered, and `errno` will be set to 4, `EINTR`. The caller of `fgets` should retry when `NULL` is returned with `errno` set to `EINTR`. --- src/nvim/ex_cmds2.c | 6 ++++++ src/nvim/fileio.c | 5 +++++ src/nvim/if_cscope.c | 17 +++++++++++++++-- src/nvim/quickfix.c | 20 +++++++++++++++++--- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 9b8e463aee..ec4ce63e17 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3199,8 +3199,14 @@ static char_u *get_one_sourceline(struct source_cookie *sp) ga_grow(&ga, 120); buf = (char_u *)ga.ga_data; +retry: + errno = 0; if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len, sp->fp) == NULL) { + if (errno == EINTR) { + goto retry; + } + break; } len = ga.ga_len + (int)STRLEN(buf + ga.ga_len); diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index ae6c3f96e3..9214e1e644 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -4448,7 +4448,12 @@ bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL char tbuf[FGETS_SIZE]; buf[size - 2] = NUL; +retry: + errno = 0; eof = fgets((char *)buf, size, fp); + if (eof == NULL && errno == EINTR) { + goto retry; + } if (buf[size - 2] != NUL && buf[size - 2] != '\n') { buf[size - 1] = NUL; /* Truncate the line */ diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 0f9ecdf2d7..21e4b84074 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -553,9 +553,15 @@ static int cs_cnt_matches(size_t idx) char *buf = xmalloc(CSREAD_BUFSIZE); for (;; ) { + errno = 0; if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp)) { - if (feof(csinfo[idx].fr_fp)) + if (errno == EINTR) { + continue; + } + + if (feof(csinfo[idx].fr_fp)) { errno = EIO; + } cs_reading_emsg(idx); @@ -1381,9 +1387,16 @@ static char *cs_parse_results(size_t cnumber, char *buf, int bufsize, char *p; char *name; +retry: + errno = 0; if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL) { - if (feof(csinfo[cnumber].fr_fp)) + if (errno == EINTR) { + goto retry; + } + + if (feof(csinfo[cnumber].fr_fp)) { errno = EIO; + } cs_reading_emsg(cnumber); diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index b9228e15b9..1fc585f0c9 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -570,7 +570,12 @@ static int qf_get_next_file_line(qfstate_T *state) { size_t growbuflen; +retry: + errno = 0; if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) { + if (errno == EINTR) { + goto retry; + } return QF_END_OF_INPUT; } @@ -590,8 +595,12 @@ static int qf_get_next_file_line(qfstate_T *state) growbuflen = state->linelen; for (;;) { + errno = 0; if (fgets((char *)state->growbuf + growbuflen, (int)(state->growbufsiz - growbuflen), state->fd) == NULL) { + if (errno == EINTR) { + continue; + } break; } state->linelen = STRLEN(state->growbuf + growbuflen); @@ -612,9 +621,14 @@ static int qf_get_next_file_line(qfstate_T *state) while (discard) { // The current line is longer than LINE_MAXLEN, continue reading but // discard everything until EOL or EOF is reached. - if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL - || STRLEN(IObuff) < IOSIZE - 1 - || IObuff[IOSIZE - 1] == '\n') { + errno = 0; + if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) { + if (errno == EINTR) { + continue; + } + break; + } + if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 1] == '\n') { break; } } -- cgit From bab2f8200aea09ad32bbcb2e83404bbd4076a227 Mon Sep 17 00:00:00 2001 From: Matt Widmann Date: Sat, 25 Nov 2017 13:27:59 -0800 Subject: io: fix handling EOF in vim_fgets If an EOF is returned from `fgets`, `vim_fgets` might spin forever, as it tries to consume the current line. A `NULL` return value from `fgets` should break out of the function (unless `errno` is `EINTR`), and then `feof` should be used to check for the EOF condition on the stream. --- src/nvim/fileio.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 9214e1e644..1f4cd22754 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -4443,27 +4443,32 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) /// @return true for end-of-file. bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL { - char *eof; -#define FGETS_SIZE 200 - char tbuf[FGETS_SIZE]; + char *retval; + assert(size > 0); buf[size - 2] = NUL; -retry: - errno = 0; - eof = fgets((char *)buf, size, fp); - if (eof == NULL && errno == EINTR) { - goto retry; - } + + do { + errno = 0; + retval = fgets((char *)buf, size, fp); + } while (retval == NULL && errno == EINTR); + if (buf[size - 2] != NUL && buf[size - 2] != '\n') { - buf[size - 1] = NUL; /* Truncate the line */ + char tbuf[200]; + + buf[size - 1] = NUL; // Truncate the line. - /* Now throw away the rest of the line: */ + // Now throw away the rest of the line: do { - tbuf[FGETS_SIZE - 2] = NUL; - ignoredp = fgets((char *)tbuf, FGETS_SIZE, fp); - } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n'); + tbuf[sizeof(tbuf) - 2] = NUL; + errno = 0; + retval = fgets((char *)tbuf, sizeof(tbuf), fp); + if (retval == NULL && errno != EINTR) { + break; + } + } while (tbuf[sizeof(tbuf) - 2] != NUL && tbuf[sizeof(tbuf) - 2] != '\n'); } - return eof == NULL; + return retval ? false : feof(fp); } /// Read 2 bytes from "fd" and turn them into an int, MSB first. -- cgit From 944e3c06193f6d10baa9ba3021e01626337dd884 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Nov 2017 23:15:17 +0100 Subject: tui: expose terminal type in 'term' option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since "builtin" terminfo definitions were implemented (7cbf52db1bdf), the decisions made by tui.c and terminfo.c are more relevant. Exposing that decision in the 'term' option helps with troubleshooting. Also: remove code that allowed setting t_Co. `:set t_Co=…` has never worked; the highlight_spec test asserting that nvim_set_option('t_Co') _does_ work makes no sense, and should not have worked. --- runtime/doc/vim_diff.txt | 8 ++-- src/nvim/option.c | 73 ++++++++++++++++++++--------------- src/nvim/tui/terminfo.c | 28 ++++++++++++-- src/nvim/tui/tui.c | 22 +++++++++-- test/functional/helpers.lua | 10 +++++ test/functional/terminal/tui_spec.lua | 49 +++++++++++++++++++++-- test/functional/ui/highlight_spec.lua | 2 - 7 files changed, 147 insertions(+), 45 deletions(-) diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 026ff6a0fb..c8155f7a68 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -333,9 +333,11 @@ terminal capabilities. Instead Nvim treats the terminal as any other UI. For example, 'guicursor' sets the terminal cursor style if possible. *'term'* *E529* *E530* *E531* -The 'term' option has a fixed value, present only for script compatibility and -intentionally not the same as any known terminal type name. It should be a -rare case in Nvim where one needs |term-dependent-settings|. +'term' reflects the terminal type derived from |$TERM| and other environment +checks. For debugging only; not reliable during startup. > + :echo &term +"builtin_x" means one of the |builtin-terms| was chosen, because the expected +terminfo file was not found on the system. *termcap* Nvim never uses the termcap database, only |terminfo| and |builtin-terms|. diff --git a/src/nvim/option.c b/src/nvim/option.c index 65ab7a54a6..07114c9507 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -105,6 +105,9 @@ typedef enum { */ #define VAR_WIN ((char_u *)-1) +static char *p_term = NULL; +static char *p_ttytype = NULL; + /* * These are the global values for options which are also local to a buffer. * Only to be used in option.c! @@ -4530,13 +4533,17 @@ int findoption_len(const char *const arg, const size_t len) bool is_tty_option(const char *name) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return (name[0] == 't' && name[1] == '_') || strcmp(name, "term") == 0; + return (name[0] == 't' && name[1] == '_') + || strequal(name, "term") + || strequal(name, "ttytype"); } #define TCO_BUFFER_SIZE 8 +/// @param name TUI-related option +/// @param[out,allocated] value option string value bool get_tty_option(char *name, char **value) { - if (!strcmp(name, "t_Co")) { + if (strequal(name, "t_Co")) { if (value) { if (t_colors <= 1) { *value = xstrdup(""); @@ -4548,9 +4555,16 @@ bool get_tty_option(char *name, char **value) return true; } - if (!strcmp(name, "term") || !strcmp(name, "ttytype")) { + if (strequal(name, "term")) { if (value) { - *value = xstrdup("nvim"); + *value = p_term ? xstrdup(p_term) : xstrdup("nvim"); + } + return true; + } + + if (strequal(name, "ttytype")) { + if (value) { + *value = p_ttytype ? xstrdup(p_ttytype) : xstrdup("nvim"); } return true; } @@ -4566,25 +4580,25 @@ bool get_tty_option(char *name, char **value) return false; } -bool set_tty_option(const char *name, const char *value) +bool set_tty_option(const char *name, char *value) { - if (!strcmp(name, "t_Co")) { - int colors = atoi(value); - - // Only reinitialize colors if t_Co value has really changed to - // avoid expensive reload of colorscheme if t_Co is set to the - // same value multiple times - if (colors != t_colors) { - t_colors = colors; - // We now have a different color setup, initialize it again. - init_highlight(true, false); + if (strequal(name, "term")) { + if (p_term) { + xfree(p_term); } + p_term = value; + return true; + } + if (strequal(name, "ttytype")) { + if (p_ttytype) { + xfree(p_ttytype); + } + p_ttytype = value; return true; } - return (is_tty_option(name) || !strcmp(name, "term") - || !strcmp(name, "ttytype")); + return false; } /// Find index for an option @@ -4597,18 +4611,15 @@ static int findoption(const char *const arg) return findoption_len(arg, strlen(arg)); } -/* - * Get the value for an option. - * - * Returns: - * Number or Toggle option: 1, *numval gets value. - * String option: 0, *stringval gets allocated string. - * Hidden Number or Toggle option: -1. - * hidden String option: -2. - * unknown option: -3. - */ -int -get_option_value ( +/// Gets the value for an option. +/// +/// @returns: +/// Number or Toggle option: 1, *numval gets value. +/// String option: 0, *stringval gets allocated string. +/// Hidden Number or Toggle option: -1. +/// hidden String option: -2. +/// unknown option: -3. +int get_option_value ( char_u *name, long *numval, char_u **stringval, /* NULL when only checking existence */ @@ -4791,8 +4802,8 @@ char *set_option_value(const char *const name, const long number, const char *const string, const int opt_flags) FUNC_ATTR_NONNULL_ARG(1) { - if (set_tty_option(name, string)) { - return NULL; + if (is_tty_option(name)) { + return NULL; // Fail silently; many old vimrcs set t_xx options. } int opt_idx; diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index 75e9a2d8da..fdc33f0a77 100644 --- a/src/nvim/tui/terminfo.c +++ b/src/nvim/tui/terminfo.c @@ -9,6 +9,7 @@ #include #include "nvim/log.h" +#include "nvim/memory.h" #include "nvim/tui/terminfo.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -94,51 +95,72 @@ bool terminfo_is_term_family(const char *term, const char *family) /// Loads a built-in terminfo db when we (unibilium) failed to load a terminfo /// record from the environment (termcap systems, unrecognized $TERM, …). /// We do not attempt to detect xterm pretenders here. -static unibi_term *terminfo_builtin(const char *term) +/// +/// @param term $TERM value +/// @param[out,allocated] termname decided builtin 'term' name +/// @return [allocated] terminfo structure +static unibi_term *terminfo_builtin(const char *term, char **termname) { if (terminfo_is_term_family(term, "xterm")) { + *termname = xstrdup("builtin_xterm"); return unibi_from_mem((const char *)xterm_256colour_terminfo, sizeof xterm_256colour_terminfo); } else if (terminfo_is_term_family(term, "screen")) { + *termname = xstrdup("builtin_screen"); return unibi_from_mem((const char *)screen_256colour_terminfo, sizeof screen_256colour_terminfo); } else if (terminfo_is_term_family(term, "tmux")) { + *termname = xstrdup("builtin_tmux"); return unibi_from_mem((const char *)tmux_256colour_terminfo, sizeof tmux_256colour_terminfo); } else if (terminfo_is_term_family(term, "rxvt")) { + *termname = xstrdup("builtin_rxvt"); return unibi_from_mem((const char *)rxvt_256colour_terminfo, sizeof rxvt_256colour_terminfo); } else if (terminfo_is_term_family(term, "putty")) { + *termname = xstrdup("builtin_putty"); return unibi_from_mem((const char *)putty_256colour_terminfo, sizeof putty_256colour_terminfo); } else if (terminfo_is_term_family(term, "linux")) { + *termname = xstrdup("builtin_linux"); return unibi_from_mem((const char *)linux_16colour_terminfo, sizeof linux_16colour_terminfo); } else if (terminfo_is_term_family(term, "interix")) { + *termname = xstrdup("builtin_interix"); return unibi_from_mem((const char *)interix_8colour_terminfo, sizeof interix_8colour_terminfo); } else if (terminfo_is_term_family(term, "iterm") || terminfo_is_term_family(term, "iterm2") || terminfo_is_term_family(term, "iTerm.app") || terminfo_is_term_family(term, "iTerm2.app")) { + *termname = xstrdup("builtin_iterm"); return unibi_from_mem((const char *)iterm_256colour_terminfo, sizeof iterm_256colour_terminfo); } else if (terminfo_is_term_family(term, "st")) { + *termname = xstrdup("builtin_st"); return unibi_from_mem((const char *)st_256colour_terminfo, sizeof st_256colour_terminfo); } else if (terminfo_is_term_family(term, "gnome") || terminfo_is_term_family(term, "vte")) { + *termname = xstrdup("builtin_vte"); return unibi_from_mem((const char *)vte_256colour_terminfo, sizeof vte_256colour_terminfo); } else { + *termname = xstrdup("builtin_ansi"); return unibi_from_mem((const char *)ansi_terminfo, sizeof ansi_terminfo); } } -unibi_term *terminfo_from_builtin(const char *term) +/// @param term $TERM value +/// @param[out,allocated] termname decided builtin 'term' name +/// @return [allocated] terminfo structure +unibi_term *terminfo_from_builtin(const char *term, char **termname) { - unibi_term *ut = terminfo_builtin(term); + unibi_term *ut = terminfo_builtin(term, termname); + if (*termname == NULL) { + *termname = xstrdup("builtin_?"); + } // Disable BCE by default (for built-in terminfos). #7624 // https://github.com/kovidgoyal/kitty/issues/160#issuecomment-346470545 unibi_set_bool(ut, unibi_back_color_erase, false); diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index c2e597c36c..732a86d0fb 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -23,6 +23,7 @@ #include "nvim/map.h" #include "nvim/main.h" #include "nvim/memory.h" +#include "nvim/option.h" #include "nvim/api/vim.h" #include "nvim/api/private/helpers.h" #include "nvim/event/loop.h" @@ -166,6 +167,13 @@ static size_t unibi_pre_fmt_str(TUIData *data, unsigned int unibi_index, return unibi_run(str, data->params, buf, len); } +static void termname_set_event(void **argv) +{ + char *termname = argv[0]; + set_tty_option("term", termname); + // Do not free termname, it is freed by set_tty_option. +} + static void terminfo_start(UI *ui) { TUIData *data = ui->data; @@ -190,12 +198,20 @@ static void terminfo_start(UI *ui) data->unibi_ext.reset_cursor_style = -1; data->out_fd = 1; data->out_isatty = os_isatty(data->out_fd); - // setup unibilium + + // Set up unibilium/terminfo. const char *term = os_getenv("TERM"); data->ut = unibi_from_env(); + char *termname = NULL; if (!data->ut) { - data->ut = terminfo_from_builtin(term); + data->ut = terminfo_from_builtin(term, &termname); + } else { + termname = xstrdup(term); } + // Update 'term' option. + loop_schedule_deferred(&main_loop, + event_create(termname_set_event, 1, termname)); + // None of the following work over SSH; see :help TERM . const char *colorterm = os_getenv("COLORTERM"); const char *termprg = os_getenv("TERM_PROGRAM"); @@ -344,7 +360,7 @@ static void tui_scheduler(Event event, void *d) { UI *ui = d; TUIData *data = ui->data; - loop_schedule(data->loop, event); + loop_schedule(data->loop, event); // `tui_loop` local to tui_main(). } #ifdef UNIX diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 272d2045c9..da334d4ac6 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -603,6 +603,15 @@ local function get_pathsep() return funcs.fnamemodify('.', ':p'):sub(-1) end +-- Returns a valid, platform-independent $NVIM_LISTEN_ADDRESS. +-- Useful for communicating with child instances. +local function new_pipename() + -- HACK: Start a server temporarily, get the name, then stop it. + local pipename = nvim_eval('serverstart()') + funcs.serverstop(pipename) + return pipename +end + local function missing_provider(provider) if provider == 'ruby' then local prog = funcs['provider#' .. provider .. '#Detect']() @@ -732,6 +741,7 @@ local module = { missing_provider = missing_provider, alter_slashes = alter_slashes, hexdump = hexdump, + new_pipename = new_pipename, } return function(after_each) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 777ef65d9e..723325c040 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1,12 +1,16 @@ -- TUI acceptance tests. -- Uses :terminal as a way to send keys and assert screen state. local global_helpers = require('test.helpers') +local uname = global_helpers.uname local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local feed_data = thelpers.feed_data local feed_command = helpers.feed_command +local clear = helpers.clear local nvim_dir = helpers.nvim_dir local retry = helpers.retry +local nvim_prog = helpers.nvim_prog +local nvim_set = helpers.nvim_set if helpers.pending_win32(pending) then return end @@ -14,7 +18,7 @@ describe('tui', function() local screen before_each(function() - helpers.clear() + clear() screen = thelpers.screen_setup(0, '["'..helpers.nvim_prog ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]') -- right now pasting can be really slow in the TUI, especially in ASAN. @@ -372,7 +376,7 @@ end) -- does not initialize the TUI. describe("tui 't_Co' (terminal colors)", function() local screen - local is_freebsd = (string.lower(global_helpers.uname()) == 'freebsd') + local is_freebsd = (string.lower(uname()) == 'freebsd') local function assert_term_colors(term, colorterm, maxcolors) helpers.clear({env={TERM=term}, args={}}) @@ -384,7 +388,7 @@ describe("tui 't_Co' (terminal colors)", function() (colorterm ~= nil and "COLORTERM="..colorterm or ""), helpers.nvim_prog)) - thelpers.feed_data(":echo &t_Co\n") + feed_data(":echo &t_Co\n") helpers.wait() local tline if maxcolors == 8 or maxcolors == 16 then @@ -628,3 +632,42 @@ describe("tui 't_Co' (terminal colors)", function() end) end) + +-- These tests require `thelpers` because --headless/--embed +-- does not initialize the TUI. +describe("tui 'term' option", function() + local screen + local is_bsd = not not string.find(string.lower(uname()), 'bsd') + + local function assert_term(term_envvar, term_expected) + clear() + -- This is ugly because :term/termopen() forces TERM=xterm-256color. + -- TODO: Revisit this after jobstart/termopen accept `env` dict. + local cmd = string.format( + [=[['sh', '-c', 'LANG=C TERM=%s %s -u NONE -i NONE --cmd "%s"']]=], + term_envvar or "", + nvim_prog, + nvim_set) + screen = thelpers.screen_setup(0, cmd) + + local full_timeout = screen.timeout + screen.timeout = 250 -- We want screen:expect() to fail quickly. + retry(nil, 2 * full_timeout, function() -- Wait for TUI thread to set 'term'. + feed_data(":echo 'term='.(&term)\n") + screen:expect('term='..term_expected, nil, nil, nil, true) + end) + end + + it('gets builtin term if $TERM is invalid', function() + assert_term("foo", "builtin_ansi") + end) + + it('gets system-provided term if $TERM is valid', function() + if is_bsd then -- BSD lacks terminfo, we always use builtin there. + assert_term("xterm", "builtin_xterm") + else + assert_term("xterm", "xterm") + end + end) + +end) diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index d1357ea525..12d71a1603 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -14,8 +14,6 @@ describe('colorscheme compatibility', function() it('t_Co is set to 256 by default', function() eq('256', eval('&t_Co')) - request('nvim_set_option', 't_Co', '88') - eq('88', eval('&t_Co')) end) end) -- cgit From c8b40930c03844908c37c8aeade0a0f1156a0a0c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 27 Nov 2017 00:27:40 +0100 Subject: test: tui_spec.lua: use robust settings --- test/functional/terminal/tui_spec.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 723325c040..d5f6a21d1d 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -19,8 +19,8 @@ describe('tui', function() before_each(function() clear() - screen = thelpers.screen_setup(0, '["'..helpers.nvim_prog - ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]') + screen = thelpers.screen_setup(0, '["'..nvim_prog + ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler undodir=. directory=. viewdir=. backupdir=."]') -- right now pasting can be really slow in the TUI, especially in ASAN. -- this will be fixed later but for now we require a high timeout. screen.timeout = 60000 @@ -383,10 +383,11 @@ describe("tui 't_Co' (terminal colors)", function() -- This is ugly because :term/termopen() forces TERM=xterm-256color. -- TODO: Revisit this after jobstart/termopen accept `env` dict. screen = thelpers.screen_setup(0, string.format( - [=[['sh', '-c', 'LANG=C TERM=%s %s %s -u NONE -i NONE --cmd "silent set noswapfile noshowcmd noruler"']]=], + [=[['sh', '-c', 'LANG=C TERM=%s %s %s -u NONE -i NONE --cmd "%s"']]=], term or "", (colorterm ~= nil and "COLORTERM="..colorterm or ""), - helpers.nvim_prog)) + nvim_prog, + nvim_set)) feed_data(":echo &t_Co\n") helpers.wait() @@ -401,10 +402,10 @@ describe("tui 't_Co' (terminal colors)", function() %s| %s| %s| - {5:[No Name] }| + %s| %-3s | {3:-- TERMINAL --} | - ]], tline, tline, tline, tostring(maxcolors and maxcolors or ""))) + ]], tline, tline, tline, tline, tostring(maxcolors and maxcolors or ""))) end -- ansi and no terminal type at all: -- cgit From 6cf186edb5dec13bc7f4cd57be726d124af578de Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 27 Nov 2017 09:33:12 +0100 Subject: lint --- src/nvim/option.c | 25 ++++++++++++------------- test/functional/ui/highlight_spec.lua | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 07114c9507..913d27d508 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4619,10 +4619,10 @@ static int findoption(const char *const arg) /// Hidden Number or Toggle option: -1. /// hidden String option: -2. /// unknown option: -3. -int get_option_value ( +int get_option_value( char_u *name, long *numval, - char_u **stringval, /* NULL when only checking existence */ + char_u **stringval, ///< NULL when only checking existence int opt_flags ) { @@ -4630,32 +4630,31 @@ int get_option_value ( return 0; } - int opt_idx; - char_u *varp; - - opt_idx = findoption((const char *)name); + int opt_idx = findoption((const char *)name); if (opt_idx < 0) { // Unknown option. return -3; } - varp = get_varp_scope(&(options[opt_idx]), opt_flags); + char_u *varp = get_varp_scope(&(options[opt_idx]), opt_flags); if (options[opt_idx].flags & P_STRING) { - if (varp == NULL) /* hidden option */ + if (varp == NULL) { // hidden option return -2; + } if (stringval != NULL) { *stringval = vim_strsave(*(char_u **)(varp)); } return 0; } - if (varp == NULL) /* hidden option */ + if (varp == NULL) { // hidden option return -1; - if (options[opt_idx].flags & P_NUM) + } + if (options[opt_idx].flags & P_NUM) { *numval = *(long *)varp; - else { - /* Special case: 'modified' is b_changed, but we also want to consider - * it set when 'ff' or 'fenc' changed. */ + } else { + // Special case: 'modified' is b_changed, but we also want to consider + // it set when 'ff' or 'fenc' changed. if ((int *)varp == &curbuf->b_changed) { *numval = curbufIsChanged(); } else { diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 12d71a1603..2252e3580f 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -4,7 +4,7 @@ local os = require('os') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local command = helpers.command local eval, exc_exec = helpers.eval, helpers.exc_exec -local feed_command, request, eq = helpers.feed_command, helpers.request, helpers.eq +local feed_command, eq = helpers.feed_command, helpers.eq local curbufmeths = helpers.curbufmeths describe('colorscheme compatibility', function() -- cgit From df019cebd59a456d6f7dc5948703fdd2059c4b04 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 27 Nov 2017 11:06:43 +0100 Subject: Revert "provider: delete vimL stderr collector, now that it exists builtin" This change exposed a memory issue with buffered channels, possibly involving GC. Revert until it has been fixed. This reverts commit 0de019b6a65c6dd5141b7e002343df3689065ce7. --- runtime/autoload/provider.vim | 20 ++++++++++++++++++++ runtime/autoload/provider/clipboard.vim | 6 ++++-- runtime/autoload/provider/node.vim | 9 +++++---- runtime/autoload/provider/pythonx.vim | 9 +++++---- 4 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 runtime/autoload/provider.vim diff --git a/runtime/autoload/provider.vim b/runtime/autoload/provider.vim new file mode 100644 index 0000000000..e6514f5ba8 --- /dev/null +++ b/runtime/autoload/provider.vim @@ -0,0 +1,20 @@ +" Common functionality for providers + +let s:stderr = {} + +function! provider#stderr_collector(chan_id, data, event) + let stderr = get(s:stderr, a:chan_id, ['']) + let stderr[-1] .= a:data[0] + call extend(stderr, a:data[1:]) + let s:stderr[a:chan_id] = stderr +endfunction + +function! provider#clear_stderr(chan_id) + if has_key(s:stderr, a:chan_id) + call remove(s:stderr, a:chan_id) + endif +endfunction + +function! provider#get_stderr(chan_id) + return get(s:stderr, a:chan_id, []) +endfunction diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 381fe2cf2d..6454a01c2a 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -7,7 +7,7 @@ let s:clipboard = {} " When caching is enabled, store the jobid of the xclip/xsel process keeping " ownership of the selection, so we know how long the cache is valid. -let s:selection = { 'owner': 0, 'data': [], 'stderr_buffered': v:true } +let s:selection = { 'owner': 0, 'data': [], 'on_stderr': function('provider#stderr_collector') } function! s:selection.on_exit(jobid, data, event) abort " At this point this nvim instance might already have launched @@ -16,10 +16,12 @@ function! s:selection.on_exit(jobid, data, event) abort let self.owner = 0 endif if a:data != 0 + let stderr = provider#get_stderr(a:jobid) echohl WarningMsg - echomsg 'clipboard: error invoking '.get(self.argv, 0, '?').': '.join(self.stderr) + echomsg 'clipboard: error invoking '.get(self.argv, 0, '?').': '.join(stderr) echohl None endif + call provider#clear_stderr(a:jobid) endfunction let s:selections = { '*': s:selection, '+': copy(s:selection) } diff --git a/runtime/autoload/provider/node.vim b/runtime/autoload/provider/node.vim index 419dd517cd..b08ad4f316 100644 --- a/runtime/autoload/provider/node.vim +++ b/runtime/autoload/provider/node.vim @@ -3,7 +3,7 @@ if exists('g:loaded_node_provider') endif let g:loaded_node_provider = 1 -let s:job_opts = {'rpc': v:true, 'stderr_buffered': v:true} +let s:job_opts = {'rpc': v:true, 'on_stderr': function('provider#stderr_collector')} function! provider#node#Detect() abort return has('win32') ? exepath('neovim-node-host.cmd') : exepath('neovim-node-host') @@ -32,18 +32,19 @@ function! provider#node#Require(host) abort endif try - let job = copy(s:job_opts) - let channel_id = jobstart(args, job) + let channel_id = jobstart(args, s:job_opts) if rpcrequest(channel_id, 'poll') ==# 'ok' return channel_id endif catch echomsg v:throwpoint echomsg v:exception - for row in job.stderr + for row in provider#get_stderr(channel_id) echomsg row endfor endtry + finally + call provider#clear_stderr(channel_id) endtry throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_NODE_LOG_FILE') endfunction diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim index 1c77eabe23..7285ed43ea 100644 --- a/runtime/autoload/provider/pythonx.vim +++ b/runtime/autoload/provider/pythonx.vim @@ -5,7 +5,7 @@ endif let s:loaded_pythonx_provider = 1 -let s:job_opts = {'rpc': v:true, 'stderr_buffered': v:true} +let s:job_opts = {'rpc': v:true, 'on_stderr': function('provider#stderr_collector')} function! provider#pythonx#Require(host) abort let ver = (a:host.orig_name ==# 'python') ? 2 : 3 @@ -21,17 +21,18 @@ function! provider#pythonx#Require(host) abort endfor try - let job = copy(s:job_opts) - let channel_id = jobstart(args, job) + let channel_id = jobstart(args, s:job_opts) if rpcrequest(channel_id, 'poll') ==# 'ok' return channel_id endif catch echomsg v:throwpoint echomsg v:exception - for row in job.stderr + for row in provider#get_stderr(channel_id) echomsg row endfor + finally + call provider#clear_stderr(channel_id) endtry throw remote#host#LoadErrorForHost(a:host.orig_name, \ '$NVIM_PYTHON_LOG_FILE') -- cgit From e3c4c8a90e04316d1290729f6952a89ea2733cb6 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 27 Nov 2017 11:43:24 +0100 Subject: tests: mark flaky socket test pending for now --- test/functional/core/channels_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index 7a2f157df3..765e3c5919 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -27,7 +27,7 @@ describe('channels', function() source(init) end) - it('can connect to socket', function() + pending('can connect to socket', function() local server = spawn(nvim_argv) set_session(server) local address = funcs.serverlist()[1] -- cgit From 27a70fec48f5ca6c6b91aa3402eb0d1591021024 Mon Sep 17 00:00:00 2001 From: Michael Schupikov Date: Sat, 23 Sep 2017 12:44:37 +0200 Subject: version.c: mark NA patches - channels: vim-patch:8.0.0018 - GUI: vim-patch:8.0.0021 - Different recursive function implementation: vim-patch:8.0.0141 - JSON handling: vim-patch:8.0.0166, vim-patch:8.0.0169, vim-patch:8.0.0170, vim-patch:8.0.0171, vim-patch:8.0.0180 Mark vim-patch:8.0.0096 applied, since it was added in 860ecd705588470b52094b7036c016b2af15f8c9. [ci skip] --- src/nvim/version.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/nvim/version.c b/src/nvim/version.c index 205c25b6cd..286fcc2391 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -803,7 +803,7 @@ static const int included_patches[] = { 305, // 304, // 303, - // 302, NA + // 302 NA // 301, 300, // 299, @@ -925,7 +925,7 @@ static const int included_patches[] = { // 183 NA 182, 181, - // 180, + // 180 NA 179, 178, 177, @@ -935,11 +935,11 @@ static const int included_patches[] = { // 173 NA 172, // 171, - // 170, - // 169, + // 170 NA + // 169 NA 168, 167, - // 166, + // 166 NA 165, 164, // 163 NA @@ -964,7 +964,7 @@ static const int included_patches[] = { // 144 NA 143, 142, - // 141, + // 141 NA 140, // 139 NA // 138 NA @@ -1009,7 +1009,7 @@ static const int included_patches[] = { 99, // 98 NA // 97 NA - // 96, + 96, // 95 NA // 94 NA // 93 NA @@ -1084,10 +1084,10 @@ static const int included_patches[] = { // 24 NA 23, // 22 NA - // 21, + // 21 NA 20, 19, - // 18, + // 18 NA 17, // 16 NA // 15 NA -- cgit From 20bde8866e6a310f6fee6a6fcdb7546bac335944 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 26 Nov 2017 12:28:12 -0500 Subject: Add OpenBSD as an expected OS for opening char devices Closes #7542 --- src/nvim/vim.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 1db1a073ed..88014c8ae8 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -314,7 +314,7 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext() // Lowest number used for window ID. Cannot have this many windows per tab. #define LOWEST_WIN_ID 1000 -#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && defined(S_ISCHR) +#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)) && defined(S_ISCHR) # define OPEN_CHR_FILES #endif -- cgit From 8f91f2c9b47e6705e29da2fdbc9519092c757ba5 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 26 Nov 2017 21:26:56 -0500 Subject: Use defined(BSD) check when defining OPEN_CHR_FILES Rather than enumerate predefines for all BSD systems, just rely on the fact that they all "#define BSD" in sys/param.h. Debian's GNU/kFreeBSD still requires its own check, since it isn't using the BSD userspace. References: OpenBSD - https://github.com/openbsd/src/blob/210ebf9df0460bbdad02da9bbd5d859b61f57462/sys/sys/param.h#L40 FreeBSD - https://github.com/freebsd/freebsd/blob/f5d95e1f8d32db4ccccfd5ad9cecb21ed07a695d/sys/sys/param.h#L43 NetBSD - https://github.com/NetBSD/src/blob/ea620980793cf2011e5424f4a537b0488e3ffb4d/sys/sys/param.h#L49 DragonFlyBSD - https://github.com/DragonFlyBSD/DragonFlyBSD/blob/94ecf1295bb42b59772448d58ff40dd75c4a3ef8/sys/sys/param.h#L41 vim-patch:8.0.1357 --- src/nvim/os/os_defs.h | 1 + src/nvim/version.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/nvim/vim.h | 3 +- 3 files changed, 154 insertions(+), 1 deletion(-) diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h index 923a362b41..87f8d214bd 100644 --- a/src/nvim/os/os_defs.h +++ b/src/nvim/os/os_defs.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/src/nvim/version.c b/src/nvim/version.c index 286fcc2391..a09574a73e 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -78,6 +78,157 @@ static char *features[] = { // clang-format off static const int included_patches[] = { + 1357, + // 1356, + // 1355, + // 1354, + // 1353, + // 1352, + // 1351, + // 1350, + // 1349, + // 1348, + // 1347, + // 1346, + // 1345, + // 1344, + // 1343, + // 1342, + // 1341, + // 1340, + // 1339, + // 1338, + // 1337, + // 1336, + // 1335, + // 1334, + // 1333, + // 1332, + // 1331, + // 1330, + // 1329, + // 1328, + // 1327, + // 1326, + // 1325, + // 1324, + // 1323, + // 1322, + // 1321, + // 1320, + // 1319, + // 1318, + // 1317, + // 1316, + // 1315, + // 1314, + // 1313, + // 1312, + // 1311, + // 1310, + // 1309, + // 1308, + // 1307, + // 1306, + // 1305, + // 1304, + // 1303, + // 1302, + // 1301, + // 1300, + // 1299, + // 1298, + // 1297, + // 1296, + // 1295, + // 1294, + // 1293, + // 1292, + // 1291, + // 1290, + // 1289, + // 1288, + // 1287, + // 1286, + // 1285, + // 1284, + // 1283, + // 1282, + // 1281, + // 1280, + // 1279, + // 1278, + // 1277, + // 1276, + // 1275, + // 1274, + // 1273, + // 1272, + // 1271, + // 1270, + // 1269, + // 1268, + // 1267, + // 1266, + // 1265, + // 1264, + // 1263, + // 1262, + // 1261, + // 1260, + // 1259, + // 1258, + // 1257, + // 1256, + // 1255, + // 1254, + // 1253, + // 1252, + // 1251, + // 1250, + // 1249, + // 1248, + // 1247, + // 1246, + // 1245, + // 1244, + // 1243, + // 1242, + // 1241, + // 1240, + // 1239, + // 1238, + // 1237, + // 1236, + // 1235, + // 1234, + // 1233, + // 1232, + // 1231, + // 1230, + // 1229, + // 1228, + // 1227, + // 1226, + // 1225, + // 1224, + // 1223, + // 1222, + // 1221, + // 1220, + // 1219, + // 1218, + // 1217, + // 1216, + // 1215, + // 1214, + // 1213, + // 1212, + // 1211, + // 1210, + // 1209, + // 1208, + // 1207, 1206, // 1026, 1025, diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 88014c8ae8..7da3c8246f 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -314,7 +314,8 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext() // Lowest number used for window ID. Cannot have this many windows per tab. #define LOWEST_WIN_ID 1000 -#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)) && defined(S_ISCHR) +// BSD is supposed to cover FreeBSD and similar systems. +#if (defined(BSD) || defined(__FreeBSD_kernel__)) && defined(S_ISCHR) # define OPEN_CHR_FILES #endif -- cgit From 2d732a11b1ef12b3a3458f45f2f170954ad3bdc6 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 28 Nov 2017 21:19:33 -0500 Subject: provider: fix batchfile extension for ruby gem (#7651) ruby uses batchfiles with 'cmd' extension. gem creates batchfiles with 'bat' extension. `gem install rails` does the following in Windows (not Cygwin): 1. Run `gem.cmd install rails` on cmd.exe 2. gem.cmd runs `ruby.exe -x gem install rails` 3. `rails` gem is installed. `rails.bat` is created in the same directory where ruby.exe and gem.cmd reside. --- runtime/autoload/provider/ruby.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim index 518a9dc793..da73a0dfc0 100644 --- a/runtime/autoload/provider/ruby.vim +++ b/runtime/autoload/provider/ruby.vim @@ -19,7 +19,7 @@ function! provider#ruby#Detect() abort if exists("g:ruby_host_prog") return g:ruby_host_prog else - return has('win32') ? exepath('neovim-ruby-host.cmd') : exepath('neovim-ruby-host') + return has('win32') ? exepath('neovim-ruby-host.bat') : exepath('neovim-ruby-host') end endfunction -- cgit From 59f4bd435c6754f475dfb61bb6c881ce914b17e6 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 29 Nov 2017 10:07:12 -0500 Subject: unittest: Ignore _Float128 types in ffi When building with certain GCC versions, a _Float128 type is present when setting up the ffi for unit tests. ./test/unit/helpers.lua:256: declaration specifier expected near '_Float128' at line 396 /usr/bin/luajit: /usr/share/lua/5.1/busted/runner.lua:99: attempt to concatenate local 'message' (a table value) stack traceback: /usr/share/lua/5.1/busted/runner.lua:99: in function 'fn' /usr/share/lua/5.1/mediator.lua:103: in function 'publish' /usr/share/lua/5.1/busted/modules/helper_loader.lua:21: in function 'helperLoader' /usr/share/lua/5.1/busted/runner.lua:147: in function /usr/bin/busted:3: in main chunk [C]: at 0x004044a0 CMake Error at /<>/cmake/RunTests.cmake:53 (message): Running unit tests failed with error: 1. Since this is being pulled in by a dependency, not directly used by nvim, just ignore the type. Closes #7423 --- test/unit/helpers.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua index 4b9f185156..ac5e394a54 100644 --- a/test/unit/helpers.lua +++ b/test/unit/helpers.lua @@ -138,6 +138,7 @@ local function filter_complex_blocks(body) for line in body:gmatch("[^\r\n]+") do if not (string.find(line, "(^)", 1, true) ~= nil or string.find(line, "_ISwupper", 1, true) + or string.find(line, "_Float128") or string.find(line, "msgpack_zone_push_finalizer") or string.find(line, "msgpack_unpacker_reserve_buffer") or string.find(line, "UUID_NULL") -- static const uuid_t UUID_NULL = {...} -- cgit From 4618c9c43b2fe052332329b347ac10b4b1db94b5 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 29 Nov 2017 23:41:41 +0100 Subject: Revert "tui: update cleared area only if non-default bg" Reverts 0b93bab6c22edf7a07cf965ebbbf631b93e1dc1b. This change was counter-productive to the other changes which intended to reduce the role of BCE. ref #7624 --- src/nvim/tui/tui.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 732a86d0fb..724d59b15a 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -956,10 +956,9 @@ static void tui_scroll(UI *ui, Integer count) } cursor_goto(ui, saved_row, saved_col); - if (!scroll_clears_to_current_colour && grid->bg != -1) { - // Scrolling may leave wrong background in the cleared area on non-bge - // terminals. Update the cleared area of the terminal if its builtin - // scrolling facility was used and bg color is not the default. + if (!scroll_clears_to_current_colour) { + // Scrolling will leave wrong background in the cleared area on non-BCE + // terminals. Update the cleared area. clear_region(ui, clear_top, clear_bot, grid->left, grid->right); } } else { -- cgit