diff -Nru neovim-0.3.4/CMakeLists.txt neovim-0.3.8/CMakeLists.txt --- neovim-0.3.4/CMakeLists.txt 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/CMakeLists.txt 2019-07-03 01:11:42.000000000 +0000 @@ -112,7 +112,7 @@ # version string, else they are combined with the result of `git describe`. set(NVIM_VERSION_MAJOR 0) set(NVIM_VERSION_MINOR 3) -set(NVIM_VERSION_PATCH 4) +set(NVIM_VERSION_PATCH 8) set(NVIM_VERSION_PRERELEASE "") # for package maintainers # API level diff -Nru neovim-0.3.4/debian/changelog neovim-0.3.8/debian/changelog --- neovim-0.3.4/debian/changelog 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/changelog 2019-07-24 02:41:01.000000000 +0000 @@ -1,3 +1,14 @@ +neovim (0.3.8-1) unstable; urgency=medium + + * New upstream release + + Fixes FTBFS with gcc-9 due to stricter handling of compound literal + lifetimes. (Closes: #925785) + * Declare compliance with Policy 4.4.0, no changes required + * Install alternatives wrapper scripts in /usr/libexec/neovim. This avoids + cluttering $PATH and addresses lintian's binary-without-manpage tag. + + -- James McCoy Tue, 23 Jul 2019 22:41:01 -0400 + neovim (0.3.4-3) unstable; urgency=high * Backport additional changes to address CVE-2019-12735 (Closes: #930024) diff -Nru neovim-0.3.4/debian/control neovim-0.3.8/debian/control --- neovim-0.3.4/debian/control 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/control 2019-07-24 02:41:01.000000000 +0000 @@ -32,7 +32,7 @@ # Disable python tests for now, as they are hitting an unexpected failure # python-neovim , # python3-neovim , -Standards-Version: 4.3.0 +Standards-Version: 4.4.0 Homepage: https://neovim.io/ Rules-Requires-Root: no Vcs-Git: https://salsa.debian.org/vim-team/neovim.git diff -Nru neovim-0.3.4/debian/neovim.install neovim-0.3.8/debian/neovim.install --- neovim-0.3.4/debian/neovim.install 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/neovim.install 2019-07-24 02:41:01.000000000 +0000 @@ -1,2 +1,2 @@ -debian/scripts/* usr/bin/ +debian/scripts/* usr/libexec/neovim/ debian/tmp/usr/bin/nvim diff -Nru neovim-0.3.4/debian/neovim.postinst neovim-0.3.8/debian/neovim.postinst --- neovim-0.3.4/debian/neovim.postinst 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/neovim.postinst 2019-07-24 02:41:01.000000000 +0000 @@ -5,13 +5,13 @@ update-alternatives --install /usr/bin/editor editor /usr/bin/nvim 30 \ --slave /usr/share/man/man1/editor.1.gz editor.1.gz \ /usr/share/man/man1/nvim.1.gz -update-alternatives --install /usr/bin/ex ex /usr/bin/ex.nvim 30 -update-alternatives --install /usr/bin/rvim rvim /usr/bin/rvim.nvim 30 -update-alternatives --install /usr/bin/rview rview /usr/bin/rview.nvim 30 +update-alternatives --install /usr/bin/ex ex /usr/libexec/neovim/ex 30 +update-alternatives --install /usr/bin/rvim rvim /usr/libexec/neovim/rvim 30 +update-alternatives --install /usr/bin/rview rview /usr/libexec/neovim/rview 30 update-alternatives --install /usr/bin/vi vi /usr/bin/nvim 30 update-alternatives --install /usr/bin/vim vim /usr/bin/nvim 30 -update-alternatives --install /usr/bin/view view /usr/bin/view.nvim 30 -update-alternatives --install /usr/bin/vimdiff vimdiff /usr/bin/vimdiff.nvim 30 +update-alternatives --install /usr/bin/view view /usr/libexec/neovim/view 30 +update-alternatives --install /usr/bin/vimdiff vimdiff /usr/libexec/neovim/vimdiff 30 #DEBHELPER# diff -Nru neovim-0.3.4/debian/neovim.prerm neovim-0.3.8/debian/neovim.prerm --- neovim-0.3.4/debian/neovim.prerm 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/neovim.prerm 2019-07-24 02:41:01.000000000 +0000 @@ -5,13 +5,13 @@ case "$1" in remove|deconfigure) update-alternatives --remove editor /usr/bin/nvim - update-alternatives --remove ex /usr/bin/ex.nvim - update-alternatives --remove rvim /usr/bin/rvim.nvim - update-alternatives --remove rview /usr/bin/rview.nvim + update-alternatives --remove ex /usr/libexec/neovim/ex + update-alternatives --remove rvim /usr/libexec/neovim/rvim + update-alternatives --remove rview /usr/libexec/neovim/rview update-alternatives --remove vi /usr/bin/nvim update-alternatives --remove vim /usr/bin/nvim - update-alternatives --remove view /usr/bin/view.nvim - update-alternatives --remove vimdiff /usr/bin/vimdiff.nvim + update-alternatives --remove view /usr/libexec/neovim/view + update-alternatives --remove vimdiff /usr/libexec/neovim/vimdiff ;; upgrade|failed-upgrade) diff -Nru neovim-0.3.4/debian/patches/0001-debcherry-fixup-patch.patch neovim-0.3.8/debian/patches/0001-debcherry-fixup-patch.patch --- neovim-0.3.4/debian/patches/0001-debcherry-fixup-patch.patch 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/patches/0001-debcherry-fixup-patch.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,1066 +0,0 @@ -From d39c384696e94bd8cb4a8830f0ec2e801619a970 Mon Sep 17 00:00:00 2001 -From: James McCoy -Date: Wed, 26 Jun 2019 21:32:44 -0400 -Subject: [PATCH 1/7] debcherry fixup patch - -ed179f931 vim-patch:8.1.1401: misspelled mkspellmem as makespellmem - - no changes against upstream or conflicts -41a3ff9fe vim-patch:8.1.1368: modeline test fails with python but without pythonhome - - no changes against upstream or conflicts -12c5b6885 vim-patch:8.1.1367: can set 'modelineexpr' in modeline - - no changes against upstream or conflicts -cffc3f5f8 vim-patch:8.1.1366: using expressions in a modeline is unsafe - - extra changes or conflicts -a15defc3c vim-patch:8.1.0547: modeline test with keymap still fails - - extra changes or conflicts -c550a5e94 vim-patch:8.1.0546: modeline test with keymap fails - - no changes against upstream or conflicts -0605eb856 vim-patch:8.1.0506: modeline test fails when run by root - - no changes against upstream or conflicts -cbec04e98 vim-patch:8.1.0205: invalid memory access with invalid modeline - - extra changes or conflicts -ed7ca8f1e vim-patch:8.1.1046: the "secure" variable is used inconsistently - - no changes against upstream or conflicts -4f223fb12 vim-patch:8.1.0613: when executing an insecure function the secure flag is stuck - - extra changes or conflicts -4fc181350 fixup: use vim_snprintf, ASCII_ISALNUM - - no changes against upstream or conflicts -2789ea195 vim-patch:8.1.0544: setting 'filetype' in a modeline causes an error - - extra changes or conflicts -94b32dd17 vim-patch:8.1.0540: may evaluate insecure value when appending to option - - extra changes or conflicts -a36f7e776 vim-patch:8.1.0539: cannot build without the sandbox - - extra changes or conflicts -b1ab0ee1a vim-patch:8.1.0538: evaluating a modeline might invoke using a shell command - - extra changes or conflicts -bc4e31de5 vim-patch:8.0.0003 - - no changes against upstream or conflicts -53bde37a8 vim-patch:8.0.0376 - - extra changes or conflicts -aa0c704e7 vim-patch:8.0.0322 - - extra changes or conflicts -29b888573 vim-patch:8.0.0057 - - no changes against upstream or conflicts -fb1670cdd vim-patch:8.0.0056 - - extra changes or conflicts ---- - runtime/doc/options.txt | 75 +++++++++--- - src/nvim/buffer.c | 6 + - src/nvim/generators/gen_options.lua | 1 + - src/nvim/option.c | 177 +++++++++++++++++++--------- - src/nvim/option_defs.h | 1 + - src/nvim/options.lua | 21 ++++ - src/nvim/testdir/test49.in | 2 +- - src/nvim/testdir/test_alot.vim | 1 + - src/nvim/testdir/test_autocmd.vim | 23 ++++ - src/nvim/testdir/test_modeline.vim | 173 +++++++++++++++++++++++++++ - 10 files changed, 406 insertions(+), 74 deletions(-) - create mode 100644 src/nvim/testdir/test_modeline.vim - -diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt -index 534b2025c..e8471d561 100644 ---- a/runtime/doc/options.txt -+++ b/runtime/doc/options.txt -@@ -478,14 +478,17 @@ backslash in front of the ':' will be removed. Example: - /* vi:set dir=c\:\tmp: */ ~ - This sets the 'dir' option to "c:\tmp". Only a single backslash before the - ':' is removed. Thus to include "\:" you have to specify "\\:". -- -+ *E992* - No other commands than "set" are supported, for security reasons (somebody - might create a Trojan horse text file with modelines). And not all options --can be set. For some options a flag is set, so that when it's used the --|sandbox| is effective. Still, there is always a small risk that a modeline --causes trouble. E.g., when some joker sets 'textwidth' to 5 all your lines --are wrapped unexpectedly. So disable modelines before editing untrusted text. --The mail ftplugin does this, for example. -+can be set. For some options a flag is set, so that when the value is used -+the |sandbox| is effective. Some options can only be set from the modeline -+when 'modelineexpr' is set (the default is off). -+ -+Still, there is always a small risk that a modeline causes trouble. E.g., -+when some joker sets 'textwidth' to 5 all your lines are wrapped unexpectedly. -+So disable modelines before editing untrusted text. The mail ftplugin does -+this, for example. - - Hint: If you would like to do something else than setting an option, you could - define an autocommand that checks the file for a specific string. For -@@ -2439,7 +2442,7 @@ A jump table for the options with a short description can be found at |Q_op|. - The expression will be evaluated in the |sandbox| if set from a - modeline, see |sandbox-option|. - This option can't be set from a |modeline| when the 'diff' option is -- on. -+ on or the 'modelineexpr' option is off. - - It is not allowed to change text or jump to another window while - evaluating 'foldexpr' |textlock|. -@@ -2554,6 +2557,7 @@ A jump table for the options with a short description can be found at |Q_op|. - - The expression will be evaluated in the |sandbox| if set from a - modeline, see |sandbox-option|. -+ This option cannot be set in a modeline when 'modelineexpr' is off. - - It is not allowed to change text or jump to another window while - evaluating 'foldtext' |textlock|. -@@ -2589,16 +2593,8 @@ A jump table for the options with a short description can be found at |Q_op|. - The expression will be evaluated in the |sandbox| when set from a - modeline, see |sandbox-option|. That stops the option from working, - since changing the buffer text is not allowed. -- -- *'formatoptions'* *'fo'* --'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt") -- local to buffer -- This is a sequence of letters which describes how automatic -- formatting is to be done. See |fo-table|. When the 'paste' option is -- on, no formatting is done (like 'formatoptions' is empty). Commas can -- be inserted for readability. -- To avoid problems with flags that are added in the future, use the -- "+=" and "-=" feature of ":set" |add-option-flags|. -+ This option cannot be set in a modeline when 'modelineexpr' is off. -+ NOTE: This option is set to "" when 'compatible' is set. - - *'formatlistpat'* *'flp'* - 'formatlistpat' 'flp' string (default: "^\s*\d\+[\]:.)}\t ]\s*") -@@ -2613,6 +2609,16 @@ A jump table for the options with a short description can be found at |Q_op|. - The default recognizes a number, followed by an optional punctuation - character and white space. - -+ *'formatoptions'* *'fo'* -+'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt") -+ local to buffer -+ This is a sequence of letters which describes how automatic -+ formatting is to be done. See |fo-table|. When the 'paste' option is -+ on, no formatting is done (like 'formatoptions' is empty). Commas can -+ be inserted for readability. -+ To avoid problems with flags that are added in the future, use the -+ "+=" and "-=" feature of ":set" |add-option-flags|. -+ - *'formatprg'* *'fp'* - 'formatprg' 'fp' string (default "") - global or local to buffer |global-local| -@@ -2643,6 +2649,9 @@ A jump table for the options with a short description can be found at |Q_op|. - - system signals low battery life - - Nvim exits abnormally - -+ This option cannot be set from a |modeline| or in the |sandbox|, for -+ security reasons. -+ - *'gdefault'* *'gd'* *'nogdefault'* *'nogd'* - 'gdefault' 'gd' boolean (default off) - global -@@ -2978,6 +2987,7 @@ A jump table for the options with a short description can be found at |Q_op|. - 'guitabtooltip' is used for the tooltip, see below. - The expression will be evaluated in the |sandbox| when set from a - modeline, see |sandbox-option|. -+ This option cannot be set in a modeline when 'modelineexpr' is off. - - Only used when the GUI tab pages line is displayed. 'e' must be - present in 'guioptions'. For the non-GUI tab pages line 'tabline' is -@@ -3106,6 +3116,7 @@ A jump table for the options with a short description can be found at |Q_op|. - When this option contains printf-style '%' items, they will be - expanded according to the rules used for 'statusline'. See - 'titlestring' for example settings. -+ This option cannot be set in a modeline when 'modelineexpr' is off. - - *'ignorecase'* *'ic'* *'noignorecase'* *'noic'* - 'ignorecase' 'ic' boolean (default off) -@@ -3209,6 +3220,7 @@ A jump table for the options with a short description can be found at |Q_op|. - - The expression will be evaluated in the |sandbox| when set from a - modeline, see |sandbox-option|. -+ This option cannot be set in a modeline when 'modelineexpr' is off. - - It is not allowed to change text or jump to another window while - evaluating 'includeexpr' |textlock|. -@@ -3277,6 +3289,7 @@ A jump table for the options with a short description can be found at |Q_op|. - - The expression will be evaluated in the |sandbox| when set from a - modeline, see |sandbox-option|. -+ This option cannot be set in a modeline when 'modelineexpr' is off. - - It is not allowed to change text or jump to another window while - evaluating 'indentexpr' |textlock|. -@@ -3879,10 +3892,23 @@ A jump table for the options with a short description can be found at |Q_op|. - < If you have less than 512 Mbyte |:mkspell| may fail for some - languages, no matter what you set 'mkspellmem' to. - -+ This option cannot be set from a |modeline| or in the |sandbox|. -+ - *'modeline'* *'ml'* *'nomodeline'* *'noml'* - 'modeline' 'ml' boolean (Vim default: on (off for root), - Vi default: off) - local to buffer -+ If 'modeline' is on 'modelines' gives the number of lines that is -+ checked for set commands. If 'modeline' is off or 'modelines' is zero -+ no lines are checked. See |modeline|. -+ -+ *'modelineexpr'* *'mle'* *'nomodelineexpr'* *'nomle'* -+'modelineexpr' 'mle' boolean (default: off) -+ global -+ When on allow some options that are an expression to be set in the -+ modeline. Check the option for whether it is affected by -+ 'modelineexpr'. Also see |modeline|. -+ - *'modelines'* *'mls'* - 'modelines' 'mls' number (default 5) - global -@@ -4622,6 +4648,8 @@ A jump table for the options with a short description can be found at |Q_op|. - When this option is not empty, it determines the content of the ruler - string, as displayed for the 'ruler' option. - The format of this option is like that of 'statusline'. -+ This option cannot be set in a modeline when 'modelineexpr' is off. -+ - The default ruler width is 17 characters. To make the ruler 15 - characters wide, put "%15(" at the start and "%)" at the end. - Example: > -@@ -5252,7 +5280,8 @@ A jump table for the options with a short description can be found at |Q_op|. - "Pattern not found", "Back at original", etc. - q use "recording" instead of "recording @a" - F don't give the file info when editing a file, like `:silent` -- was used for the command -+ was used for the command; note that this also affects messages -+ from autocommands - - This gives you the opportunity to avoid that a change between buffers - requires you to hit , but still gives as useful a message as -@@ -5527,7 +5556,7 @@ A jump table for the options with a short description can be found at |Q_op|. - - After this option has been set successfully, Vim will source the files - "spell/LANG.vim" in 'runtimepath'. "LANG" is the value of 'spelllang' -- up to the first comma, dot or underscore. -+ up to the first character that is not an ASCII letter and not a dash. - Also see |set-spc-auto|. - - -@@ -5773,6 +5802,7 @@ A jump table for the options with a short description can be found at |Q_op|. - - The 'statusline' option will be evaluated in the |sandbox| if set from - a modeline, see |sandbox-option|. -+ This option cannot be set in a modeline when 'modelineexpr' is off. - - It is not allowed to change text or jump to another window while - evaluating 'statusline' |textlock|. -@@ -5927,6 +5957,8 @@ A jump table for the options with a short description can be found at |Q_op|. - the text to be displayed. Use "%1T" for the first label, "%2T" for - the second one, etc. Use "%X" items for closing labels. - -+ This option cannot be set in a modeline when 'modelineexpr' is off. -+ - Keep in mind that only one of the tab pages is the current one, others - are invisible and you can't jump to their windows. - -@@ -6203,8 +6235,11 @@ A jump table for the options with a short description can be found at |Q_op|. - global - When this option is not empty, it will be used for the title of the - window. This happens only when the 'title' option is on. -+ - When this option contains printf-style '%' items, they will be - expanded according to the rules used for 'statusline'. -+ This option cannot be set in a modeline when 'modelineexpr' is off. -+ - Example: > - :auto BufEnter * let &titlestring = hostname() . "/" . expand("%:p") - :set title titlestring=%<%F%=%l/%L-%P titlelen=70 -@@ -6238,6 +6273,8 @@ A jump table for the options with a short description can be found at |Q_op|. - undo file that exists is used. When it cannot be read an error is - given, no further entry is used. - See |undo-persistence|. -+ This option cannot be set from a |modeline| or in the |sandbox|, for -+ security reasons. - - *'undofile'* *'noundofile'* *'udf'* *'noudf'* - 'undofile' 'udf' boolean (default off) -diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c -index 8b107041b..99e910d15 100644 ---- a/src/nvim/buffer.c -+++ b/src/nvim/buffer.c -@@ -4923,9 +4923,15 @@ chk_modeline ( - *e = NUL; /* truncate the set command */ - - if (*s != NUL) { /* skip over an empty "::" */ -+ const int secure_save = secure; - save_SID = current_SID; - current_SID = SID_MODELINE; -+ // Make sure no risky things are executed as a side effect. -+ secure = 1; -+ - retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); -+ -+ secure = secure_save; - current_SID = save_SID; - if (retval == FAIL) /* stop if error found */ - break; -diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua -index fdc00d5dc..d9c65e17c 100644 ---- a/src/nvim/generators/gen_options.lua -+++ b/src/nvim/generators/gen_options.lua -@@ -79,6 +79,7 @@ local get_flags = function(o) - {'pri_mkrc'}, - {'deny_in_modelines', 'P_NO_ML'}, - {'deny_duplicates', 'P_NODUP'}, -+ {'modelineexpr', 'P_MLE'}, - }) do - local key_name = flag_desc[1] - local def_name = flag_desc[2] or ('P_' .. key_name:upper()) -diff --git a/src/nvim/option.c b/src/nvim/option.c -index 8c692f9f4..d36a5de20 100644 ---- a/src/nvim/option.c -+++ b/src/nvim/option.c -@@ -251,6 +251,7 @@ typedef struct vimoption { - #define P_RWINONLY 0x10000000U ///< only redraw current window - #define P_NDNAME 0x20000000U ///< only normal dir name chars allowed - #define P_UI_OPTION 0x40000000U ///< send option to remote ui -+#define P_MLE 0x80000000U ///< under control of 'modelineexpr' - - #define HIGHLIGHT_INIT \ - "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ -@@ -1200,7 +1201,7 @@ do_set ( - } - len++; - if (opt_idx == -1) { -- key = find_key_option(arg + 1); -+ key = find_key_option(arg + 1, true); - } - } else { - len = 0; -@@ -1214,7 +1215,7 @@ do_set ( - } - opt_idx = findoption_len((const char *)arg, (size_t)len); - if (opt_idx == -1) { -- key = find_key_option(arg); -+ key = find_key_option(arg, false); - } - } - -@@ -1281,6 +1282,11 @@ do_set ( - errmsg = (char_u *)_("E520: Not allowed in a modeline"); - goto skip; - } -+ if ((flags & P_MLE) && !p_mle) { -+ errmsg = (char_u *)_( -+ "E992: Not allowed in a modeline when 'modelineexpr' is off"); -+ goto skip; -+ } - /* In diff mode some options are overruled. This avoids that - * 'foldmethod' becomes "marker" instead of "diff" and that - * "wrap" gets set. */ -@@ -1355,6 +1361,10 @@ do_set ( - && nextchar != NUL && !ascii_iswhite(afterchar)) - errmsg = e_trailing; - } else { -+ -+ int value_is_replaced = !prepending && !adding && !removing; -+ int value_checked = false; -+ - if (flags & P_BOOL) { /* boolean */ - if (nextchar == '=' || nextchar == ':') { - errmsg = e_invarg; -@@ -1774,12 +1784,32 @@ do_set ( - // buffer is closed by autocommands. - saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0; - -- // Handle side effects, and set the global value for -- // ":set" on local options. Note: when setting 'syntax' -- // or 'filetype' autocommands may be triggered that can -- // cause havoc. -- errmsg = did_set_string_option(opt_idx, (char_u **)varp, -- new_value_alloced, oldval, errbuf, opt_flags); -+ { -+ uint32_t *p = insecure_flag(opt_idx, opt_flags); -+ const int secure_saved = secure; -+ -+ // When an option is set in the sandbox, from a -+ // modeline or in secure mode, then deal with side -+ // effects in secure mode. Also when the value was -+ // set with the P_INSECURE flag and is not -+ // completely replaced. -+ if ((opt_flags & OPT_MODELINE) -+ || sandbox != 0 -+ || (!value_is_replaced && (*p & P_INSECURE))) { -+ secure = 1; -+ } -+ -+ // Handle side effects, and set the global value -+ // for ":set" on local options. Note: when setting -+ // 'syntax' or 'filetype' autocommands may be -+ // triggered that can cause havoc. -+ errmsg = did_set_string_option(opt_idx, (char_u **)varp, -+ new_value_alloced, oldval, -+ errbuf, sizeof(errbuf), -+ opt_flags, &value_checked); -+ -+ secure = secure_saved; -+ } - - if (errmsg == NULL) { - if (!starting) { -@@ -1806,8 +1836,7 @@ do_set ( - } - - if (opt_idx >= 0) -- did_set_option(opt_idx, opt_flags, -- !prepending && !adding && !removing); -+ did_set_option(opt_idx, opt_flags, value_is_replaced, value_checked); - } - - skip: -@@ -1872,7 +1901,9 @@ static void - did_set_option ( - int opt_idx, - int opt_flags, /* possibly with OPT_MODELINE */ -- int new_value /* value was replaced completely */ -+ int new_value, /* value was replaced completely */ -+ int value_checked /* value was checked to be safe, no need to -+ set P_INSECURE */ - ) - { - options[opt_idx].flags |= P_WAS_SET; -@@ -1881,20 +1912,22 @@ did_set_option ( - * set the P_INSECURE flag. Otherwise, if a new value is stored reset the - * flag. */ - uint32_t *p = insecure_flag(opt_idx, opt_flags); -- if (secure -- || sandbox != 0 -- || (opt_flags & OPT_MODELINE)) -+ if (!value_checked && (secure -+ || sandbox != 0 -+ || (opt_flags & OPT_MODELINE))) { - *p = *p | P_INSECURE; -- else if (new_value) -+ } else if (new_value) { - *p = *p & ~P_INSECURE; -+ } - } - --static char_u *illegal_char(char_u *errbuf, int c) -+static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c) - { -- if (errbuf == NULL) -+ if (errbuf == NULL) { - return (char_u *)""; -- sprintf((char *)errbuf, _("E539: Illegal character <%s>"), -- (char *)transchar(c)); -+ } -+ vim_snprintf((char *)errbuf, errbuflen, _("E539: Illegal character <%s>"), -+ (char *)transchar(c)); - return errbuf; - } - -@@ -1904,10 +1937,12 @@ static char_u *illegal_char(char_u *errbuf, int c) - */ - static int string_to_key(char_u *arg) - { -- if (*arg == '<') -- return find_key_option(arg + 1); -- if (*arg == '^') -+ if (*arg == '<') { -+ return find_key_option(arg + 1, true); -+ } -+ if (*arg == '^') { - return Ctrl_chr(arg[1]); -+ } - return *arg; - } - -@@ -2383,10 +2418,12 @@ static char *set_string_option(const int opt_idx, const char *const value, - char *const saved_oldval = xstrdup(oldval); - char *const saved_newval = xstrdup(s); - -+ int value_checked = false; - char *const r = (char *)did_set_string_option( -- opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, NULL, opt_flags); -+ opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, -+ NULL, 0, opt_flags, &value_checked); - if (r == NULL) { -- did_set_option(opt_idx, opt_flags, true); -+ did_set_option(opt_idx, opt_flags, true, value_checked); - } - - // call autocommand after handling side effects -@@ -2427,13 +2464,16 @@ static bool valid_filetype(char_u *val) - * Returns NULL for success, or an error message for an error. - */ - static char_u * --did_set_string_option ( -- int opt_idx, /* index in options[] table */ -- char_u **varp, /* pointer to the option variable */ -- int new_value_alloced, /* new value was allocated */ -- char_u *oldval, /* previous value of the option */ -- char_u *errbuf, /* buffer for errors, or NULL */ -- int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ -+did_set_string_option( -+ int opt_idx, // index in options[] table -+ char_u **varp, // pointer to the option variable -+ int new_value_alloced, // new value was allocated -+ char_u *oldval, // previous value of the option -+ char_u *errbuf, // buffer for errors, or NULL -+ size_t errbuflen, // length of errors buffer -+ int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL -+ int *value_checked // value was checked to be safe, no -+ // need to set P_INSECURE - ) - { - char_u *errmsg = NULL; -@@ -2651,8 +2691,20 @@ did_set_string_option ( - if (!valid_filetype(*varp)) { - errmsg = e_invarg; - } else { -+ int secure_save = secure; -+ -+ // Reset the secure flag, since the value of 'keymap' has -+ // been checked to be safe. -+ secure = 0; -+ - // load or unload key mapping tables - errmsg = keymap_init(); -+ -+ secure = secure_save; -+ -+ // Since we check the value, there is no need to set P_INSECURE, -+ // even when the value comes from a modeline. -+ *value_checked = true; - } - - if (errmsg == NULL) { -@@ -2738,7 +2790,7 @@ did_set_string_option ( - while (*s && *s != ':') { - if (vim_strchr((char_u *)COM_ALL, *s) == NULL - && !ascii_isdigit(*s) && *s != '-') { -- errmsg = illegal_char(errbuf, *s); -+ errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - ++s; -@@ -2790,7 +2842,7 @@ did_set_string_option ( - for (s = p_shada; *s; ) { - /* Check it's a valid character */ - if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL) { -- errmsg = illegal_char(errbuf, *s); -+ errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - if (*s == 'n') { /* name is always last one */ -@@ -2810,9 +2862,9 @@ did_set_string_option ( - - if (!ascii_isdigit(*(s - 1))) { - if (errbuf != NULL) { -- sprintf((char *)errbuf, -- _("E526: Missing number after <%s>"), -- transchar_byte(*(s - 1))); -+ vim_snprintf((char *)errbuf, errbuflen, -+ _("E526: Missing number after <%s>"), -+ transchar_byte(*(s - 1))); - errmsg = errbuf; - } else - errmsg = (char_u *)""; -@@ -2990,7 +3042,7 @@ did_set_string_option ( - if (!*s) - break; - if (vim_strchr((char_u *)".wbuksid]tU", *s) == NULL) { -- errmsg = illegal_char(errbuf, *s); -+ errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - if (*++s != NUL && *s != ',' && *s != ' ') { -@@ -3004,9 +3056,9 @@ did_set_string_option ( - } - } else { - if (errbuf != NULL) { -- sprintf((char *)errbuf, -- _("E535: Illegal character after <%c>"), -- *--s); -+ vim_snprintf((char *)errbuf, errbuflen, -+ _("E535: Illegal character after <%c>"), -+ *--s); - errmsg = errbuf; - } else - errmsg = (char_u *)""; -@@ -3163,12 +3215,20 @@ did_set_string_option ( - errmsg = e_invarg; - } else { - value_changed = STRCMP(oldval, *varp) != 0; -+ -+ // Since we check the value, there is no need to set P_INSECURE, -+ // even when the value comes from a modeline. -+ *value_checked = true; - } - } else if (gvarp == &p_syn) { - if (!valid_filetype(*varp)) { - errmsg = e_invarg; - } else { - value_changed = STRCMP(oldval, *varp) != 0; -+ -+ // Since we check the value, there is no need to set P_INSECURE, -+ // even when the value comes from a modeline. -+ *value_checked = true; - } - } else if (varp == &curwin->w_p_winhl) { - if (!parse_winhl_opt(curwin)) { -@@ -3194,7 +3254,7 @@ did_set_string_option ( - if (p != NULL) { - for (s = *varp; *s; ++s) - if (vim_strchr(p, *s) == NULL) { -- errmsg = illegal_char(errbuf, *s); -+ errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - } -@@ -3258,6 +3318,11 @@ did_set_string_option ( - // already set to this value. - if (!(opt_flags & OPT_MODELINE) || value_changed) { - static int ft_recursive = 0; -+ int secure_save = secure; -+ -+ // Reset the secure flag, since the value of 'filetype' has -+ // been checked to be safe. -+ secure = 0; - - ft_recursive++; - did_filetype = true; -@@ -3270,6 +3335,7 @@ did_set_string_option ( - if (varp != &(curbuf->b_p_ft)) { - varp = NULL; - } -+ secure = secure_save; - } - } - if (varp == &(curwin->w_s->b_p_spl)) { -@@ -3287,11 +3353,13 @@ did_set_string_option ( - * '.encoding'. - */ - for (p = q; *p != NUL; ++p) -- if (vim_strchr((char_u *)"_.,", *p) != NULL) -+ if (!ASCII_ISALNUM(*p) && *p != '-') - break; -- vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim", -- (int)(p - q), q); -- source_runtime(fname, DIP_ALL); -+ if (p > q) { -+ vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim", -+ (int)(p - q), q); -+ source_runtime(fname, DIP_ALL); -+ } - } - } - -@@ -3553,7 +3621,7 @@ char_u *check_stl_option(char_u *s) - continue; - } - if (vim_strchr(STL_ALL, *s) == NULL) { -- return illegal_char(errbuf, *s); -+ return illegal_char(errbuf, sizeof(errbuf), *s); - } - if (*s == '{') { - s++; -@@ -4892,19 +4960,20 @@ char *set_option_value(const char *const name, const long number, - return NULL; - } - --/* -- * Translate a string like "t_xx", "" or "" to a key number. -- */ --int find_key_option_len(const char_u *arg, size_t len) -+// Translate a string like "t_xx", "" or "" to a key number. -+// When "has_lt" is true there is a '<' before "*arg_arg". -+// Returns 0 when the key is not recognized. -+int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) - { -- int key; -+ int key = 0; - int modifiers; -+ const char_u *arg = arg_arg; - - // Don't use get_special_key_code() for t_xx, we don't want it to call - // add_termcap_entry(). - if (len >= 4 && arg[0] == 't' && arg[1] == '_') { - key = TERMCAP2KEY(arg[2], arg[3]); -- } else { -+ } else if (has_lt) { - arg--; // put arg at the '<' - modifiers = 0; - key = find_special_key(&arg, len + 1, &modifiers, true, true, false); -@@ -4915,9 +4984,9 @@ int find_key_option_len(const char_u *arg, size_t len) - return key; - } - --static int find_key_option(const char_u *arg) -+static int find_key_option(const char_u *arg, bool has_lt) - { -- return find_key_option_len(arg, STRLEN(arg)); -+ return find_key_option_len(arg, STRLEN(arg), has_lt); - } - - /* -diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h -index 6a0d0e32e..f64b07c27 100644 ---- a/src/nvim/option_defs.h -+++ b/src/nvim/option_defs.h -@@ -503,6 +503,7 @@ EXTERN long p_mmd; // 'maxmapdepth' - EXTERN long p_mmp; // 'maxmempattern' - EXTERN long p_mis; // 'menuitems' - EXTERN char_u *p_msm; // 'mkspellmem' -+EXTERN long p_mle; // 'modelineexpr' - EXTERN long p_mls; // 'modelines' - EXTERN char_u *p_mouse; // 'mouse' - EXTERN char_u *p_mousem; // 'mousemodel' -diff --git a/src/nvim/options.lua b/src/nvim/options.lua -index 0cc6f58c5..7ca1b4d64 100644 ---- a/src/nvim/options.lua -+++ b/src/nvim/options.lua -@@ -8,6 +8,7 @@ - -- defaults={condition=nil, if_true={vi=224, vim=0}, if_false=nil}, - -- secure=nil, gettext=nil, noglob=nil, normal_fname_chars=nil, - -- pri_mkrc=nil, deny_in_modelines=nil, normal_dname_chars=nil, -+-- modelineexpr=nil, - -- expand=nil, nodefault=nil, no_mkrc=nil, vi_def=true, vim=true, - -- alloced=nil, - -- save_pv_indir=nil, -@@ -286,6 +287,7 @@ return { - deny_duplicates=true, - vi_def=true, - expand=true, -+ secure=true, - varname='p_cdpath', - defaults={if_true={vi=",,"}} - }, -@@ -856,6 +858,7 @@ return { - type='string', scope={'window'}, - vi_def=true, - vim=true, -+ modelineexpr=true, - alloced=true, - redraw={'current_window'}, - defaults={if_true={vi="0"}} -@@ -931,6 +934,7 @@ return { - type='string', scope={'window'}, - vi_def=true, - vim=true, -+ modelineexpr=true, - alloced=true, - redraw={'current_window'}, - defaults={if_true={vi="foldtext()"}} -@@ -940,6 +944,7 @@ return { - type='string', scope={'buffer'}, - vi_def=true, - vim=true, -+ modelineexpr=true, - alloced=true, - varname='p_fex', - defaults={if_true={vi=""}} -@@ -1053,6 +1058,7 @@ return { - full_name='guitablabel', abbreviation='gtl', - type='string', scope={'global'}, - vi_def=true, -+ modelineexpr=true, - redraw={'current_window'}, - enable_if=false, - }, -@@ -1143,6 +1149,7 @@ return { - full_name='iconstring', - type='string', scope={'global'}, - vi_def=true, -+ modelineexpr=true, - varname='p_iconstring', - defaults={if_true={vi=""}} - }, -@@ -1209,6 +1216,7 @@ return { - full_name='includeexpr', abbreviation='inex', - type='string', scope={'buffer'}, - vi_def=true, -+ modelineexpr=true, - alloced=true, - varname='p_inex', - defaults={if_true={vi=""}} -@@ -1225,6 +1233,7 @@ return { - type='string', scope={'buffer'}, - vi_def=true, - vim=true, -+ modelineexpr=true, - alloced=true, - varname='p_inde', - defaults={if_true={vi=""}} -@@ -1538,6 +1547,14 @@ return { - varname='p_ml', - defaults={if_true={vi=false, vim=true}} - }, -+ { -+ full_name='modelineexpr', abbreviation='mle', -+ type='bool', scope={'global'}, -+ vi_def=true, -+ secure=true, -+ varname='p_mle', -+ defaults={if_true={vi=false}} -+ }, - { - full_name='modelines', abbreviation='mls', - type='number', scope={'global'}, -@@ -1898,6 +1915,7 @@ return { - type='string', scope={'global'}, - vi_def=true, - alloced=true, -+ modelineexpr=true, - redraw={'statuslines'}, - varname='p_ruf', - defaults={if_true={vi=""}} -@@ -2293,6 +2311,7 @@ return { - type='string', scope={'global', 'window'}, - vi_def=true, - alloced=true, -+ modelineexpr=true, - redraw={'statuslines'}, - varname='p_stl', - defaults={if_true={vi=""}} -@@ -2352,6 +2371,7 @@ return { - full_name='tabline', abbreviation='tal', - type='string', scope={'global'}, - vi_def=true, -+ modelineexpr=true, - redraw={'all_windows'}, - varname='p_tal', - defaults={if_true={vi=""}} -@@ -2511,6 +2531,7 @@ return { - full_name='titlestring', - type='string', scope={'global'}, - vi_def=true, -+ modelineexpr=true, - varname='p_titlestring', - defaults={if_true={vi=""}} - }, -diff --git a/src/nvim/testdir/test49.in b/src/nvim/testdir/test49.in -index 435e62765..eb17ace2f 100644 ---- a/src/nvim/testdir/test49.in -+++ b/src/nvim/testdir/test49.in -@@ -4,7 +4,7 @@ If after adding a new test, the test output doesn't appear properly in - test49.failed, try to add one or more "G"s at the line ending in "test.out" - - STARTTEST --:se nomore -+:se nomore modelineexpr - :lang mess C - :so test49.vim - :" Go back to this file and append the results from register r. -diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim -index 0602ff6a4..9d81d2162 100644 ---- a/src/nvim/testdir/test_alot.vim -+++ b/src/nvim/testdir/test_alot.vim -@@ -28,6 +28,7 @@ source test_lambda.vim - source test_mapping.vim - source test_menu.vim - source test_messages.vim -+source test_modeline.vim - source test_move.vim - source test_partial.vim - source test_popup.vim -diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim -index 253d6750e..12b6a38ef 100644 ---- a/src/nvim/testdir/test_autocmd.vim -+++ b/src/nvim/testdir/test_autocmd.vim -@@ -652,6 +652,29 @@ func Test_OptionSet_diffmode_close() - "delfunc! AutoCommandOptionSet - endfunc - -+func Test_OptionSet_modeline() -+ throw 'skipped: Nvim does not support test_override()' -+ call test_override('starting', 1) -+ au! OptionSet -+ augroup set_tabstop -+ au OptionSet tabstop call timer_start(1, {-> execute("echo 'Handler called'", "")}) -+ augroup END -+ call writefile(['vim: set ts=7 sw=5 :', 'something'], 'XoptionsetModeline') -+ set modeline -+ let v:errmsg = '' -+ call assert_fails('split XoptionsetModeline', 'E12:') -+ call assert_equal(7, &ts) -+ call assert_equal('', v:errmsg) -+ -+ augroup set_tabstop -+ au! -+ augroup END -+ bwipe! -+ set ts& -+ call delete('XoptionsetModeline') -+ call test_override('starting', 0) -+endfunc -+ - " Test for Bufleave autocommand that deletes the buffer we are about to edit. - func Test_BufleaveWithDelete() - new | edit Xfile1 -diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim -new file mode 100644 -index 000000000..1e196e07f ---- /dev/null -+++ b/src/nvim/testdir/test_modeline.vim -@@ -0,0 +1,173 @@ -+" Tests for parsing the modeline. -+ -+func Test_modeline_invalid() -+ " This was reading allocated memory in the past. -+ call writefile(['vi:0', 'nothing'], 'Xmodeline') -+ let modeline = &modeline -+ set modeline -+ call assert_fails('set Xmodeline', 'E518:') -+ -+ let &modeline = modeline -+ bwipe! -+ call delete('Xmodeline') -+ endfunc -+ -+func Test_modeline_filetype() -+ call writefile(['vim: set ft=c :', 'nothing'], 'Xmodeline_filetype') -+ let modeline = &modeline -+ set modeline -+ filetype plugin on -+ split Xmodeline_filetype -+ call assert_equal("c", &filetype) -+ call assert_equal(1, b:did_ftplugin) -+ call assert_equal("ccomplete#Complete", &ofu) -+ -+ bwipe! -+ call delete('Xmodeline_filetype') -+ let &modeline = modeline -+ filetype plugin off -+endfunc -+ -+func Test_modeline_syntax() -+ call writefile(['vim: set syn=c :', 'nothing'], 'Xmodeline_syntax') -+ let modeline = &modeline -+ set modeline -+ syntax enable -+ split Xmodeline_syntax -+ call assert_equal("c", &syntax) -+ call assert_equal("c", b:current_syntax) -+ -+ bwipe! -+ call delete('Xmodeline_syntax') -+ let &modeline = modeline -+ syntax off -+endfunc -+ -+func Test_modeline_keymap() -+ if !has('keymap') -+ return -+ endif -+ call writefile(['vim: set keymap=greek :', 'nothing'], 'Xmodeline_keymap') -+ let modeline = &modeline -+ set modeline -+ split Xmodeline_keymap -+ call assert_equal("greek", &keymap) -+ call assert_match('greek\|grk', b:keymap_name) -+ -+ bwipe! -+ call delete('Xmodeline_keymap') -+ let &modeline = modeline -+ set keymap= iminsert=0 imsearch=-1 -+endfunc -+ -+func s:modeline_fails(what, text, error) -+ if !exists('+' . a:what) -+ return -+ endif -+ let fname = "Xmodeline_fails_" . a:what -+ call writefile(['vim: set ' . a:text . ' :', 'nothing'], fname) -+ let modeline = &modeline -+ set modeline -+ filetype plugin on -+ syntax enable -+ call assert_fails('split ' . fname, a:error) -+ call assert_equal("", &filetype) -+ call assert_equal("", &syntax) -+ -+ bwipe! -+ call delete(fname) -+ let &modeline = modeline -+ filetype plugin off -+ syntax off -+endfunc -+ -+func Test_modeline_filetype_fails() -+ call s:modeline_fails('filetype', 'ft=evil$CMD', 'E474:') -+endfunc -+ -+func Test_modeline_syntax_fails() -+ call s:modeline_fails('syntax', 'syn=evil$CMD', 'E474:') -+endfunc -+ -+func Test_modeline_keymap_fails() -+ call s:modeline_fails('keymap', 'keymap=evil$CMD', 'E474:') -+endfunc -+ -+func Test_modeline_fails_always() -+ call s:modeline_fails('backupdir', 'backupdir=Something()', 'E520:') -+ call s:modeline_fails('cdpath', 'cdpath=Something()', 'E520:') -+ call s:modeline_fails('charconvert', 'charconvert=Something()', 'E520:') -+ call s:modeline_fails('completefunc', 'completefunc=Something()', 'E520:') -+ call s:modeline_fails('cscopeprg', 'cscopeprg=Something()', 'E520:') -+ call s:modeline_fails('diffexpr', 'diffexpr=Something()', 'E520:') -+ call s:modeline_fails('directory', 'directory=Something()', 'E520:') -+ call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') -+ call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') -+ call s:modeline_fails('exrc', 'exrc=Something()', 'E520:') -+ call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:') -+ call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') -+ call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') -+ call s:modeline_fails('helpfile', 'helpfile=Something()', 'E520:') -+ call s:modeline_fails('imactivatefunc', 'imactivatefunc=Something()', 'E520:') -+ call s:modeline_fails('imstatusfunc', 'imstatusfunc=Something()', 'E520:') -+ call s:modeline_fails('imstyle', 'imstyle=Something()', 'E520:') -+ call s:modeline_fails('keywordprg', 'keywordprg=Something()', 'E520:') -+ call s:modeline_fails('langmap', 'langmap=Something()', 'E520:') -+ call s:modeline_fails('luadll', 'luadll=Something()', 'E520:') -+ call s:modeline_fails('makeef', 'makeef=Something()', 'E520:') -+ call s:modeline_fails('makeprg', 'makeprg=Something()', 'E520:') -+ call s:modeline_fails('mkspellmem', 'mkspellmem=Something()', 'E520:') -+ call s:modeline_fails('mzschemedll', 'mzschemedll=Something()', 'E520:') -+ call s:modeline_fails('mzschemegcdll', 'mzschemegcdll=Something()', 'E520:') -+ call s:modeline_fails('modelineexpr', 'modelineexpr=Something()', 'E520:') -+ call s:modeline_fails('omnifunc', 'omnifunc=Something()', 'E520:') -+ call s:modeline_fails('operatorfunc', 'operatorfunc=Something()', 'E520:') -+ call s:modeline_fails('perldll', 'perldll=Something()', 'E520:') -+ call s:modeline_fails('printdevice', 'printdevice=Something()', 'E520:') -+ call s:modeline_fails('patchexpr', 'patchexpr=Something()', 'E520:') -+ call s:modeline_fails('printexpr', 'printexpr=Something()', 'E520:') -+ call s:modeline_fails('pythondll', 'pythondll=Something()', 'E520:') -+ call s:modeline_fails('pythonhome', 'pythonhome=Something()', 'E520:') -+ call s:modeline_fails('pythonthreedll', 'pythonthreedll=Something()', 'E520:') -+ call s:modeline_fails('pythonthreehome', 'pythonthreehome=Something()', 'E520:') -+ call s:modeline_fails('pyxversion', 'pyxversion=Something()', 'E520:') -+ call s:modeline_fails('rubydll', 'rubydll=Something()', 'E520:') -+ call s:modeline_fails('runtimepath', 'runtimepath=Something()', 'E520:') -+ call s:modeline_fails('secure', 'secure=Something()', 'E520:') -+ call s:modeline_fails('shell', 'shell=Something()', 'E520:') -+ call s:modeline_fails('shellcmdflag', 'shellcmdflag=Something()', 'E520:') -+ call s:modeline_fails('shellpipe', 'shellpipe=Something()', 'E520:') -+ call s:modeline_fails('shellquote', 'shellquote=Something()', 'E520:') -+ call s:modeline_fails('shellredir', 'shellredir=Something()', 'E520:') -+ call s:modeline_fails('shellxquote', 'shellxquote=Something()', 'E520:') -+ call s:modeline_fails('spellfile', 'spellfile=Something()', 'E520:') -+ call s:modeline_fails('spellsuggest', 'spellsuggest=Something()', 'E520:') -+ call s:modeline_fails('tcldll', 'tcldll=Something()', 'E520:') -+ call s:modeline_fails('titleold', 'titleold=Something()', 'E520:') -+ call s:modeline_fails('viewdir', 'viewdir=Something()', 'E520:') -+ call s:modeline_fails('viminfo', 'viminfo=Something()', 'E520:') -+ call s:modeline_fails('viminfofile', 'viminfofile=Something()', 'E520:') -+ call s:modeline_fails('winptydll', 'winptydll=Something()', 'E520:') -+ call s:modeline_fails('undodir', 'undodir=Something()', 'E520:') -+ " only check a few terminal options -+ " Skip these since nvim doesn't support termcodes as options -+ "call s:modeline_fails('t_AB', 't_AB=Something()', 'E520:') -+ "call s:modeline_fails('t_ce', 't_ce=Something()', 'E520:') -+ "call s:modeline_fails('t_sr', 't_sr=Something()', 'E520:') -+ "call s:modeline_fails('t_8b', 't_8b=Something()', 'E520:') -+endfunc -+ -+func Test_modeline_fails_modelineexpr() -+ call s:modeline_fails('balloonexpr', 'balloonexpr=Something()', 'E992:') -+ call s:modeline_fails('foldexpr', 'foldexpr=Something()', 'E992:') -+ call s:modeline_fails('foldtext', 'foldtext=Something()', 'E992:') -+ call s:modeline_fails('formatexpr', 'formatexpr=Something()', 'E992:') -+ call s:modeline_fails('guitablabel', 'guitablabel=Something()', 'E992:') -+ call s:modeline_fails('iconstring', 'iconstring=Something()', 'E992:') -+ call s:modeline_fails('includeexpr', 'includeexpr=Something()', 'E992:') -+ call s:modeline_fails('indentexpr', 'indentexpr=Something()', 'E992:') -+ call s:modeline_fails('rulerformat', 'rulerformat=Something()', 'E992:') -+ call s:modeline_fails('statusline', 'statusline=Something()', 'E992:') -+ call s:modeline_fails('tabline', 'tabline=Something()', 'E992:') -+ call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:') -+endfunc diff -Nru neovim-0.3.4/debian/patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch neovim-0.3.8/debian/patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch --- neovim-0.3.4/debian/patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/patches/0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -From 0deb5bd4710ca912420bd796e74f6a7175d7753f Mon Sep 17 00:00:00 2001 -From: "Justin M. Keyes" -Date: Wed, 29 May 2019 00:33:22 +0200 -Subject: [PATCH 2/7] vim-patch:8.1.1365: :source should check sandbox #10082 - -Problem: Source command doesn't check for the sandbox. (Armin Razmjou) -Solution: Check for the sandbox when sourcing a file. -https://github.com/vim/vim/commit/53575521406739cf20bbe4e384d88e7dca11f040 - -(cherry picked from commit 4553fc5e6cb6c8c43f57c173d01b31a61e51d13f) - -Signed-off-by: James McCoy -Closes: CVE-2019-12735 -Closes: #930024 ---- - src/nvim/getchar.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c -index 94702a9a3..243e6afce 100644 ---- a/src/nvim/getchar.c -+++ b/src/nvim/getchar.c -@@ -1244,6 +1244,13 @@ openscript ( - EMSG(_(e_nesting)); - return; - } -+ -+ // Disallow sourcing a file in the sandbox, the commands would be executed -+ // later, possibly outside of the sandbox. -+ if (check_secure()) { -+ return; -+ } -+ - if (ignore_script) - /* Not reading from script, also don't open one. Warning message? */ - return; diff -Nru neovim-0.3.4/debian/patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch neovim-0.3.8/debian/patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch --- neovim-0.3.4/debian/patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/patches/0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -From ee6325436e32803a8b2e4678ff334c7b9423ef7e Mon Sep 17 00:00:00 2001 -From: Jan Edmund Lazo -Date: Sat, 23 Mar 2019 00:58:00 -0400 -Subject: [PATCH 3/7] vim-patch:8.1.0177: defining function in sandbox is - inconsistent - -Problem: Defining function in sandbox is inconsistent, cannot use :function - but can define a lambda. -Solution: Allow defining a function in the sandbox, but also use the sandbox - when executing it. (closes vim/vim#3182) -https://github.com/vim/vim/commit/93343725b5fa1cf580a24302455980faacae8ee2 - -(cherry picked from commit c202e4a86856594a6602a795314a081c497c2df5) - -Signed-off-by: James McCoy ---- - src/nvim/eval.c | 19 ++++++++++++++++++- - src/nvim/ex_cmds.lua | 2 +- - 2 files changed, 19 insertions(+), 2 deletions(-) - -diff --git a/src/nvim/eval.c b/src/nvim/eval.c -index 5191328b5..9163673a3 100644 ---- a/src/nvim/eval.c -+++ b/src/nvim/eval.c -@@ -241,13 +241,14 @@ typedef enum { - ///< the value (prevents error message). - } GetLvalFlags; - --// function flags -+// flags used in uf_flags - #define FC_ABORT 0x01 // abort function on error - #define FC_RANGE 0x02 // function accepts range - #define FC_DICT 0x04 // Dict function, uses "self" - #define FC_CLOSURE 0x08 // closure, uses outer scope variables - #define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 - #define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 -+#define FC_SANDBOX 0x40 // function defined in the sandbox - - // The names of packages that once were loaded are remembered. - static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL }; -@@ -5853,6 +5854,9 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate) - if (prof_def_func()) { - func_do_profile(fp); - } -+ if (sandbox) { -+ flags |= FC_SANDBOX; -+ } - fp->uf_varargs = true; - fp->uf_flags = flags; - fp->uf_calls = 0; -@@ -20315,6 +20319,9 @@ void ex_function(exarg_T *eap) - if (prof_def_func()) - func_do_profile(fp); - fp->uf_varargs = varargs; -+ if (sandbox) { -+ flags |= FC_SANDBOX; -+ } - fp->uf_flags = flags; - fp->uf_calls = 0; - fp->uf_script_ID = current_SID; -@@ -21305,6 +21312,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, - char_u *save_sourcing_name; - linenr_T save_sourcing_lnum; - scid_T save_current_SID; -+ bool using_sandbox = false; - funccall_T *fc; - int save_did_emsg; - static int depth = 0; -@@ -21462,6 +21470,12 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, - save_sourcing_name = sourcing_name; - save_sourcing_lnum = sourcing_lnum; - sourcing_lnum = 1; -+ -+ if (fp->uf_flags & FC_SANDBOX) { -+ using_sandbox = true; -+ sandbox++; -+ } -+ - // need space for new sourcing_name: - // * save_sourcing_name - // * "["number"].." or "function " -@@ -21622,6 +21636,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, - if (do_profiling_yes) { - script_prof_restore(&wait_start); - } -+ if (using_sandbox) { -+ sandbox--; -+ } - - if (p_verbose >= 12 && sourcing_name != NULL) { - ++no_wait_return; -diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua -index 79ca5363e..fae21d8c9 100644 ---- a/src/nvim/ex_cmds.lua -+++ b/src/nvim/ex_cmds.lua -@@ -1004,7 +1004,7 @@ return { - }, - { - command='function', -- flags=bit.bor(EXTRA, BANG, CMDWIN), -+ flags=bit.bor(EXTRA, BANG, SBOXOK, CMDWIN), - addr_type=ADDR_LINES, - func='ex_function', - }, diff -Nru neovim-0.3.4/debian/patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch neovim-0.3.8/debian/patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch --- neovim-0.3.4/debian/patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/patches/0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -From 5be949ce2df74446f33ea2949620234b41c046b0 Mon Sep 17 00:00:00 2001 -From: Jan Edmund Lazo -Date: Sat, 23 Mar 2019 01:26:07 -0400 -Subject: [PATCH 4/7] vim-patch:8.1.0189: function defined in sandbox not - tested - -Problem: Function defined in sandbox not tested. -Solution: Add a text. -https://github.com/vim/vim/commit/d90a144eda047816acffc7a8f297b43a7120710e - -(cherry picked from commit f514b7fbbc75b4464af5abe44d5f859a0d904495) - -Signed-off-by: James McCoy ---- - src/nvim/testdir/test_functions.vim | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim -index 7dc9f31ce..292f69d70 100644 ---- a/src/nvim/testdir/test_functions.vim -+++ b/src/nvim/testdir/test_functions.vim -@@ -1037,3 +1037,19 @@ func Test_func_range_with_edit() - call delete('Xfuncrange2') - bwipe! - endfunc -+ -+sandbox function Fsandbox() -+ normal ix -+endfunc -+ -+func Test_func_sandbox() -+ sandbox let F = {-> 'hello'} -+ call assert_equal('hello', F()) -+ -+ sandbox let F = {-> execute("normal ix\")} -+ call assert_fails('call F()', 'E48:') -+ unlet F -+ -+ call assert_fails('call Fsandbox()', 'E48:') -+ delfunc Fsandbox -+endfunc diff -Nru neovim-0.3.4/debian/patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch neovim-0.3.8/debian/patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch --- neovim-0.3.4/debian/patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/patches/0005-vim-patch-8.1.0206-duplicate-test-function-name.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -From 86093f2847efb7e0579247b7ff850e4cafe71912 Mon Sep 17 00:00:00 2001 -From: Jan Edmund Lazo -Date: Sat, 25 May 2019 14:47:17 -0400 -Subject: [PATCH 5/7] vim-patch:8.1.0206: duplicate test function name - -Problem: Duplicate test function name. -Solution: Rename both functions. -https://github.com/vim/vim/commit/cd96eef3a869557bd3d2d4497861d87cb525db06 - -(cherry picked from commit 6683cb60b805fa305a069cf7873be8b605d78a3d) - -Signed-off-by: James McCoy ---- - src/nvim/testdir/test_glob2regpat.vim | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/nvim/testdir/test_glob2regpat.vim b/src/nvim/testdir/test_glob2regpat.vim -index fdf17946b..e6e41f13e 100644 ---- a/src/nvim/testdir/test_glob2regpat.vim -+++ b/src/nvim/testdir/test_glob2regpat.vim -@@ -1,12 +1,12 @@ - " Test glob2regpat() - --func Test_invalid() -+func Test_glob2regpat_invalid() - call assert_fails('call glob2regpat(1.33)', 'E806:') - call assert_fails('call glob2regpat("}")', 'E219:') - call assert_fails('call glob2regpat("{")', 'E220:') - endfunc - --func Test_valid() -+func Test_glob2regpat_valid() - call assert_equal('^foo\.', glob2regpat('foo.*')) - call assert_equal('^foo.$', glob2regpat('foo?')) - call assert_equal('\.vim$', glob2regpat('*.vim')) diff -Nru neovim-0.3.4/debian/patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch neovim-0.3.8/debian/patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch --- neovim-0.3.4/debian/patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/patches/0006-vim-patch-8.1.1382-error-when-editing-test-file.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -From e45938b8c7465d854b3d4feeff6acfc71835078f Mon Sep 17 00:00:00 2001 -From: James McCoy -Date: Sat, 22 Jun 2019 22:09:32 -0400 -Subject: [PATCH 6/7] vim-patch:8.1.1382: error when editing test file - -Problem: Error when editing test file. -Solution: Remove part of modeline. -https://github.com/vim/vim/commit/3020a87cb121123abf1e9a1eca0eddac241fc481 - -(cherry picked from commit 13f3a21226fdd31c42ba927ff12ac6c34c940311) - -Signed-off-by: James McCoy ---- - src/nvim/testdir/test49.in | 2 +- - src/nvim/testdir/test49.vim | 3 +-- - src/nvim/testdir/test_vimscript.vim | 1 - - 3 files changed, 2 insertions(+), 4 deletions(-) - -diff --git a/src/nvim/testdir/test49.in b/src/nvim/testdir/test49.in -index eb17ace2f..435e62765 100644 ---- a/src/nvim/testdir/test49.in -+++ b/src/nvim/testdir/test49.in -@@ -4,7 +4,7 @@ If after adding a new test, the test output doesn't appear properly in - test49.failed, try to add one or more "G"s at the line ending in "test.out" - - STARTTEST --:se nomore modelineexpr -+:se nomore - :lang mess C - :so test49.vim - :" Go back to this file and append the results from register r. -diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim -index 467abcd9b..837e55ebc 100644 ---- a/src/nvim/testdir/test49.vim -+++ b/src/nvim/testdir/test49.vim -@@ -1,6 +1,6 @@ - " Vim script language tests - " Author: Servatius Brandt --" Last Change: 2016 Feb 07 -+" Last Change: 2019 May 24 - - "------------------------------------------------------------------------------- - " Test environment {{{1 -@@ -9005,5 +9005,4 @@ Xcheck 50443995 - "------------------------------------------------------------------------------- - " Modelines {{{1 - " vim: ts=8 sw=4 tw=80 fdm=marker --" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "") - "------------------------------------------------------------------------------- -diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim -index 5b16f6d20..c856fd720 100644 ---- a/src/nvim/testdir/test_vimscript.vim -+++ b/src/nvim/testdir/test_vimscript.vim -@@ -1297,5 +1297,4 @@ endfunc - "------------------------------------------------------------------------------- - " Modelines {{{1 - " vim: ts=8 sw=4 tw=80 fdm=marker --" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "") - "------------------------------------------------------------------------------- diff -Nru neovim-0.3.4/debian/patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch neovim-0.3.8/debian/patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch --- neovim-0.3.4/debian/patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/patches/0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -From 3e2e812f17fd05687dd9ffdbd42ccf9d31ee9bc7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= -Date: Wed, 26 Jun 2019 08:11:51 +0200 -Subject: [PATCH 7/7] eval/api: don't allow the API to be called in the - sandbox. - -Identifying and maintaining a "secure" subset of the API would be too -much busywork. So just disable the entire thing. - -(cherry picked from commit 413b313ad2cfd5a1ee32369b944436e14fc8bfb3) - -Signed-off-by: James McCoy ---- - src/nvim/eval.c | 4 ++++ - test/functional/eval/api_functions_spec.lua | 9 ++++++++- - 2 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/src/nvim/eval.c b/src/nvim/eval.c -index 9163673a3..618cd50a7 100644 ---- a/src/nvim/eval.c -+++ b/src/nvim/eval.c -@@ -6516,6 +6516,10 @@ static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) - - static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) - { -+ if (check_restricted() || check_secure()) { -+ return; -+ } -+ - ApiDispatchWrapper fn = (ApiDispatchWrapper)fptr; - - Array args = ARRAY_DICT_INIT; -diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua -index 6f440c7d8..951c5d685 100644 ---- a/test/functional/eval/api_functions_spec.lua -+++ b/test/functional/eval/api_functions_spec.lua -@@ -4,7 +4,8 @@ local lfs = require('lfs') - local neq, eq, command = helpers.neq, helpers.eq, helpers.command - local clear, curbufmeths = helpers.clear, helpers.curbufmeths - local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval --local insert = helpers.insert -+local insert, meth_pcall = helpers.insert, helpers.meth_pcall -+local meths = helpers.meths - - describe('api functions', function() - before_each(clear) -@@ -145,4 +146,10 @@ describe('api functions', function() - ]]) - screen:detach() - end) -+ -+ it('cannot be called from sandbox', function() -+ eq({false, 'Vim(call):E48: Not allowed in sandbox'}, -+ meth_pcall(command, "sandbox call nvim_input('ievil')")) -+ eq({''}, meths.buf_get_lines(0, 0, -1, true)) -+ end) - end) diff -Nru neovim-0.3.4/debian/patches/series neovim-0.3.8/debian/patches/series --- neovim-0.3.4/debian/patches/series 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -# exported from git by git-debcherry -0001-debcherry-fixup-patch.patch -0002-vim-patch-8.1.1365-source-should-check-sandbox-10082.patch -0003-vim-patch-8.1.0177-defining-function-in-sandbox-is-i.patch -0004-vim-patch-8.1.0189-function-defined-in-sandbox-not-t.patch -0005-vim-patch-8.1.0206-duplicate-test-function-name.patch -0006-vim-patch-8.1.1382-error-when-editing-test-file.patch -0007-eval-api-don-t-allow-the-API-to-be-called-in-the-san.patch diff -Nru neovim-0.3.4/debian/README.source neovim-0.3.8/debian/README.source --- neovim-0.3.4/debian/README.source 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/README.source 2019-07-24 02:41:01.000000000 +0000 @@ -16,6 +16,5 @@ documentation in the gitpkg(1) and git-debcherry(1) man pages. The main development branch is debian/sid, with corresponding branches for -backports to previous releases. Tagging follows upstream's naming -convention, so the first Debian upload of the upstream tag vX.Y.Z should -be tagged vX.Y.Z-1. +backports to previous releases. Tagging follows DEP-14 convention, so the +first Debian upload of the upstream tag vX.Y.Z should be tagged debian/X.Y.Z-1. diff -Nru neovim-0.3.4/debian/scripts/ex neovim-0.3.8/debian/scripts/ex --- neovim-0.3.4/debian/scripts/ex 1970-01-01 00:00:00.000000000 +0000 +++ neovim-0.3.8/debian/scripts/ex 2019-07-24 02:41:01.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec /usr/bin/nvim -e "$@" diff -Nru neovim-0.3.4/debian/scripts/ex.nvim neovim-0.3.8/debian/scripts/ex.nvim --- neovim-0.3.4/debian/scripts/ex.nvim 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/scripts/ex.nvim 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -#!/bin/sh -exec /usr/bin/nvim -e "$@" diff -Nru neovim-0.3.4/debian/scripts/rview neovim-0.3.8/debian/scripts/rview --- neovim-0.3.4/debian/scripts/rview 1970-01-01 00:00:00.000000000 +0000 +++ neovim-0.3.8/debian/scripts/rview 2019-07-24 02:41:01.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec /usr/bin/nvim -RZ "$@" diff -Nru neovim-0.3.4/debian/scripts/rview.nvim neovim-0.3.8/debian/scripts/rview.nvim --- neovim-0.3.4/debian/scripts/rview.nvim 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/scripts/rview.nvim 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -#!/bin/sh -exec /usr/bin/nvim -RZ "$@" diff -Nru neovim-0.3.4/debian/scripts/rvim neovim-0.3.8/debian/scripts/rvim --- neovim-0.3.4/debian/scripts/rvim 1970-01-01 00:00:00.000000000 +0000 +++ neovim-0.3.8/debian/scripts/rvim 2019-07-24 02:41:01.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec /usr/bin/nvim -Z "$@" diff -Nru neovim-0.3.4/debian/scripts/rvim.nvim neovim-0.3.8/debian/scripts/rvim.nvim --- neovim-0.3.4/debian/scripts/rvim.nvim 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/scripts/rvim.nvim 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -#!/bin/sh -exec /usr/bin/nvim -Z "$@" diff -Nru neovim-0.3.4/debian/scripts/view neovim-0.3.8/debian/scripts/view --- neovim-0.3.4/debian/scripts/view 1970-01-01 00:00:00.000000000 +0000 +++ neovim-0.3.8/debian/scripts/view 2019-07-24 02:41:01.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec /usr/bin/nvim -R "$@" diff -Nru neovim-0.3.4/debian/scripts/view.nvim neovim-0.3.8/debian/scripts/view.nvim --- neovim-0.3.4/debian/scripts/view.nvim 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/scripts/view.nvim 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -#!/bin/sh -exec /usr/bin/nvim -R "$@" diff -Nru neovim-0.3.4/debian/scripts/vimdiff neovim-0.3.8/debian/scripts/vimdiff --- neovim-0.3.4/debian/scripts/vimdiff 1970-01-01 00:00:00.000000000 +0000 +++ neovim-0.3.8/debian/scripts/vimdiff 2019-07-24 02:41:01.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec /usr/bin/nvim -d "$@" diff -Nru neovim-0.3.4/debian/scripts/vimdiff.nvim neovim-0.3.8/debian/scripts/vimdiff.nvim --- neovim-0.3.4/debian/scripts/vimdiff.nvim 2019-06-27 01:21:33.000000000 +0000 +++ neovim-0.3.8/debian/scripts/vimdiff.nvim 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -#!/bin/sh -exec /usr/bin/nvim -d "$@" diff -Nru neovim-0.3.4/runtime/doc/options.txt neovim-0.3.8/runtime/doc/options.txt --- neovim-0.3.4/runtime/doc/options.txt 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/runtime/doc/options.txt 2019-07-03 01:11:42.000000000 +0000 @@ -478,14 +478,17 @@ /* vi:set dir=c\:\tmp: */ ~ This sets the 'dir' option to "c:\tmp". Only a single backslash before the ':' is removed. Thus to include "\:" you have to specify "\\:". - + *E992* No other commands than "set" are supported, for security reasons (somebody might create a Trojan horse text file with modelines). And not all options -can be set. For some options a flag is set, so that when it's used the -|sandbox| is effective. Still, there is always a small risk that a modeline -causes trouble. E.g., when some joker sets 'textwidth' to 5 all your lines -are wrapped unexpectedly. So disable modelines before editing untrusted text. -The mail ftplugin does this, for example. +can be set. For some options a flag is set, so that when the value is used +the |sandbox| is effective. Some options can only be set from the modeline +when 'modelineexpr' is set (the default is off). + +Still, there is always a small risk that a modeline causes trouble. E.g., +when some joker sets 'textwidth' to 5 all your lines are wrapped unexpectedly. +So disable modelines before editing untrusted text. The mail ftplugin does +this, for example. Hint: If you would like to do something else than setting an option, you could define an autocommand that checks the file for a specific string. For @@ -2439,7 +2442,7 @@ The expression will be evaluated in the |sandbox| if set from a modeline, see |sandbox-option|. This option can't be set from a |modeline| when the 'diff' option is - on. + on or the 'modelineexpr' option is off. It is not allowed to change text or jump to another window while evaluating 'foldexpr' |textlock|. @@ -2554,6 +2557,7 @@ The expression will be evaluated in the |sandbox| if set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'foldtext' |textlock|. @@ -2589,16 +2593,8 @@ The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. That stops the option from working, since changing the buffer text is not allowed. - - *'formatoptions'* *'fo'* -'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt") - local to buffer - This is a sequence of letters which describes how automatic - formatting is to be done. See |fo-table|. When the 'paste' option is - on, no formatting is done (like 'formatoptions' is empty). Commas can - be inserted for readability. - To avoid problems with flags that are added in the future, use the - "+=" and "-=" feature of ":set" |add-option-flags|. + This option cannot be set in a modeline when 'modelineexpr' is off. + NOTE: This option is set to "" when 'compatible' is set. *'formatlistpat'* *'flp'* 'formatlistpat' 'flp' string (default: "^\s*\d\+[\]:.)}\t ]\s*") @@ -2613,6 +2609,16 @@ The default recognizes a number, followed by an optional punctuation character and white space. + *'formatoptions'* *'fo'* +'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt") + local to buffer + This is a sequence of letters which describes how automatic + formatting is to be done. See |fo-table|. When the 'paste' option is + on, no formatting is done (like 'formatoptions' is empty). Commas can + be inserted for readability. + To avoid problems with flags that are added in the future, use the + "+=" and "-=" feature of ":set" |add-option-flags|. + *'formatprg'* *'fp'* 'formatprg' 'fp' string (default "") global or local to buffer |global-local| @@ -2643,6 +2649,9 @@ - system signals low battery life - Nvim exits abnormally + This option cannot be set from a |modeline| or in the |sandbox|, for + security reasons. + *'gdefault'* *'gd'* *'nogdefault'* *'nogd'* 'gdefault' 'gd' boolean (default off) global @@ -2978,6 +2987,7 @@ 'guitabtooltip' is used for the tooltip, see below. The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. Only used when the GUI tab pages line is displayed. 'e' must be present in 'guioptions'. For the non-GUI tab pages line 'tabline' is @@ -3106,6 +3116,7 @@ When this option contains printf-style '%' items, they will be expanded according to the rules used for 'statusline'. See 'titlestring' for example settings. + This option cannot be set in a modeline when 'modelineexpr' is off. *'ignorecase'* *'ic'* *'noignorecase'* *'noic'* 'ignorecase' 'ic' boolean (default off) @@ -3209,6 +3220,7 @@ The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'includeexpr' |textlock|. @@ -3277,6 +3289,7 @@ The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'indentexpr' |textlock|. @@ -3879,10 +3892,23 @@ < If you have less than 512 Mbyte |:mkspell| may fail for some languages, no matter what you set 'mkspellmem' to. + This option cannot be set from a |modeline| or in the |sandbox|. + *'modeline'* *'ml'* *'nomodeline'* *'noml'* 'modeline' 'ml' boolean (Vim default: on (off for root), Vi default: off) local to buffer + If 'modeline' is on 'modelines' gives the number of lines that is + checked for set commands. If 'modeline' is off or 'modelines' is zero + no lines are checked. See |modeline|. + + *'modelineexpr'* *'mle'* *'nomodelineexpr'* *'nomle'* +'modelineexpr' 'mle' boolean (default: off) + global + When on allow some options that are an expression to be set in the + modeline. Check the option for whether it is affected by + 'modelineexpr'. Also see |modeline|. + *'modelines'* *'mls'* 'modelines' 'mls' number (default 5) global @@ -4622,6 +4648,8 @@ When this option is not empty, it determines the content of the ruler string, as displayed for the 'ruler' option. The format of this option is like that of 'statusline'. + This option cannot be set in a modeline when 'modelineexpr' is off. + The default ruler width is 17 characters. To make the ruler 15 characters wide, put "%15(" at the start and "%)" at the end. Example: > @@ -5252,7 +5280,8 @@ "Pattern not found", "Back at original", etc. q use "recording" instead of "recording @a" F don't give the file info when editing a file, like `:silent` - was used for the command + was used for the command; note that this also affects messages + from autocommands This gives you the opportunity to avoid that a change between buffers requires you to hit , but still gives as useful a message as @@ -5527,7 +5556,7 @@ After this option has been set successfully, Vim will source the files "spell/LANG.vim" in 'runtimepath'. "LANG" is the value of 'spelllang' - up to the first comma, dot or underscore. + up to the first character that is not an ASCII letter and not a dash. Also see |set-spc-auto|. @@ -5773,6 +5802,7 @@ The 'statusline' option will be evaluated in the |sandbox| if set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'statusline' |textlock|. @@ -5927,6 +5957,8 @@ the text to be displayed. Use "%1T" for the first label, "%2T" for the second one, etc. Use "%X" items for closing labels. + This option cannot be set in a modeline when 'modelineexpr' is off. + Keep in mind that only one of the tab pages is the current one, others are invisible and you can't jump to their windows. @@ -6203,8 +6235,11 @@ global When this option is not empty, it will be used for the title of the window. This happens only when the 'title' option is on. + When this option contains printf-style '%' items, they will be expanded according to the rules used for 'statusline'. + This option cannot be set in a modeline when 'modelineexpr' is off. + Example: > :auto BufEnter * let &titlestring = hostname() . "/" . expand("%:p") :set title titlestring=%<%F%=%l/%L-%P titlelen=70 @@ -6238,6 +6273,8 @@ undo file that exists is used. When it cannot be read an error is given, no further entry is used. See |undo-persistence|. + This option cannot be set from a |modeline| or in the |sandbox|, for + security reasons. *'undofile'* *'noundofile'* *'udf'* *'noudf'* 'undofile' 'udf' boolean (default off) diff -Nru neovim-0.3.4/runtime/doc/provider.txt neovim-0.3.8/runtime/doc/provider.txt --- neovim-0.3.4/runtime/doc/provider.txt 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/runtime/doc/provider.txt 2019-07-03 01:11:42.000000000 +0000 @@ -24,29 +24,34 @@ |python3| interfaces (which are implemented as remote-plugins). Note: Only the Vim 7.3 API is supported; bindeval (Vim 7.4) is not. -PYTHON QUICKSTART ~ - -Install the "pynvim" Python package: -- Run |:checkhealth| to see if you already have the package (some package - managers install the "pynvim" Python package with Nvim itself). +PYTHON QUICKSTART ~ -- For Python 2 plugins, make sure Python 2.7 is available in your $PATH, then - install the package systemwide: > - sudo pip2 install --upgrade pynvim -< or for the current user: > - pip2 install --user --upgrade pynvim -< If "pip2" is missing, try "pip". - -- For Python 3 plugins, make sure Python 3.4+ is available in your $PATH, then - install the package systemwide: > - sudo pip3 install --upgrade pynvim -< or for the current user: > - pip3 install --user --upgrade pynvim -< If "pip3" is missing, try "pip". +To use Python plugins, you need the "pynvim" module. Run |:checkhealth| to see +if you already have it (some package managers install the module with Nvim +itself). + +For Python 3 plugins: +1. Make sure Python 3.4+ is available in your $PATH. +2. Install the module (try "pip" if "pip3" is missing): > + pip3 install --user --upgrade pynvim + +For Python 2 plugins: +1. Make sure Python 2.7 is available in your $PATH. +2. Install the module (try "pip" if "pip2" is missing): > + pip2 install --user --upgrade pynvim + +The pip `--upgrade` flag ensures that you get the latest version even if +a previous version was already installed. + +See also |python-virtualenv|. + +Note: The old "neovim" module was renamed to "pynvim". +https://github.com/neovim/neovim/wiki/Following-HEAD#20181118 +If you run into problems, uninstall _both_ then install "pynvim" again: > + pip uninstall neovim pynvim + pip install pynvim -- The `--upgrade` flag ensures you have the latest version even if a previous - version was already installed. PYTHON PROVIDER CONFIGURATION ~ *g:python_host_prog* @@ -67,8 +72,9 @@ To disable Python 3 support: > let g:loaded_python3_provider = 1 -PYTHON VIRTUALENVS ~ +PYTHON VIRTUALENVS ~ + *python-virtualenv* If you plan to use per-project virtualenvs often, you should assign one virtualenv for Neovim and hard-code the interpreter path via |g:python3_host_prog| (or |g:python_host_prog|) so that the "pynvim" package @@ -91,6 +97,7 @@ Nvim supports Ruby |remote-plugin|s and the Vim legacy |ruby-vim| interface (which is itself implemented as a Nvim remote-plugin). + RUBY QUICKSTART ~ To use Ruby plugins with Nvim, install the latest "neovim" RubyGem: > @@ -98,6 +105,7 @@ Run |:checkhealth| to see if your system is up-to-date. + RUBY PROVIDER CONFIGURATION ~ *g:loaded_ruby_provider* To disable Ruby support: > @@ -120,6 +128,7 @@ Nvim supports Node.js |remote-plugin|s. https://github.com/neovim/node-client/ + NODEJS QUICKSTART~ To use javascript remote-plugins with Nvim, install the "neovim" npm package: > @@ -127,6 +136,7 @@ Run |:checkhealth| to see if your system is up-to-date. + NODEJS PROVIDER CONFIGURATION~ *g:loaded_node_provider* To disable Node.js support: > Binary files /tmp/tmpnzwXRN/C7UKXpqbO1/neovim-0.3.4/runtime/nvim.png and /tmp/tmpnzwXRN/UGUJdm05iK/neovim-0.3.8/runtime/nvim.png differ diff -Nru neovim-0.3.4/scripts/genappimage.sh neovim-0.3.8/scripts/genappimage.sh --- neovim-0.3.4/scripts/genappimage.sh 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/scripts/genappimage.sh 2019-07-03 01:11:42.000000000 +0000 @@ -37,29 +37,24 @@ cd "$APP_BUILD_DIR" -curl -Lo "$APP_BUILD_DIR"/appimage_functions.sh https://github.com/AppImage/AppImages/raw/master/functions.sh -. ./appimage_functions.sh +# Only downloads linuxdeploy if the remote file is different from local +if [ -e "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage ]; then + curl -Lo "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage \ + -z "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage \ + https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage +else + curl -Lo "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage \ + https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage +fi + +chmod +x "$APP_BUILD_DIR"/linuxdeploy-x86_64.AppImage -# Copy desktop and icon file to AppDir for AppRun to pick them up. -# get_apprun -# get_desktop -cp "$ROOT_DIR/runtime/nvim.desktop" "$APP_DIR/" -cp "$ROOT_DIR/runtime/nvim.png" "$APP_DIR/" +# metainfo is not packaged automatically by linuxdeploy mkdir "$APP_DIR/usr/share/metainfo/" cp "$ROOT_DIR/runtime/nvim.appdata.xml" "$APP_DIR/usr/share/metainfo/" cd "$APP_DIR" -# copy dependencies -copy_deps -# Move the libraries to usr/bin -move_lib - -# Delete stuff that should not go into the AppImage. -# Delete dangerous libraries; see -# https://github.com/AppImage/AppImages/blob/master/excludelist -delete_blacklisted - ######################################################################## # AppDir complete. Now package it as an AppImage. ######################################################################## @@ -78,21 +73,24 @@ cd "$APP_BUILD_DIR" # Get out of AppImage directory. +# Set the name of the file generated by appimage +export OUTPUT=nvim.appimage + +# If it's a release generate the zsync file +if [ -n "$TAG" ]; then + export UPDATE_INFORMATION="gh-releases-zsync|neovim|neovim|$TAG|nvim.appimage.zsync" +fi + # Generate AppImage. # - Expects: $ARCH, $APP, $VERSION env vars # - Expects: ./$APP.AppDir/ directory -# - Produces: ../out/$APP-$VERSION.glibc$GLIBC_NEEDED-$ARCH.AppImage -if [ -n "$TAG" ]; then - generate_type2_appimage -u "gh-releases-zsync|neovim|neovim|$TAG|nvim.appimage.zsync" -else - generate_type2_appimage -fi +# - Produces: ./nvim.appimage +./linuxdeploy-x86_64.AppImage --appdir $APP.AppDir -d $ROOT_DIR/runtime/nvim.desktop -i \ +"$ROOT_DIR/runtime/nvim.png" --output appimage # Moving the final executable to a different folder so it isn't in the # way for a subsequent build. -mv "$ROOT_DIR"/out/*.AppImage* "$ROOT_DIR"/build/bin -# Remove the (now empty) folder the AppImage was built in -rmdir "$ROOT_DIR"/out +mv "$ROOT_DIR"/build/nvim.appimage* "$ROOT_DIR"/build/bin echo 'genappimage.sh: finished' diff -Nru neovim-0.3.4/scripts/release.sh neovim-0.3.8/scripts/release.sh --- neovim-0.3.4/scripts/release.sh 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/scripts/release.sh 2019-07-03 01:11:42.000000000 +0000 @@ -15,10 +15,6 @@ # - Tag the commit. # Create the "version bump" commit: # - CMakeLists.txt: Set NVIM_VERSION_PRERELEASE to "-dev" -# -# Manual steps: -# - CMakeLists.txt: Bump NVIM_VERSION_* as appropriate. -# - git push --follow-tags set -e set -u @@ -95,5 +91,9 @@ echo " Next steps: - Double-check NVIM_VERSION_* in CMakeLists.txt - - git push --follow-tags - - update website: index.html" + - Push the tag: + git push --follow-tags + - Update the 'stable' tag: + git push --force upstream HEAD^:refs/tags/stable + git fetch --tags + - Update website: index.html" diff -Nru neovim-0.3.4/src/nvim/api/vim.c neovim-0.3.8/src/nvim/api/vim.c --- neovim-0.3.4/src/nvim/api/vim.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/api/vim.c 2019-07-03 01:11:42.000000000 +0000 @@ -594,7 +594,7 @@ return; } - post_chdir(kCdScopeGlobal); + post_chdir(kCdScopeGlobal, true); try_end(err); } diff -Nru neovim-0.3.4/src/nvim/buffer.c neovim-0.3.8/src/nvim/buffer.c --- neovim-0.3.4/src/nvim/buffer.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/buffer.c 2019-07-03 01:11:42.000000000 +0000 @@ -1559,6 +1559,7 @@ if (starting == 0 && curbuf->b_ffname != NULL && vim_chdirfile(curbuf->b_ffname) == OK) { + post_chdir(kCdScopeGlobal, false); shorten_fnames(true); } } @@ -4923,9 +4924,15 @@ *e = NUL; /* truncate the set command */ if (*s != NUL) { /* skip over an empty "::" */ + const int secure_save = secure; save_SID = current_SID; current_SID = SID_MODELINE; + // Make sure no risky things are executed as a side effect. + secure = 1; + retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); + + secure = secure_save; current_SID = save_SID; if (retval == FAIL) /* stop if error found */ break; diff -Nru neovim-0.3.4/src/nvim/eval.c neovim-0.3.8/src/nvim/eval.c --- neovim-0.3.4/src/nvim/eval.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/eval.c 2019-07-03 01:11:42.000000000 +0000 @@ -241,13 +241,14 @@ ///< the value (prevents error message). } GetLvalFlags; -// function flags +// flags used in uf_flags #define FC_ABORT 0x01 // abort function on error #define FC_RANGE 0x02 // function accepts range #define FC_DICT 0x04 // Dict function, uses "self" #define FC_CLOSURE 0x08 // closure, uses outer scope variables #define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 #define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 +#define FC_SANDBOX 0x40 // function defined in the sandbox // The names of packages that once were loaded are remembered. static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL }; @@ -5853,6 +5854,9 @@ if (prof_def_func()) { func_do_profile(fp); } + if (sandbox) { + flags |= FC_SANDBOX; + } fp->uf_varargs = true; fp->uf_flags = flags; fp->uf_calls = 0; @@ -6512,6 +6516,10 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) { + if (check_restricted() || check_secure()) { + return; + } + ApiDispatchWrapper fn = (ApiDispatchWrapper)fptr; Array args = ARRAY_DICT_INIT; @@ -20315,6 +20323,9 @@ if (prof_def_func()) func_do_profile(fp); fp->uf_varargs = varargs; + if (sandbox) { + flags |= FC_SANDBOX; + } fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_script_ID = current_SID; @@ -21305,6 +21316,7 @@ char_u *save_sourcing_name; linenr_T save_sourcing_lnum; scid_T save_current_SID; + bool using_sandbox = false; funccall_T *fc; int save_did_emsg; static int depth = 0; @@ -21462,6 +21474,12 @@ save_sourcing_name = sourcing_name; save_sourcing_lnum = sourcing_lnum; sourcing_lnum = 1; + + if (fp->uf_flags & FC_SANDBOX) { + using_sandbox = true; + sandbox++; + } + // need space for new sourcing_name: // * save_sourcing_name // * "["number"].." or "function " @@ -21622,6 +21640,9 @@ if (do_profiling_yes) { script_prof_restore(&wait_start); } + if (using_sandbox) { + sandbox--; + } if (p_verbose >= 12 && sourcing_name != NULL) { ++no_wait_return; diff -Nru neovim-0.3.4/src/nvim/ex_cmds.lua neovim-0.3.8/src/nvim/ex_cmds.lua --- neovim-0.3.4/src/nvim/ex_cmds.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/ex_cmds.lua 2019-07-03 01:11:42.000000000 +0000 @@ -1004,7 +1004,7 @@ }, { command='function', - flags=bit.bor(EXTRA, BANG, CMDWIN), + flags=bit.bor(EXTRA, BANG, SBOXOK, CMDWIN), addr_type=ADDR_LINES, func='ex_function', }, diff -Nru neovim-0.3.4/src/nvim/ex_docmd.c neovim-0.3.8/src/nvim/ex_docmd.c --- neovim-0.3.4/src/nvim/ex_docmd.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/ex_docmd.c 2019-07-03 01:11:42.000000000 +0000 @@ -7218,7 +7218,7 @@ /// Deal with the side effects of changing the current directory. /// /// @param scope Scope of the function call (global, tab or window). -void post_chdir(CdScope scope) +void post_chdir(CdScope scope, bool trigger_dirchanged) { // Always overwrite the window-local CWD. xfree(curwin->w_localdir); @@ -7258,7 +7258,10 @@ } shorten_fnames(true); - do_autocmd_dirchanged(cwd, scope); + + if (trigger_dirchanged) { + do_autocmd_dirchanged(cwd, scope); + } } /// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`. @@ -7320,7 +7323,7 @@ if (vim_chdir(new_dir, scope)) { EMSG(_(e_failed)); } else { - post_chdir(scope); + post_chdir(scope, true); // Echo the new current directory if the command was typed. if (KeyTyped || p_verbose >= 5) { ex_pwd(eap); diff -Nru neovim-0.3.4/src/nvim/generators/gen_options.lua neovim-0.3.8/src/nvim/generators/gen_options.lua --- neovim-0.3.4/src/nvim/generators/gen_options.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/generators/gen_options.lua 2019-07-03 01:11:42.000000000 +0000 @@ -79,6 +79,7 @@ {'pri_mkrc'}, {'deny_in_modelines', 'P_NO_ML'}, {'deny_duplicates', 'P_NODUP'}, + {'modelineexpr', 'P_MLE'}, }) do local key_name = flag_desc[1] local def_name = flag_desc[2] or ('P_' .. key_name:upper()) diff -Nru neovim-0.3.4/src/nvim/getchar.c neovim-0.3.8/src/nvim/getchar.c --- neovim-0.3.4/src/nvim/getchar.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/getchar.c 2019-07-03 01:11:42.000000000 +0000 @@ -1244,6 +1244,13 @@ EMSG(_(e_nesting)); return; } + + // Disallow sourcing a file in the sandbox, the commands would be executed + // later, possibly outside of the sandbox. + if (check_secure()) { + return; + } + if (ignore_script) /* Not reading from script, also don't open one. Warning message? */ return; diff -Nru neovim-0.3.4/src/nvim/memfile.c neovim-0.3.8/src/nvim/memfile.c --- neovim-0.3.4/src/nvim/memfile.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/memfile.c 2019-07-03 01:11:42.000000000 +0000 @@ -76,7 +76,8 @@ /// @param flags Flags for open() call. /// -/// @return The open memory file. +/// @return - The open memory file, on success. +/// - NULL, on failure (e.g. file does not exist). memfile_T *mf_open(char_u *fname, int flags) { memfile_T *mfp = xmalloc(sizeof(memfile_T)); diff -Nru neovim-0.3.4/src/nvim/memline.c neovim-0.3.8/src/nvim/memline.c --- neovim-0.3.4/src/nvim/memline.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/memline.c 2019-07-03 01:11:42.000000000 +0000 @@ -277,6 +277,9 @@ // Open the memfile. No swap file is created yet. memfile_T *mfp = mf_open(NULL, 0); + if (mfp == NULL) { + goto error; + } buf->b_ml.ml_mfp = mfp; buf->b_ml.ml_flags = ML_EMPTY; @@ -360,10 +363,12 @@ return OK; error: - if (hp) { - mf_put(mfp, hp, false, false); + if (mfp != NULL) { + if (hp) { + mf_put(mfp, hp, false, false); + } + mf_close(mfp, true); // will also xfree(mfp->mf_fname) } - mf_close(mfp, true); // will also xfree(mfp->mf_fname) buf->b_ml.ml_mfp = NULL; return FAIL; } @@ -839,7 +844,7 @@ mf_open() will consume "fname_used"! */ mfp = mf_open(fname_used, O_RDONLY); fname_used = p; - if (mfp->mf_fd < 0) { + if (mfp == NULL || mfp->mf_fd < 0) { EMSG2(_("E306: Cannot open %s"), fname_used); goto theend; } diff -Nru neovim-0.3.4/src/nvim/option.c neovim-0.3.8/src/nvim/option.c --- neovim-0.3.4/src/nvim/option.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/option.c 2019-07-03 01:11:42.000000000 +0000 @@ -251,6 +251,7 @@ #define P_RWINONLY 0x10000000U ///< only redraw current window #define P_NDNAME 0x20000000U ///< only normal dir name chars allowed #define P_UI_OPTION 0x40000000U ///< send option to remote ui +#define P_MLE 0x80000000U ///< under control of 'modelineexpr' #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ @@ -306,6 +307,15 @@ static char *(p_icm_values[]) = { "nosplit", "split", NULL }; static char *(p_scl_values[]) = { "yes", "no", "auto", NULL }; +/// All possible flags for 'shm'. +static char_u SHM_ALL[] = { + SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, + SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER, + SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, SHM_COMPLETIONMENU, + SHM_RECORDING, SHM_FILEINFO, + 0, +}; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "option.c.generated.h" #endif @@ -1200,7 +1210,7 @@ } len++; if (opt_idx == -1) { - key = find_key_option(arg + 1); + key = find_key_option(arg + 1, true); } } else { len = 0; @@ -1214,7 +1224,7 @@ } opt_idx = findoption_len((const char *)arg, (size_t)len); if (opt_idx == -1) { - key = find_key_option(arg); + key = find_key_option(arg, false); } } @@ -1281,6 +1291,11 @@ errmsg = (char_u *)_("E520: Not allowed in a modeline"); goto skip; } + if ((flags & P_MLE) && !p_mle) { + errmsg = (char_u *)_( + "E992: Not allowed in a modeline when 'modelineexpr' is off"); + goto skip; + } /* In diff mode some options are overruled. This avoids that * 'foldmethod' becomes "marker" instead of "diff" and that * "wrap" gets set. */ @@ -1355,6 +1370,10 @@ && nextchar != NUL && !ascii_iswhite(afterchar)) errmsg = e_trailing; } else { + + int value_is_replaced = !prepending && !adding && !removing; + int value_checked = false; + if (flags & P_BOOL) { /* boolean */ if (nextchar == '=' || nextchar == ':') { errmsg = e_invarg; @@ -1774,12 +1793,32 @@ // buffer is closed by autocommands. saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0; - // Handle side effects, and set the global value for - // ":set" on local options. Note: when setting 'syntax' - // or 'filetype' autocommands may be triggered that can - // cause havoc. - errmsg = did_set_string_option(opt_idx, (char_u **)varp, - new_value_alloced, oldval, errbuf, opt_flags); + { + uint32_t *p = insecure_flag(opt_idx, opt_flags); + const int secure_saved = secure; + + // When an option is set in the sandbox, from a + // modeline or in secure mode, then deal with side + // effects in secure mode. Also when the value was + // set with the P_INSECURE flag and is not + // completely replaced. + if ((opt_flags & OPT_MODELINE) + || sandbox != 0 + || (!value_is_replaced && (*p & P_INSECURE))) { + secure = 1; + } + + // Handle side effects, and set the global value + // for ":set" on local options. Note: when setting + // 'syntax' or 'filetype' autocommands may be + // triggered that can cause havoc. + errmsg = did_set_string_option(opt_idx, (char_u **)varp, + new_value_alloced, oldval, + errbuf, sizeof(errbuf), + opt_flags, &value_checked); + + secure = secure_saved; + } if (errmsg == NULL) { if (!starting) { @@ -1806,8 +1845,7 @@ } if (opt_idx >= 0) - did_set_option(opt_idx, opt_flags, - !prepending && !adding && !removing); + did_set_option(opt_idx, opt_flags, value_is_replaced, value_checked); } skip: @@ -1872,7 +1910,9 @@ did_set_option ( int opt_idx, int opt_flags, /* possibly with OPT_MODELINE */ - int new_value /* value was replaced completely */ + int new_value, /* value was replaced completely */ + int value_checked /* value was checked to be safe, no need to + set P_INSECURE */ ) { options[opt_idx].flags |= P_WAS_SET; @@ -1881,20 +1921,22 @@ * set the P_INSECURE flag. Otherwise, if a new value is stored reset the * flag. */ uint32_t *p = insecure_flag(opt_idx, opt_flags); - if (secure - || sandbox != 0 - || (opt_flags & OPT_MODELINE)) + if (!value_checked && (secure + || sandbox != 0 + || (opt_flags & OPT_MODELINE))) { *p = *p | P_INSECURE; - else if (new_value) + } else if (new_value) { *p = *p & ~P_INSECURE; + } } -static char_u *illegal_char(char_u *errbuf, int c) +static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c) { - if (errbuf == NULL) + if (errbuf == NULL) { return (char_u *)""; - sprintf((char *)errbuf, _("E539: Illegal character <%s>"), - (char *)transchar(c)); + } + vim_snprintf((char *)errbuf, errbuflen, _("E539: Illegal character <%s>"), + (char *)transchar(c)); return errbuf; } @@ -1904,10 +1946,12 @@ */ static int string_to_key(char_u *arg) { - if (*arg == '<') - return find_key_option(arg + 1); - if (*arg == '^') + if (*arg == '<') { + return find_key_option(arg + 1, true); + } + if (*arg == '^') { return Ctrl_chr(arg[1]); + } return *arg; } @@ -2383,10 +2427,12 @@ char *const saved_oldval = xstrdup(oldval); char *const saved_newval = xstrdup(s); + int value_checked = false; char *const r = (char *)did_set_string_option( - opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, NULL, opt_flags); + opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, + NULL, 0, opt_flags, &value_checked); if (r == NULL) { - did_set_option(opt_idx, opt_flags, true); + did_set_option(opt_idx, opt_flags, true, value_checked); } // call autocommand after handling side effects @@ -2417,23 +2463,21 @@ return true; } -#ifdef _MSC_VER -// MSVC optimizations are disabled for this function because it -// incorrectly generates an empty string for SHM_ALL. -#pragma optimize("", off) -#endif /* * Handle string options that need some action to perform when changed. * Returns NULL for success, or an error message for an error. */ static char_u * -did_set_string_option ( - int opt_idx, /* index in options[] table */ - char_u **varp, /* pointer to the option variable */ - int new_value_alloced, /* new value was allocated */ - char_u *oldval, /* previous value of the option */ - char_u *errbuf, /* buffer for errors, or NULL */ - int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ +did_set_string_option( + int opt_idx, // index in options[] table + char_u **varp, // pointer to the option variable + int new_value_alloced, // new value was allocated + char_u *oldval, // previous value of the option + char_u *errbuf, // buffer for errors, or NULL + size_t errbuflen, // length of errors buffer + int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL + int *value_checked // value was checked to be safe, no + // need to set P_INSECURE ) { char_u *errmsg = NULL; @@ -2651,8 +2695,20 @@ if (!valid_filetype(*varp)) { errmsg = e_invarg; } else { + int secure_save = secure; + + // Reset the secure flag, since the value of 'keymap' has + // been checked to be safe. + secure = 0; + // load or unload key mapping tables errmsg = keymap_init(); + + secure = secure_save; + + // Since we check the value, there is no need to set P_INSECURE, + // even when the value comes from a modeline. + *value_checked = true; } if (errmsg == NULL) { @@ -2738,7 +2794,7 @@ while (*s && *s != ':') { if (vim_strchr((char_u *)COM_ALL, *s) == NULL && !ascii_isdigit(*s) && *s != '-') { - errmsg = illegal_char(errbuf, *s); + errmsg = illegal_char(errbuf, errbuflen, *s); break; } ++s; @@ -2790,7 +2846,7 @@ for (s = p_shada; *s; ) { /* Check it's a valid character */ if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL) { - errmsg = illegal_char(errbuf, *s); + errmsg = illegal_char(errbuf, errbuflen, *s); break; } if (*s == 'n') { /* name is always last one */ @@ -2810,9 +2866,9 @@ if (!ascii_isdigit(*(s - 1))) { if (errbuf != NULL) { - sprintf((char *)errbuf, - _("E526: Missing number after <%s>"), - transchar_byte(*(s - 1))); + vim_snprintf((char *)errbuf, errbuflen, + _("E526: Missing number after <%s>"), + transchar_byte(*(s - 1))); errmsg = errbuf; } else errmsg = (char_u *)""; @@ -2990,7 +3046,7 @@ if (!*s) break; if (vim_strchr((char_u *)".wbuksid]tU", *s) == NULL) { - errmsg = illegal_char(errbuf, *s); + errmsg = illegal_char(errbuf, errbuflen, *s); break; } if (*++s != NUL && *s != ',' && *s != ' ') { @@ -3004,9 +3060,9 @@ } } else { if (errbuf != NULL) { - sprintf((char *)errbuf, - _("E535: Illegal character after <%c>"), - *--s); + vim_snprintf((char *)errbuf, errbuflen, + _("E535: Illegal character after <%c>"), + *--s); errmsg = errbuf; } else errmsg = (char_u *)""; @@ -3163,12 +3219,20 @@ errmsg = e_invarg; } else { value_changed = STRCMP(oldval, *varp) != 0; + + // Since we check the value, there is no need to set P_INSECURE, + // even when the value comes from a modeline. + *value_checked = true; } } else if (gvarp == &p_syn) { if (!valid_filetype(*varp)) { errmsg = e_invarg; } else { value_changed = STRCMP(oldval, *varp) != 0; + + // Since we check the value, there is no need to set P_INSECURE, + // even when the value comes from a modeline. + *value_checked = true; } } else if (varp == &curwin->w_p_winhl) { if (!parse_winhl_opt(curwin)) { @@ -3194,7 +3258,7 @@ if (p != NULL) { for (s = *varp; *s; ++s) if (vim_strchr(p, *s) == NULL) { - errmsg = illegal_char(errbuf, *s); + errmsg = illegal_char(errbuf, errbuflen, *s); break; } } @@ -3258,6 +3322,11 @@ // already set to this value. if (!(opt_flags & OPT_MODELINE) || value_changed) { static int ft_recursive = 0; + int secure_save = secure; + + // Reset the secure flag, since the value of 'filetype' has + // been checked to be safe. + secure = 0; ft_recursive++; did_filetype = true; @@ -3270,6 +3339,7 @@ if (varp != &(curbuf->b_p_ft)) { varp = NULL; } + secure = secure_save; } } if (varp == &(curwin->w_s->b_p_spl)) { @@ -3287,11 +3357,13 @@ * '.encoding'. */ for (p = q; *p != NUL; ++p) - if (vim_strchr((char_u *)"_.,", *p) != NULL) + if (!ASCII_ISALNUM(*p) && *p != '-') break; - vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim", - (int)(p - q), q); - source_runtime(fname, DIP_ALL); + if (p > q) { + vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim", + (int)(p - q), q); + source_runtime(fname, DIP_ALL); + } } } @@ -3311,9 +3383,6 @@ return errmsg; } -#ifdef _MSC_VER -#pragma optimize("", on) -#endif /* * Simple int comparison function for use with qsort() @@ -3553,7 +3622,7 @@ continue; } if (vim_strchr(STL_ALL, *s) == NULL) { - return illegal_char(errbuf, *s); + return illegal_char(errbuf, sizeof(errbuf), *s); } if (*s == '{') { s++; @@ -4892,19 +4961,20 @@ return NULL; } -/* - * Translate a string like "t_xx", "" or "" to a key number. - */ -int find_key_option_len(const char_u *arg, size_t len) +// Translate a string like "t_xx", "" or "" to a key number. +// When "has_lt" is true there is a '<' before "*arg_arg". +// Returns 0 when the key is not recognized. +int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) { - int key; + int key = 0; int modifiers; + const char_u *arg = arg_arg; // Don't use get_special_key_code() for t_xx, we don't want it to call // add_termcap_entry(). if (len >= 4 && arg[0] == 't' && arg[1] == '_') { key = TERMCAP2KEY(arg[2], arg[3]); - } else { + } else if (has_lt) { arg--; // put arg at the '<' modifiers = 0; key = find_special_key(&arg, len + 1, &modifiers, true, true, false); @@ -4915,9 +4985,9 @@ return key; } -static int find_key_option(const char_u *arg) +static int find_key_option(const char_u *arg, bool has_lt) { - return find_key_option_len(arg, STRLEN(arg)); + return find_key_option_len(arg, STRLEN(arg), has_lt); } /* diff -Nru neovim-0.3.4/src/nvim/option_defs.h neovim-0.3.8/src/nvim/option_defs.h --- neovim-0.3.4/src/nvim/option_defs.h 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/option_defs.h 2019-07-03 01:11:42.000000000 +0000 @@ -178,14 +178,6 @@ SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, \ 0, \ }) -/// All possible flags for 'shm'. -#define SHM_ALL ((char_u[]) { \ - SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, \ - SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER, \ - SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, SHM_COMPLETIONMENU, \ - SHM_RECORDING, SHM_FILEINFO, \ - 0, \ -}) /* characters for p_go: */ #define GO_ASEL 'a' /* autoselect */ @@ -503,6 +495,7 @@ EXTERN long p_mmp; // 'maxmempattern' EXTERN long p_mis; // 'menuitems' EXTERN char_u *p_msm; // 'mkspellmem' +EXTERN long p_mle; // 'modelineexpr' EXTERN long p_mls; // 'modelines' EXTERN char_u *p_mouse; // 'mouse' EXTERN char_u *p_mousem; // 'mousemodel' diff -Nru neovim-0.3.4/src/nvim/options.lua neovim-0.3.8/src/nvim/options.lua --- neovim-0.3.4/src/nvim/options.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/options.lua 2019-07-03 01:11:42.000000000 +0000 @@ -8,6 +8,7 @@ -- defaults={condition=nil, if_true={vi=224, vim=0}, if_false=nil}, -- secure=nil, gettext=nil, noglob=nil, normal_fname_chars=nil, -- pri_mkrc=nil, deny_in_modelines=nil, normal_dname_chars=nil, +-- modelineexpr=nil, -- expand=nil, nodefault=nil, no_mkrc=nil, vi_def=true, vim=true, -- alloced=nil, -- save_pv_indir=nil, @@ -286,6 +287,7 @@ deny_duplicates=true, vi_def=true, expand=true, + secure=true, varname='p_cdpath', defaults={if_true={vi=",,"}} }, @@ -856,6 +858,7 @@ type='string', scope={'window'}, vi_def=true, vim=true, + modelineexpr=true, alloced=true, redraw={'current_window'}, defaults={if_true={vi="0"}} @@ -931,6 +934,7 @@ type='string', scope={'window'}, vi_def=true, vim=true, + modelineexpr=true, alloced=true, redraw={'current_window'}, defaults={if_true={vi="foldtext()"}} @@ -940,6 +944,7 @@ type='string', scope={'buffer'}, vi_def=true, vim=true, + modelineexpr=true, alloced=true, varname='p_fex', defaults={if_true={vi=""}} @@ -1053,6 +1058,7 @@ full_name='guitablabel', abbreviation='gtl', type='string', scope={'global'}, vi_def=true, + modelineexpr=true, redraw={'current_window'}, enable_if=false, }, @@ -1143,6 +1149,7 @@ full_name='iconstring', type='string', scope={'global'}, vi_def=true, + modelineexpr=true, varname='p_iconstring', defaults={if_true={vi=""}} }, @@ -1209,6 +1216,7 @@ full_name='includeexpr', abbreviation='inex', type='string', scope={'buffer'}, vi_def=true, + modelineexpr=true, alloced=true, varname='p_inex', defaults={if_true={vi=""}} @@ -1225,6 +1233,7 @@ type='string', scope={'buffer'}, vi_def=true, vim=true, + modelineexpr=true, alloced=true, varname='p_inde', defaults={if_true={vi=""}} @@ -1539,6 +1548,14 @@ defaults={if_true={vi=false, vim=true}} }, { + full_name='modelineexpr', abbreviation='mle', + type='bool', scope={'global'}, + vi_def=true, + secure=true, + varname='p_mle', + defaults={if_true={vi=false}} + }, + { full_name='modelines', abbreviation='mls', type='number', scope={'global'}, vi_def=true, @@ -1898,6 +1915,7 @@ type='string', scope={'global'}, vi_def=true, alloced=true, + modelineexpr=true, redraw={'statuslines'}, varname='p_ruf', defaults={if_true={vi=""}} @@ -2293,6 +2311,7 @@ type='string', scope={'global', 'window'}, vi_def=true, alloced=true, + modelineexpr=true, redraw={'statuslines'}, varname='p_stl', defaults={if_true={vi=""}} @@ -2352,6 +2371,7 @@ full_name='tabline', abbreviation='tal', type='string', scope={'global'}, vi_def=true, + modelineexpr=true, redraw={'all_windows'}, varname='p_tal', defaults={if_true={vi=""}} @@ -2511,6 +2531,7 @@ full_name='titlestring', type='string', scope={'global'}, vi_def=true, + modelineexpr=true, varname='p_titlestring', defaults={if_true={vi=""}} }, diff -Nru neovim-0.3.4/src/nvim/regexp.c neovim-0.3.8/src/nvim/regexp.c --- neovim-0.3.4/src/nvim/regexp.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/regexp.c 2019-07-03 01:11:42.000000000 +0000 @@ -4920,7 +4920,7 @@ } } else { const char_u *const line = - reg_getline(behind_pos.rs_u.pos.lnum); + reg_getline(rp->rs_un.regsave.rs_u.pos.lnum); rp->rs_un.regsave.rs_u.pos.col -= utf_head_off(line, diff -Nru neovim-0.3.4/src/nvim/screen.c neovim-0.3.8/src/nvim/screen.c --- neovim-0.3.4/src/nvim/screen.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/screen.c 2019-07-03 01:11:42.000000000 +0000 @@ -5338,10 +5338,11 @@ schar_from_ascii(ScreenLines[off - 1], ' '); ScreenAttrs[off - 1] = 0; // redraw the previous cell, make it empty - if (put_dirty_first == -1) { + if (put_dirty_first == -1 || col-1 < put_dirty_first) { put_dirty_first = col-1; } put_dirty_last = col+1; + put_dirty_last = MAX(put_dirty_last, col+1); // force the cell at "col" to be redrawn force_redraw_next = true; } @@ -5422,10 +5423,10 @@ ScreenLines[off + 1][0] = 0; ScreenAttrs[off + 1] = attr; } - if (put_dirty_first == -1) { + if (put_dirty_first == -1 || col < put_dirty_first) { put_dirty_first = col; } - put_dirty_last = col+mbyte_cells; + put_dirty_last = MAX(put_dirty_last, col+mbyte_cells); } off += mbyte_cells; diff -Nru neovim-0.3.4/src/nvim/spell.c neovim-0.3.8/src/nvim/spell.c --- neovim-0.3.4/src/nvim/spell.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/spell.c 2019-07-03 01:11:42.000000000 +0000 @@ -2510,7 +2510,7 @@ buf->b_spell = true; buf->b_p_swf = true; // may create a swap file if (ml_open(buf) == FAIL) { - abort(); + ELOG("Error opening a new memline"); } ml_open_file(buf); // create swap file now diff -Nru neovim-0.3.4/src/nvim/terminal.c neovim-0.3.8/src/nvim/terminal.c --- neovim-0.3.4/src/nvim/terminal.c 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/terminal.c 2019-07-03 01:11:42.000000000 +0000 @@ -1304,8 +1304,6 @@ static void adjust_topline(Terminal *term, buf_T *buf, long added) { - int height, width; - vterm_get_size(term->vt, &height, &width); FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer == buf) { linenr_T ml_end = buf->b_ml.ml_line_count; @@ -1314,7 +1312,7 @@ if (following || (wp == curwin && is_focused(term))) { // "Follow" the terminal output wp->w_cursor.lnum = ml_end; - set_topline(wp, MAX(wp->w_cursor.lnum - height + 1, 1)); + set_topline(wp, MAX(wp->w_cursor.lnum - wp->w_height + 1, 1)); } else { // Ensure valid cursor for each window displaying this terminal. wp->w_cursor.lnum = MIN(wp->w_cursor.lnum, ml_end); diff -Nru neovim-0.3.4/src/nvim/testdir/test49.vim neovim-0.3.8/src/nvim/testdir/test49.vim --- neovim-0.3.4/src/nvim/testdir/test49.vim 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/testdir/test49.vim 2019-07-03 01:11:42.000000000 +0000 @@ -1,6 +1,6 @@ " Vim script language tests " Author: Servatius Brandt -" Last Change: 2016 Feb 07 +" Last Change: 2019 May 24 "------------------------------------------------------------------------------- " Test environment {{{1 @@ -9005,5 +9005,4 @@ "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=4 tw=80 fdm=marker -" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "") "------------------------------------------------------------------------------- diff -Nru neovim-0.3.4/src/nvim/testdir/test_alot.vim neovim-0.3.8/src/nvim/testdir/test_alot.vim --- neovim-0.3.4/src/nvim/testdir/test_alot.vim 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/testdir/test_alot.vim 2019-07-03 01:11:42.000000000 +0000 @@ -28,6 +28,7 @@ source test_mapping.vim source test_menu.vim source test_messages.vim +source test_modeline.vim source test_move.vim source test_partial.vim source test_popup.vim diff -Nru neovim-0.3.4/src/nvim/testdir/test_autocmd.vim neovim-0.3.8/src/nvim/testdir/test_autocmd.vim --- neovim-0.3.4/src/nvim/testdir/test_autocmd.vim 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/testdir/test_autocmd.vim 2019-07-03 01:11:42.000000000 +0000 @@ -652,6 +652,29 @@ "delfunc! AutoCommandOptionSet endfunc +func Test_OptionSet_modeline() + throw 'skipped: Nvim does not support test_override()' + call test_override('starting', 1) + au! OptionSet + augroup set_tabstop + au OptionSet tabstop call timer_start(1, {-> execute("echo 'Handler called'", "")}) + augroup END + call writefile(['vim: set ts=7 sw=5 :', 'something'], 'XoptionsetModeline') + set modeline + let v:errmsg = '' + call assert_fails('split XoptionsetModeline', 'E12:') + call assert_equal(7, &ts) + call assert_equal('', v:errmsg) + + augroup set_tabstop + au! + augroup END + bwipe! + set ts& + call delete('XoptionsetModeline') + call test_override('starting', 0) +endfunc + " Test for Bufleave autocommand that deletes the buffer we are about to edit. func Test_BufleaveWithDelete() new | edit Xfile1 diff -Nru neovim-0.3.4/src/nvim/testdir/test_functions.vim neovim-0.3.8/src/nvim/testdir/test_functions.vim --- neovim-0.3.4/src/nvim/testdir/test_functions.vim 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/testdir/test_functions.vim 2019-07-03 01:11:42.000000000 +0000 @@ -1037,3 +1037,19 @@ call delete('Xfuncrange2') bwipe! endfunc + +sandbox function Fsandbox() + normal ix +endfunc + +func Test_func_sandbox() + sandbox let F = {-> 'hello'} + call assert_equal('hello', F()) + + sandbox let F = {-> execute("normal ix\")} + call assert_fails('call F()', 'E48:') + unlet F + + call assert_fails('call Fsandbox()', 'E48:') + delfunc Fsandbox +endfunc diff -Nru neovim-0.3.4/src/nvim/testdir/test_glob2regpat.vim neovim-0.3.8/src/nvim/testdir/test_glob2regpat.vim --- neovim-0.3.4/src/nvim/testdir/test_glob2regpat.vim 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/testdir/test_glob2regpat.vim 2019-07-03 01:11:42.000000000 +0000 @@ -1,12 +1,12 @@ " Test glob2regpat() -func Test_invalid() +func Test_glob2regpat_invalid() call assert_fails('call glob2regpat(1.33)', 'E806:') call assert_fails('call glob2regpat("}")', 'E219:') call assert_fails('call glob2regpat("{")', 'E220:') endfunc -func Test_valid() +func Test_glob2regpat_valid() call assert_equal('^foo\.', glob2regpat('foo.*')) call assert_equal('^foo.$', glob2regpat('foo?')) call assert_equal('\.vim$', glob2regpat('*.vim')) diff -Nru neovim-0.3.4/src/nvim/testdir/test_modeline.vim neovim-0.3.8/src/nvim/testdir/test_modeline.vim --- neovim-0.3.4/src/nvim/testdir/test_modeline.vim 1970-01-01 00:00:00.000000000 +0000 +++ neovim-0.3.8/src/nvim/testdir/test_modeline.vim 2019-07-03 01:11:42.000000000 +0000 @@ -0,0 +1,173 @@ +" Tests for parsing the modeline. + +func Test_modeline_invalid() + " This was reading allocated memory in the past. + call writefile(['vi:0', 'nothing'], 'Xmodeline') + let modeline = &modeline + set modeline + call assert_fails('set Xmodeline', 'E518:') + + let &modeline = modeline + bwipe! + call delete('Xmodeline') + endfunc + +func Test_modeline_filetype() + call writefile(['vim: set ft=c :', 'nothing'], 'Xmodeline_filetype') + let modeline = &modeline + set modeline + filetype plugin on + split Xmodeline_filetype + call assert_equal("c", &filetype) + call assert_equal(1, b:did_ftplugin) + call assert_equal("ccomplete#Complete", &ofu) + + bwipe! + call delete('Xmodeline_filetype') + let &modeline = modeline + filetype plugin off +endfunc + +func Test_modeline_syntax() + call writefile(['vim: set syn=c :', 'nothing'], 'Xmodeline_syntax') + let modeline = &modeline + set modeline + syntax enable + split Xmodeline_syntax + call assert_equal("c", &syntax) + call assert_equal("c", b:current_syntax) + + bwipe! + call delete('Xmodeline_syntax') + let &modeline = modeline + syntax off +endfunc + +func Test_modeline_keymap() + if !has('keymap') + return + endif + call writefile(['vim: set keymap=greek :', 'nothing'], 'Xmodeline_keymap') + let modeline = &modeline + set modeline + split Xmodeline_keymap + call assert_equal("greek", &keymap) + call assert_match('greek\|grk', b:keymap_name) + + bwipe! + call delete('Xmodeline_keymap') + let &modeline = modeline + set keymap= iminsert=0 imsearch=-1 +endfunc + +func s:modeline_fails(what, text, error) + if !exists('+' . a:what) + return + endif + let fname = "Xmodeline_fails_" . a:what + call writefile(['vim: set ' . a:text . ' :', 'nothing'], fname) + let modeline = &modeline + set modeline + filetype plugin on + syntax enable + call assert_fails('split ' . fname, a:error) + call assert_equal("", &filetype) + call assert_equal("", &syntax) + + bwipe! + call delete(fname) + let &modeline = modeline + filetype plugin off + syntax off +endfunc + +func Test_modeline_filetype_fails() + call s:modeline_fails('filetype', 'ft=evil$CMD', 'E474:') +endfunc + +func Test_modeline_syntax_fails() + call s:modeline_fails('syntax', 'syn=evil$CMD', 'E474:') +endfunc + +func Test_modeline_keymap_fails() + call s:modeline_fails('keymap', 'keymap=evil$CMD', 'E474:') +endfunc + +func Test_modeline_fails_always() + call s:modeline_fails('backupdir', 'backupdir=Something()', 'E520:') + call s:modeline_fails('cdpath', 'cdpath=Something()', 'E520:') + call s:modeline_fails('charconvert', 'charconvert=Something()', 'E520:') + call s:modeline_fails('completefunc', 'completefunc=Something()', 'E520:') + call s:modeline_fails('cscopeprg', 'cscopeprg=Something()', 'E520:') + call s:modeline_fails('diffexpr', 'diffexpr=Something()', 'E520:') + call s:modeline_fails('directory', 'directory=Something()', 'E520:') + call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') + call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') + call s:modeline_fails('exrc', 'exrc=Something()', 'E520:') + call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:') + call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') + call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') + call s:modeline_fails('helpfile', 'helpfile=Something()', 'E520:') + call s:modeline_fails('imactivatefunc', 'imactivatefunc=Something()', 'E520:') + call s:modeline_fails('imstatusfunc', 'imstatusfunc=Something()', 'E520:') + call s:modeline_fails('imstyle', 'imstyle=Something()', 'E520:') + call s:modeline_fails('keywordprg', 'keywordprg=Something()', 'E520:') + call s:modeline_fails('langmap', 'langmap=Something()', 'E520:') + call s:modeline_fails('luadll', 'luadll=Something()', 'E520:') + call s:modeline_fails('makeef', 'makeef=Something()', 'E520:') + call s:modeline_fails('makeprg', 'makeprg=Something()', 'E520:') + call s:modeline_fails('mkspellmem', 'mkspellmem=Something()', 'E520:') + call s:modeline_fails('mzschemedll', 'mzschemedll=Something()', 'E520:') + call s:modeline_fails('mzschemegcdll', 'mzschemegcdll=Something()', 'E520:') + call s:modeline_fails('modelineexpr', 'modelineexpr=Something()', 'E520:') + call s:modeline_fails('omnifunc', 'omnifunc=Something()', 'E520:') + call s:modeline_fails('operatorfunc', 'operatorfunc=Something()', 'E520:') + call s:modeline_fails('perldll', 'perldll=Something()', 'E520:') + call s:modeline_fails('printdevice', 'printdevice=Something()', 'E520:') + call s:modeline_fails('patchexpr', 'patchexpr=Something()', 'E520:') + call s:modeline_fails('printexpr', 'printexpr=Something()', 'E520:') + call s:modeline_fails('pythondll', 'pythondll=Something()', 'E520:') + call s:modeline_fails('pythonhome', 'pythonhome=Something()', 'E520:') + call s:modeline_fails('pythonthreedll', 'pythonthreedll=Something()', 'E520:') + call s:modeline_fails('pythonthreehome', 'pythonthreehome=Something()', 'E520:') + call s:modeline_fails('pyxversion', 'pyxversion=Something()', 'E520:') + call s:modeline_fails('rubydll', 'rubydll=Something()', 'E520:') + call s:modeline_fails('runtimepath', 'runtimepath=Something()', 'E520:') + call s:modeline_fails('secure', 'secure=Something()', 'E520:') + call s:modeline_fails('shell', 'shell=Something()', 'E520:') + call s:modeline_fails('shellcmdflag', 'shellcmdflag=Something()', 'E520:') + call s:modeline_fails('shellpipe', 'shellpipe=Something()', 'E520:') + call s:modeline_fails('shellquote', 'shellquote=Something()', 'E520:') + call s:modeline_fails('shellredir', 'shellredir=Something()', 'E520:') + call s:modeline_fails('shellxquote', 'shellxquote=Something()', 'E520:') + call s:modeline_fails('spellfile', 'spellfile=Something()', 'E520:') + call s:modeline_fails('spellsuggest', 'spellsuggest=Something()', 'E520:') + call s:modeline_fails('tcldll', 'tcldll=Something()', 'E520:') + call s:modeline_fails('titleold', 'titleold=Something()', 'E520:') + call s:modeline_fails('viewdir', 'viewdir=Something()', 'E520:') + call s:modeline_fails('viminfo', 'viminfo=Something()', 'E520:') + call s:modeline_fails('viminfofile', 'viminfofile=Something()', 'E520:') + call s:modeline_fails('winptydll', 'winptydll=Something()', 'E520:') + call s:modeline_fails('undodir', 'undodir=Something()', 'E520:') + " only check a few terminal options + " Skip these since nvim doesn't support termcodes as options + "call s:modeline_fails('t_AB', 't_AB=Something()', 'E520:') + "call s:modeline_fails('t_ce', 't_ce=Something()', 'E520:') + "call s:modeline_fails('t_sr', 't_sr=Something()', 'E520:') + "call s:modeline_fails('t_8b', 't_8b=Something()', 'E520:') +endfunc + +func Test_modeline_fails_modelineexpr() + call s:modeline_fails('balloonexpr', 'balloonexpr=Something()', 'E992:') + call s:modeline_fails('foldexpr', 'foldexpr=Something()', 'E992:') + call s:modeline_fails('foldtext', 'foldtext=Something()', 'E992:') + call s:modeline_fails('formatexpr', 'formatexpr=Something()', 'E992:') + call s:modeline_fails('guitablabel', 'guitablabel=Something()', 'E992:') + call s:modeline_fails('iconstring', 'iconstring=Something()', 'E992:') + call s:modeline_fails('includeexpr', 'includeexpr=Something()', 'E992:') + call s:modeline_fails('indentexpr', 'indentexpr=Something()', 'E992:') + call s:modeline_fails('rulerformat', 'rulerformat=Something()', 'E992:') + call s:modeline_fails('statusline', 'statusline=Something()', 'E992:') + call s:modeline_fails('tabline', 'tabline=Something()', 'E992:') + call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:') +endfunc diff -Nru neovim-0.3.4/src/nvim/testdir/test_vimscript.vim neovim-0.3.8/src/nvim/testdir/test_vimscript.vim --- neovim-0.3.4/src/nvim/testdir/test_vimscript.vim 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/src/nvim/testdir/test_vimscript.vim 2019-07-03 01:11:42.000000000 +0000 @@ -1297,5 +1297,4 @@ "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=4 tw=80 fdm=marker -" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "") "------------------------------------------------------------------------------- diff -Nru neovim-0.3.4/test/functional/eval/api_functions_spec.lua neovim-0.3.8/test/functional/eval/api_functions_spec.lua --- neovim-0.3.4/test/functional/eval/api_functions_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/eval/api_functions_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -4,7 +4,8 @@ local neq, eq, command = helpers.neq, helpers.eq, helpers.command local clear, curbufmeths = helpers.clear, helpers.curbufmeths local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval -local insert = helpers.insert +local insert, meth_pcall = helpers.insert, helpers.meth_pcall +local meths = helpers.meths describe('api functions', function() before_each(clear) @@ -145,4 +146,10 @@ ]]) screen:detach() end) + + it('cannot be called from sandbox', function() + eq({false, 'Vim(call):E48: Not allowed in sandbox'}, + meth_pcall(command, "sandbox call nvim_input('ievil')")) + eq({''}, meths.buf_get_lines(0, 0, -1, true)) + end) end) diff -Nru neovim-0.3.4/test/functional/ex_cmds/cd_spec.lua neovim-0.3.8/test/functional/ex_cmds/cd_spec.lua --- neovim-0.3.4/test/functional/ex_cmds/cd_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/ex_cmds/cd_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -286,6 +286,15 @@ command("call delete('../"..directories.global.."', 'd')") eq("", helpers.eval("getcwd()")) end) + + it("works with 'autochdir' after local directory was set (#9892)", function() + local curdir = cwd() + command('lcd ' .. directories.global) + command('lcd -') + command('set autochdir') + command('edit ' .. directories.global .. '/foo') + eq(curdir .. pathsep .. directories.global, cwd()) + end) end) diff -Nru neovim-0.3.4/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua neovim-0.3.8/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua --- neovim-0.3.4/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -1,10 +1,11 @@ local Screen = require('test.functional.ui.screen') local helpers = require('test.functional.helpers')(after_each) local lfs = require('lfs') -local feed_command, eq, eval, expect, source = - helpers.feed_command, helpers.eq, helpers.eval, helpers.expect, helpers.source +local eq, eval, expect, source = + helpers.eq, helpers.eval, helpers.expect, helpers.source local clear = helpers.clear local command = helpers.command +local expect_err = helpers.expect_err local feed = helpers.feed local nvim_prog = helpers.nvim_prog local ok = helpers.ok @@ -17,9 +18,14 @@ before_each(clear) it('fails if given a non-existent swapfile', function() - local swapname = 'bogus-swapfile' - feed_command('recover '..swapname) -- This should not segfault. #2117 - eq('E305: No swap file found for '..swapname, eval('v:errmsg')) + local swapname = 'bogus_swapfile' + local swapname2 = 'bogus_swapfile.swp' + expect_err('E305: No swap file found for '..swapname, + command, 'recover '..swapname) -- Should not segfault. #2117 + -- Also check filename ending with ".swp". #9504 + expect_err('Vim%(recover%):E306: Cannot open '..swapname2, + command, 'recover '..swapname2) -- Should not segfault. #2117 + eq(2, eval('1+1')) -- Still alive? end) end) diff -Nru neovim-0.3.4/test/functional/terminal/altscreen_spec.lua neovim-0.3.8/test/functional/terminal/altscreen_spec.lua --- neovim-0.3.4/test/functional/terminal/altscreen_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/altscreen_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -8,7 +8,7 @@ if helpers.pending_win32(pending) then return end -describe('terminal altscreen', function() +describe(':terminal altscreen', function() local screen before_each(function() diff -Nru neovim-0.3.4/test/functional/terminal/buffer_spec.lua neovim-0.3.8/test/functional/terminal/buffer_spec.lua --- neovim-0.3.4/test/functional/terminal/buffer_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/buffer_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -6,7 +6,7 @@ local eq, neq = helpers.eq, helpers.neq local write_file = helpers.write_file -describe('terminal buffer', function() +describe(':terminal buffer', function() local screen before_each(function() diff -Nru neovim-0.3.4/test/functional/terminal/cursor_spec.lua neovim-0.3.8/test/functional/terminal/cursor_spec.lua --- neovim-0.3.4/test/functional/terminal/cursor_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/cursor_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -7,7 +7,7 @@ local hide_cursor = thelpers.hide_cursor local show_cursor = thelpers.show_cursor -describe('terminal cursor', function() +describe(':terminal cursor', function() local screen before_each(function() diff -Nru neovim-0.3.4/test/functional/terminal/highlight_spec.lua neovim-0.3.8/test/functional/terminal/highlight_spec.lua --- neovim-0.3.4/test/functional/terminal/highlight_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/highlight_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -5,7 +5,7 @@ local nvim_dir, command = helpers.nvim_dir, helpers.command local eq, eval = helpers.eq, helpers.eval -describe('terminal window highlighting', function() +describe(':terminal window highlighting', function() local screen before_each(function() diff -Nru neovim-0.3.4/test/functional/terminal/mouse_spec.lua neovim-0.3.8/test/functional/terminal/mouse_spec.lua --- neovim-0.3.4/test/functional/terminal/mouse_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/mouse_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -4,7 +4,7 @@ local feed, nvim = helpers.feed, helpers.nvim local feed_data = thelpers.feed_data -describe('terminal mouse', function() +describe(':terminal mouse', function() local screen before_each(function() diff -Nru neovim-0.3.4/test/functional/terminal/scrollback_spec.lua neovim-0.3.8/test/functional/terminal/scrollback_spec.lua --- neovim-0.3.4/test/functional/terminal/scrollback_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/scrollback_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -12,7 +12,7 @@ local nvim = helpers.nvim local feed_data = thelpers.feed_data -describe('terminal scrollback', function() +describe(':terminal scrollback', function() local screen before_each(function() @@ -344,7 +344,7 @@ end) end) -describe('terminal prints more lines than the screen height and exits', function() +describe(':terminal prints more lines than the screen height and exits', function() it('will push extra lines to scrollback', function() clear() local screen = Screen.new(30, 7) @@ -460,7 +460,7 @@ screen:detach() end) - it('defaults to 10000 in terminal buffers', function() + it('defaults to 10000 in :terminal buffers', function() set_fake_shell() command('terminal') eq(10000, curbufmeths.get_option('scrollback')) diff -Nru neovim-0.3.4/test/functional/terminal/tui_spec.lua neovim-0.3.8/test/functional/terminal/tui_spec.lua --- neovim-0.3.4/test/functional/terminal/tui_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/tui_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -20,7 +20,7 @@ if helpers.pending_win32(pending) then return end -describe('tui', function() +describe('TUI', function() local screen before_each(function() diff -Nru neovim-0.3.4/test/functional/terminal/window_spec.lua neovim-0.3.8/test/functional/terminal/window_spec.lua --- neovim-0.3.4/test/functional/terminal/window_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/window_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -3,8 +3,12 @@ local feed, clear = helpers.feed, helpers.clear local wait = helpers.wait local iswin = helpers.iswin +local command = helpers.command +local retry = helpers.retry +local eq = helpers.eq +local eval = helpers.eval -describe('terminal window', function() +describe(':terminal window', function() local screen before_each(function() @@ -12,6 +16,19 @@ screen = thelpers.screen_setup() end) + it('sets topline correctly #8556', function() + -- Test has hardcoded assumptions of dimensions. + eq(7, eval('&lines')) + command('set shell=sh') + command('terminal') + retry(nil, nil, function() assert(nil ~= eval('b:terminal_job_pid')) end) + -- Terminal/shell contents must exceed the height of this window. + command('topleft 1split') + feed([[i]]) + -- Check topline _while_ in terminal-mode. + retry(nil, nil, function() eq(6, eval('winsaveview()["topline"]')) end) + end) + describe("with 'number'", function() it('wraps text', function() feed([[]]) diff -Nru neovim-0.3.4/test/functional/terminal/window_split_tab_spec.lua neovim-0.3.8/test/functional/terminal/window_split_tab_spec.lua --- neovim-0.3.4/test/functional/terminal/window_split_tab_spec.lua 2019-01-13 13:25:08.000000000 +0000 +++ neovim-0.3.8/test/functional/terminal/window_split_tab_spec.lua 2019-07-03 01:11:42.000000000 +0000 @@ -9,7 +9,7 @@ local iswin = helpers.iswin local retry = helpers.retry -describe('terminal', function() +describe(':terminal', function() local screen before_each(function()