aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--Makefile4
-rw-r--r--contrib/local.mk.example2
-rw-r--r--runtime/autoload/health.vim3
-rw-r--r--runtime/autoload/health/nvim.vim51
-rw-r--r--runtime/autoload/remote/host.vim2
-rw-r--r--runtime/doc/deprecated.txt4
-rw-r--r--runtime/doc/eval.txt32
-rw-r--r--runtime/doc/insert.txt2
-rw-r--r--runtime/doc/vim_diff.txt18
-rw-r--r--runtime/ftplugin/man.vim2
-rw-r--r--runtime/syntax/vim.vim8
-rw-r--r--scripts/gendispatch.lua102
-rw-r--r--src/nvim/CMakeLists.txt10
-rw-r--r--src/nvim/api/private/dispatch.c45
-rw-r--r--src/nvim/api/private/dispatch.h1
-rw-r--r--src/nvim/api/private/helpers.c21
-rw-r--r--src/nvim/api/tabpage.c17
-rw-r--r--src/nvim/api/window.c20
-rw-r--r--src/nvim/edit.c3
-rw-r--r--src/nvim/eval.c33
-rw-r--r--src/nvim/event/rstream.c4
-rw-r--r--src/nvim/ex_eval.h22
-rw-r--r--src/nvim/ex_getln.c1
-rw-r--r--src/nvim/fold.c13
-rw-r--r--src/nvim/if_cscope.c43
-rw-r--r--src/nvim/normal.c3
-rw-r--r--src/nvim/option.c9
-rw-r--r--src/nvim/os/shell.c10
-rw-r--r--src/nvim/testdir/Makefile1
-rw-r--r--src/nvim/testdir/test_history.vim65
-rw-r--r--src/nvim/version.c17
-rw-r--r--src/nvim/window.c51
-rw-r--r--test/functional/api/tabpage_spec.lua16
-rw-r--r--test/functional/api/window_spec.lua24
-rw-r--r--test/functional/eval/execute_spec.lua12
-rw-r--r--test/functional/eval/system_spec.lua (renamed from test/functional/shell/viml_system_spec.lua)14
-rw-r--r--test/functional/eval/timer_spec.lua68
-rw-r--r--test/functional/ex_cmds/bang_filter_spec.lua (renamed from test/functional/shell/bang_filter_spec.lua)0
-rw-r--r--test/functional/ex_cmds/dict_notifications_spec.lua (renamed from test/functional/dict_notifications_spec.lua)0
-rw-r--r--test/functional/terminal/api_spec.lua12
41 files changed, 553 insertions, 216 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93e153be53..4aa6a2de32 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -256,6 +256,10 @@ option(
if(TRAVIS_CI_BUILD)
message(STATUS "Travis CI build enabled.")
add_definitions(-Werror)
+ if(DEFINED ENV{BUILD_32BIT})
+ # Get some test coverage for unsigned char
+ add_definitions(-funsigned-char)
+ endif()
endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
diff --git a/Makefile b/Makefile
index ef4b9cdcb5..8fdf007260 100644
--- a/Makefile
+++ b/Makefile
@@ -13,10 +13,6 @@ CLINT_ERRORS_FILE_PATH := /reports/clint/errors.json
BUILD_TYPE ?= $(shell (type ninja > /dev/null 2>&1 && echo "Ninja") || \
echo "Unix Makefiles")
-ifneq (,$(PREFIX))
- CMAKE_FLAGS += -DCMAKE_INSTALL_PREFIX:PATH="$(PREFIX)"
-endif
-
ifeq (,$(BUILD_TOOL))
ifeq (Ninja,$(BUILD_TYPE))
ifneq ($(shell cmake --help 2>/dev/null | grep Ninja),)
diff --git a/contrib/local.mk.example b/contrib/local.mk.example
index 6959107ea2..a0b2d034e1 100644
--- a/contrib/local.mk.example
+++ b/contrib/local.mk.example
@@ -2,7 +2,7 @@
# Individual entries must be uncommented to take effect.
# By default, the installation prefix is '/usr/local'.
-# PREFIX := /usr/local/nvim-latest
+# CMAKE_EXTRA_FLAGS += -DCMAKE_INSTALL_PREFIX=/usr/local/nvim-latest
# These CFLAGS can be used in addition to those specified in CMakeLists.txt:
# CMAKE_EXTRA_FLAGS="-DCMAKE_C_FLAGS=-ftrapv -Wlogical-op"
diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim
index 783c30cbf6..336adc65e5 100644
--- a/runtime/autoload/health.vim
+++ b/runtime/autoload/health.vim
@@ -13,6 +13,9 @@ function! s:enhance_syntax() abort
syntax keyword healthSuggestion SUGGESTIONS
highlight link healthSuggestion String
+
+ " We do not care about markdown syntax errors in :CheckHealth output.
+ highlight! link markdownError Normal
endfunction
" Runs the specified healthchecks.
diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim
index d769525373..60e56034e1 100644
--- a/runtime/autoload/health/nvim.vim
+++ b/runtime/autoload/health/nvim.vim
@@ -57,6 +57,57 @@ function! s:check_manifest() abort
endif
endfunction
+function! s:check_tmux() abort
+ if empty($TMUX) || !executable('tmux')
+ return
+ endif
+ call health#report_start('tmux configuration')
+ let suggestions = ["Set escape-time in ~/.tmux.conf: set-option -sg escape-time 10",
+ \ 'See https://github.com/neovim/neovim/wiki/FAQ']
+ let cmd = 'tmux show-option -qvgs escape-time'
+ let out = system(cmd)
+ let tmux_esc_time = substitute(out, '\v(\s|\r|\n)', '', 'g')
+
+ if v:shell_error
+ call health#report_error('command failed: '.cmd."\n".out)
+ elseif empty(tmux_esc_time)
+ call health#report_error('escape-time is not set', suggestions)
+ elseif tmux_esc_time > 500
+ call health#report_error(
+ \ 'escape-time ('.tmux_esc_time.') is higher than 300ms', suggestions)
+ else
+ call health#report_ok('escape-time = '.tmux_esc_time.'ms')
+ endif
+endfunction
+
+function! s:check_terminfo() abort
+ if !executable('infocmp')
+ return
+ endif
+ call health#report_start('terminfo')
+ let suggestions = [
+ \ "Set key_backspace to \\177 (ASCII BACKSPACE). Run these commands:\n"
+ \ .'infocmp $TERM | sed ''s/kbs=^[hH]/kbs=\\177/'' > $TERM.ti'
+ \ ."\n"
+ \ .'tic $TERM.ti',
+ \ 'See https://github.com/neovim/neovim/wiki/FAQ']
+ let cmd = 'infocmp -L'
+ let out = system(cmd)
+ let kbs_entry = matchstr(out, 'key_backspace=\S*')
+
+ if v:shell_error
+ call health#report_error('command failed: '.cmd."\n".out)
+ elseif !empty(matchstr(out, '\Vkey_backspace=^H'))
+ call health#report_error('key_backspace (kbs) entry is ^H (ASCII DELETE): '
+ \ .kbs_entry, suggestions)
+ else
+ call health#report_info('key_backspace terminfo entry: '
+ \ .(empty(kbs_entry) ? '? (not found)' : kbs_entry))
+ endif
+endfunction
+
function! health#nvim#check() abort
call s:check_manifest()
+ call s:check_tmux()
+ call s:check_terminfo()
endfunction
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index 1f30b91ab8..51f7e5886f 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -190,7 +190,7 @@ function! s:RegistrationCommands(host) abort
call remote#host#RegisterClone(host_id, a:host)
let pattern = s:plugin_patterns[a:host]
let paths = globpath(&rtp, 'rplugin/'.a:host.'/'.pattern, 0, 1)
- let paths = map(paths, 'tr(v:val,"\\","/")') " Normalize slashes #4795
+ let paths = map(paths, 'tr(resolve(v:val),"\\","/")') " Normalize slashes #4795
let paths = uniq(sort(paths))
if empty(paths)
return []
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index 2b69929cfe..6997d331e4 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -6,6 +6,10 @@
Nvim *deprecated*
+The items listed below are "deprecated". This means they will be removed in
+the future. They should not be used in new scripts, and old scripts should be
+updated.
+
==============================================================================
Normal commands ~
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index dedbe49605..3c9b4dafcd 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -6838,23 +6838,30 @@ system({cmd} [, {input}]) *system()* *E677*
Get the output of the shell command {cmd} as a |string|. {cmd}
will be run the same as in |jobstart()|. See |systemlist()|
to get the output as a |List|.
-
- When {input} is given and is a string this string is written
- to a file and passed as stdin to the command. The string is
- written as-is, you need to take care of using the correct line
- separators yourself.
- If {input} is given and is a |List| it is written to the file
- in a way |writefile()| does with {binary} set to "b" (i.e.
- with a newline between each list item with newlines inside
- list items converted to NULs).
- Pipes are not used.
+ Not to be used for interactive commands.
+
+ If {input} is a string it is written to a pipe and passed as
+ stdin to the command. The string is written as-is, line
+ separators are not changed.
+ If {input} is a |List| it is written to the pipe as
+ |writefile()| does with {binary} set to "b" (i.e. with
+ a newline between each list item, and newlines inside list
+ items converted to NULs).
+ *E5677*
+ Note: system() cannot write to or read from backgrounded ("&")
+ shell commands, e.g.: >
+ :echo system("cat - &", "foo"))
+< which is equivalent to: >
+ $ echo foo | bash -c 'cat - &'
+< The pipes are disconnected (unless overridden by shell
+ redirection syntax) before input can reach it. Use
+ |jobstart()| instead.
Note: Use |shellescape()| or |::S| with |expand()| or
|fnamemodify()| to escape special characters in a command
argument. Newlines in {cmd} may cause the command to fail.
The characters in 'shellquote' and 'shellxquote' may also
cause trouble.
- This is not to be used for interactive commands.
The result is a String. Example: >
:let files = system("ls " . shellescape(expand('%:h')))
@@ -6869,9 +6876,6 @@ system({cmd} [, {input}]) *system()* *E677*
The command executed is constructed using several options when
{cmd} is a string: 'shell' 'shellcmdflag' {cmd}
- The command will be executed in "cooked" mode, so that a
- CTRL-C will interrupt the command (on Unix at least).
-
The resulting error code can be found in |v:shell_error|.
This function will fail in |restricted-mode|.
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index 818d6cf64c..a82e17c857 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -1436,7 +1436,7 @@ original HTML files completion of tags (and only tags) isn't context aware.
RUBY *ft-ruby-omni* {Nvim}
-NOTE: Completion for ruby code is not currently provided by Nvim.
+NOTE: |compl-omni| for Ruby code requires |provider-ruby| to be installed.
Ruby completion will parse your buffer on demand in order to provide a list of
completions. These completions will be drawn from modules loaded by 'require'
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 249208911b..bb1f993ab6 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -76,6 +76,15 @@ Python plugins |provider-python|
Clipboard integration |provider-clipboard|
+USER EXPERIENCE ~
+
+A major goal of Nvim is to work intuitively and consistently. For example,
+Nvim does not have `-X`, a platform-specific option available in some Vim
+builds (with potential surprises: http://stackoverflow.com/q/14635295). Nvim
+avoids features that cannot be provided on all platforms--instead that is
+delegated to external plugins/extensions.
+
+
OTHER FEATURES ~
|bracketed-paste-mode| is built-in and enabled by default.
@@ -99,6 +108,7 @@ Options:
Commands:
|:CheckHealth|
+ |:drop| is available on all platforms
|:Man| is available by default, with many improvements such as completion
Functions:
@@ -131,10 +141,10 @@ are always available and may be used simultaneously in separate plugins. The
`neovim` pip package must be installed to use Python plugins in Nvim (see
|provider-python|).
-|:!| and |system()| do not support "interactive" commands; use |:terminal| for
-that instead. Terminal Vim supports interactive |:!| and |system()|, but gui
-Vim does not. See ":help gui-pty" in Vim:
- http://vimdoc.sourceforge.net/htmldoc/gui_x11.html#gui-pty
+|:!| does not support "interactive" commands. Use |:terminal| instead.
+(GUI Vim has a similar limitation, see ":help gui-pty" in Vim.)
+
+|system()| does not support writing/reading "backgrounded" commands. |E5677|
|mkdir()| behaviour changed:
1. Assuming /tmp/foo does not exist and /tmp can be written to
diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim
index 02d2b4e557..f6fefd0155 100644
--- a/runtime/ftplugin/man.vim
+++ b/runtime/ftplugin/man.vim
@@ -21,7 +21,7 @@ if has('vim_starting')
" all caps it is impossible to tell what the original capitilization was.
let ref = tolower(matchstr(getline(1), '^\S\+'))
let b:man_sect = man#extract_sect_and_name_ref(ref)[0]
- execute 'file man://'.ref
+ execute 'silent file man://'.ref
endif
setlocal buftype=nofile
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index d056e5b7bf..34fdae0ffc 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -5,6 +5,14 @@
" Version: 7.4-45
" Automatically generated keyword lists: {{{1
+" #############################################################################
+" #############################################################################
+" Note: Be careful when merging the upstream version of this file.
+" Much of this is generated by scripts/genvimvim.lua (result is installed
+" to: $VIMRUNTIME/syntax/vim/generated.vim)
+" #############################################################################
+" #############################################################################
+
" Quit when a syntax file was already loaded {{{2
if exists("b:current_syntax")
finish
diff --git a/scripts/gendispatch.lua b/scripts/gendispatch.lua
index 00ed84212b..4f00783825 100644
--- a/scripts/gendispatch.lua
+++ b/scripts/gendispatch.lua
@@ -52,16 +52,18 @@ package.path = nvimsrcdir .. '/?.lua;' .. package.path
-- names of all headers relative to the source root (for inclusion in the
-- generated file)
headers = {}
--- output c file(dispatch function + metadata serialized with msgpack)
-outputf = arg[#arg-1]
--- output mpack file (metadata)
+-- output h file with generated dispatch functions
+dispatch_outputf = arg[#arg-2]
+-- output h file with packed metadata
+funcs_metadata_outputf = arg[#arg-1]
+-- output metadata mpack file, for use by other build scripts
mpack_outputf = arg[#arg]
-- set of function names, used to detect duplicates
function_names = {}
-- read each input file, parse and append to the api metadata
-for i = 2, #arg - 2 do
+for i = 2, #arg - 3 do
local full_path = arg[i]
local parts = {}
for part in string.gmatch(full_path, '[^/]+') do
@@ -165,66 +167,27 @@ for _,f in ipairs(functions) do
end
--- start building the output
-output = io.open(outputf, 'wb')
-
-output:write([[
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <assert.h>
-#include <msgpack.h>
-
-#include "nvim/map.h"
-#include "nvim/log.h"
-#include "nvim/vim.h"
-#include "nvim/msgpack_rpc/helpers.h"
-#include "nvim/api/private/dispatch.h"
-#include "nvim/api/private/helpers.h"
-#include "nvim/api/private/defs.h"
+funcs_metadata_output = io.open(funcs_metadata_outputf, 'wb')
+funcs_metadata_output:write([[
+static const uint8_t funcs_metadata[] = {
]])
-for i = 1, #headers do
- if headers[i]:sub(-12) ~= '.generated.h' then
- output:write('\n#include "nvim/'..headers[i]..'"')
- end
-end
-
-output:write([[
-
-
-static const uint8_t msgpack_metadata[] = {
-
-]])
-- serialize the API metadata using msgpack and embed into the resulting
-- binary for easy querying by clients
packed_exported_functions = mpack.pack(exported_functions)
for i = 1, #packed_exported_functions do
- output:write(string.byte(packed_exported_functions, i)..', ')
+ funcs_metadata_output:write(string.byte(packed_exported_functions, i)..', ')
if i % 10 == 0 then
- output:write('\n ')
+ funcs_metadata_output:write('\n ')
end
end
-output:write([[
+funcs_metadata_output:write([[
};
-
-void msgpack_rpc_init_function_metadata(Dictionary *metadata)
-{
- msgpack_unpacked unpacked;
- msgpack_unpacked_init(&unpacked);
- if (msgpack_unpack_next(&unpacked,
- (const char *)msgpack_metadata,
- sizeof(msgpack_metadata),
- NULL) != MSGPACK_UNPACK_SUCCESS) {
- abort();
- }
- Object functions;
- msgpack_rpc_to_object(&unpacked.data, &functions);
- msgpack_unpacked_destroy(&unpacked);
- PUT(*metadata, "functions", functions);
-}
-
]])
+funcs_metadata_output:close()
+
+-- start building the dispatch wrapper output
+output = io.open(dispatch_outputf, 'wb')
local function real_type(type)
local rv = type
@@ -336,22 +299,12 @@ end
-- Generate a function that initializes method names with handler functions
output:write([[
-static Map(String, MsgpackRpcRequestHandler) *methods = NULL;
-
-void msgpack_rpc_add_method_handler(String method, MsgpackRpcRequestHandler handler)
-{
- map_put(String, MsgpackRpcRequestHandler)(methods, method, handler);
-}
-
void msgpack_rpc_init_method_table(void)
{
methods = map_new(String, MsgpackRpcRequestHandler)();
]])
--- Keep track of the maximum method name length in order to avoid walking
--- strings longer than that when searching for a method handler
-local max_fname_len = 0
for i = 1, #functions do
local fn = functions[i]
output:write(' msgpack_rpc_add_method_handler('..
@@ -360,32 +313,9 @@ for i = 1, #functions do
'(MsgpackRpcRequestHandler) {.fn = handle_'.. (fn.impl_name or fn.name)..
', .async = '..tostring(fn.async)..'});\n')
- if #fn.name > max_fname_len then
- max_fname_len = #fn.name
- end
end
output:write('\n}\n\n')
-
-output:write([[
-MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
- size_t name_len)
-{
- String m = {
- .data=(char *)name,
- .size=MIN(name_len, ]]..max_fname_len..[[)
- };
- MsgpackRpcRequestHandler rv =
- map_get(String, MsgpackRpcRequestHandler)(methods, m);
-
- if (!rv.fn) {
- rv.fn = msgpack_rpc_handle_missing_method;
- }
-
- return rv;
-}
-]])
-
output:close()
mpack_output = io.open(mpack_outputf, 'wb')
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index cbea6a05c9..49edfda838 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -18,7 +18,8 @@ set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
set(HEADER_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gendeclarations.lua)
set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include)
-set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch.c)
+set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.generated.h)
+set(GENERATED_FUNCS_METADATA ${GENERATED_DIR}/api/private/funcs_metadata.generated.h)
set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h)
set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h)
set(GENERATED_FUNCS_HASH_INPUT ${GENERATED_DIR}/funcs.generated.h.gperf)
@@ -197,8 +198,11 @@ add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES}
${UNICODE_FILES}
)
-add_custom_command(OUTPUT ${GENERATED_API_DISPATCH} ${API_METADATA}
- COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${CMAKE_CURRENT_LIST_DIR} ${API_HEADERS} ${GENERATED_API_DISPATCH} ${API_METADATA}
+add_custom_command(OUTPUT ${GENERATED_API_DISPATCH} ${GENERATED_FUNCS_METADATA}
+ ${API_METADATA}
+ COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}
+ ${API_HEADERS} ${GENERATED_API_DISPATCH}
+ ${GENERATED_FUNCS_METADATA} ${API_METADATA}
DEPENDS
${API_HEADERS}
${MSGPACK_RPC_HEADERS}
diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c
new file mode 100644
index 0000000000..9b3bcc380a
--- /dev/null
+++ b/src/nvim/api/private/dispatch.c
@@ -0,0 +1,45 @@
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <assert.h>
+#include <msgpack.h>
+
+#include "nvim/map.h"
+#include "nvim/log.h"
+#include "nvim/vim.h"
+#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/api/private/dispatch.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/api/private/defs.h"
+
+#include "nvim/api/buffer.h"
+#include "nvim/api/tabpage.h"
+#include "nvim/api/ui.h"
+#include "nvim/api/vim.h"
+#include "nvim/api/window.h"
+
+static Map(String, MsgpackRpcRequestHandler) *methods = NULL;
+
+static void msgpack_rpc_add_method_handler(String method,
+ MsgpackRpcRequestHandler handler)
+{
+ map_put(String, MsgpackRpcRequestHandler)(methods, method, handler);
+}
+
+MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
+ size_t name_len)
+{
+ String m = { .data = (char *)name, .size = name_len };
+ MsgpackRpcRequestHandler rv =
+ map_get(String, MsgpackRpcRequestHandler)(methods, m);
+
+ if (!rv.fn) {
+ rv.fn = msgpack_rpc_handle_missing_method;
+ }
+
+ return rv;
+}
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+#include "api/private/dispatch_wrappers.generated.h"
+#endif
diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h
index d91456c306..c12cf9e698 100644
--- a/src/nvim/api/private/dispatch.h
+++ b/src/nvim/api/private/dispatch.h
@@ -18,6 +18,7 @@ typedef struct {
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/dispatch.h.generated.h"
+# include "api/private/dispatch_wrappers.h.generated.h"
#endif
#endif // NVIM_API_PRIVATE_DISPATCH_H
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index d80ee7dc67..c0ee735d1a 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -7,6 +7,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/handle.h"
+#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/ascii.h"
#include "nvim/vim.h"
#include "nvim/buffer.h"
@@ -27,6 +28,7 @@ typedef struct {
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/helpers.c.generated.h"
+# include "api/private/funcs_metadata.generated.h"
#endif
/// Start block that may cause vimscript exceptions
@@ -761,7 +763,7 @@ Dictionary api_metadata(void)
static Dictionary metadata = ARRAY_DICT_INIT;
if (!metadata.size) {
- msgpack_rpc_init_function_metadata(&metadata);
+ init_function_metadata(&metadata);
init_error_type_metadata(&metadata);
init_type_metadata(&metadata);
}
@@ -769,6 +771,22 @@ Dictionary api_metadata(void)
return copy_object(DICTIONARY_OBJ(metadata)).data.dictionary;
}
+static void init_function_metadata(Dictionary *metadata)
+{
+ msgpack_unpacked unpacked;
+ msgpack_unpacked_init(&unpacked);
+ if (msgpack_unpack_next(&unpacked,
+ (const char *)funcs_metadata,
+ sizeof(funcs_metadata),
+ NULL) != MSGPACK_UNPACK_SUCCESS) {
+ abort();
+ }
+ Object functions;
+ msgpack_rpc_to_object(&unpacked.data, &functions);
+ msgpack_unpacked_destroy(&unpacked);
+ PUT(*metadata, "functions", functions);
+}
+
static void init_error_type_metadata(Dictionary *metadata)
{
Dictionary types = ARRAY_DICT_INIT;
@@ -784,6 +802,7 @@ static void init_error_type_metadata(Dictionary *metadata)
PUT(*metadata, "error_types", DICTIONARY_OBJ(types));
}
+
static void init_type_metadata(Dictionary *metadata)
{
Dictionary types = ARRAY_DICT_INIT;
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index 8b1fb041e2..fa00988ae3 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -159,6 +159,23 @@ Window nvim_tabpage_get_win(Tabpage tabpage, Error *err)
}
}
+/// Gets the tab page number
+///
+/// @param tabpage The tabpage handle
+/// @param[out] err Details of an error that may have occurred
+/// @return The tabpage number
+Integer nvim_tabpage_get_number(Tabpage tabpage, Error *err)
+{
+ Integer rv = 0;
+ tabpage_T *tab = find_tab_by_handle(tabpage, err);
+
+ if (!tab) {
+ return rv;
+ }
+
+ return tabpage_index(tab);
+}
+
/// Checks if a tab page is valid
///
/// @param tabpage The tab page handle
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 166e43f698..382f65e7d9 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -341,6 +341,26 @@ Tabpage nvim_win_get_tabpage(Window window, Error *err)
return rv;
}
+/// Gets the window number
+///
+/// @param window The window handle
+/// @param[out] err Details of an error that may have occurred
+/// @return The window number
+Integer nvim_win_get_number(Window window, Error *err)
+{
+ Integer rv = 0;
+ win_T *win = find_window_by_handle(window, err);
+
+ if (!win) {
+ return rv;
+ }
+
+ int tabnr;
+ win_get_tabwin(window, &tabnr, (int *)&rv);
+
+ return rv;
+}
+
/// Checks if a window is valid
///
/// @param window The window handle
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 51c9fb1556..a0ae1a3e6b 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -462,8 +462,7 @@ static void insert_enter(InsertState *s)
o_lnum = curwin->w_cursor.lnum;
}
- foldUpdateAll(curwin);
- foldOpenCursor();
+ foldUpdateAfterInsert();
if (s->cmdchar != 'r' && s->cmdchar != 'v') {
apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL, false, curbuf);
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index cae032f437..dce2f32707 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -9527,24 +9527,35 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
varnumber_T n;
int error = FALSE;
- /* Position the cursor. Needed after a message that ends in a space. */
- ui_cursor_goto(msg_row, msg_col);
-
++no_mapping;
++allow_keys;
for (;; ) {
- if (argvars[0].v_type == VAR_UNKNOWN)
- /* getchar(): blocking wait. */
+ // Position the cursor. Needed after a message that ends in a space,
+ // or if event processing caused a redraw.
+ ui_cursor_goto(msg_row, msg_col);
+
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ // getchar(): blocking wait.
+ if (!(char_avail() || using_script() || input_available())) {
+ input_enable_events();
+ (void)os_inchar(NULL, 0, -1, 0);
+ input_disable_events();
+ if (!multiqueue_empty(main_loop.events)) {
+ multiqueue_process_events(main_loop.events);
+ continue;
+ }
+ }
n = safe_vgetc();
- else if (get_tv_number_chk(&argvars[0], &error) == 1)
- /* getchar(1): only check if char avail */
+ } else if (get_tv_number_chk(&argvars[0], &error) == 1) {
+ // getchar(1): only check if char avail
n = vpeekc_any();
- else if (error || vpeekc_any() == NUL)
- /* illegal argument or getchar(0) and no char avail: return zero */
+ } else if (error || vpeekc_any() == NUL) {
+ // illegal argument or getchar(0) and no char avail: return zero
n = 0;
- else
- /* getchar(0) and char avail: return char */
+ } else {
+ // getchar(0) and char avail: return char
n = safe_vgetc();
+ }
if (n == K_IGNORE)
continue;
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index 5126dfd84e..92efc9fa2e 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -112,8 +112,8 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
// to `alloc_cb` will return the same unused pointer(`rbuffer_produced`
// won't be called)
&& cnt != 0) {
- DLOG("Closing Stream(%p) because of %s(%zd)", stream,
- uv_strerror((int)cnt), cnt);
+ DLOG("Closing Stream (%p): %s (%s)", stream,
+ uv_err_name((int)cnt), os_strerror((int)cnt));
// Read error or EOF, either way stop the stream and invoke the callback
// with eof == true
uv_read_stop(uvstream);
diff --git a/src/nvim/ex_eval.h b/src/nvim/ex_eval.h
index 30871c7711..f61e01d25b 100644
--- a/src/nvim/ex_eval.h
+++ b/src/nvim/ex_eval.h
@@ -23,19 +23,19 @@ struct eslist_elem {
#define CSTACK_LEN 50
struct condstack {
- short cs_flags[CSTACK_LEN]; /* CSF_ flags */
- char cs_pending[CSTACK_LEN]; /* CSTP_: what's pending in ":finally"*/
+ int cs_flags[CSTACK_LEN]; // CSF_ flags
+ char cs_pending[CSTACK_LEN]; // CSTP_: what's pending in ":finally"
union {
- void *csp_rv[CSTACK_LEN]; /* return typeval for pending return */
- void *csp_ex[CSTACK_LEN]; /* exception for pending throw */
+ void *csp_rv[CSTACK_LEN]; // return typeval for pending return
+ void *csp_ex[CSTACK_LEN]; // exception for pending throw
} cs_pend;
- void *cs_forinfo[CSTACK_LEN]; /* info used by ":for" */
- int cs_line[CSTACK_LEN]; /* line nr of ":while"/":for" line */
- int cs_idx; /* current entry, or -1 if none */
- int cs_looplevel; /* nr of nested ":while"s and ":for"s */
- int cs_trylevel; /* nr of nested ":try"s */
- eslist_T *cs_emsg_silent_list; /* saved values of "emsg_silent" */
- char cs_lflags; /* loop flags: CSL_ flags */
+ void *cs_forinfo[CSTACK_LEN]; // info used by ":for"
+ int cs_line[CSTACK_LEN]; // line nr of ":while"/":for" line
+ int cs_idx; // current entry, or -1 if none
+ int cs_looplevel; // nr of nested ":while"s and ":for"s
+ int cs_trylevel; // nr of nested ":try"s
+ eslist_T *cs_emsg_silent_list; // saved values of "emsg_silent"
+ int cs_lflags; // loop flags: CSL_ flags
};
# define cs_rettv cs_pend.csp_rv
# define cs_exception cs_pend.csp_ex
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 4254697241..7444eb8a38 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -4396,6 +4396,7 @@ static HistoryType hist_char2type(const int c)
case '>': {
return HIST_DEBUG;
}
+ case NUL:
case '/':
case '?': {
return HIST_SEARCH;
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 70030b8525..c84d738cb4 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -788,6 +788,19 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
}
}
+/// Updates folds when leaving insert-mode.
+void foldUpdateAfterInsert(void)
+{
+ if (foldmethodIsManual(curwin) // foldmethod=manual: No need to update.
+ // These foldmethods are too slow, do not auto-update on insert-leave.
+ || foldmethodIsSyntax(curwin) || foldmethodIsExpr(curwin)) {
+ return;
+ }
+
+ foldUpdateAll(curwin);
+ foldOpenCursor();
+}
+
/* foldUpdateAll() {{{2 */
/*
* Update all lines in a window for folding.
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 3ed85677fc..0b20647771 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -1761,8 +1761,8 @@ static void cs_print_tags_priv(char **matches, char **cntxts,
*/
static int cs_read_prompt(size_t i)
{
- char ch;
- char *buf = NULL; /* buffer for possible error message from cscope */
+ int ch;
+ char *buf = NULL; // buffer for possible error message from cscope
size_t bufpos = 0;
char *cs_emsg = _("E609: Cscope error: %s");
size_t cs_emsg_len = strlen(cs_emsg);
@@ -1774,35 +1774,34 @@ static int cs_read_prompt(size_t i)
size_t maxlen = IOSIZE - cs_emsg_len;
for (;; ) {
- while ((ch = (char)getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0])
- /* if there is room and char is printable */
+ while ((ch = getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0]) {
+ // if there is room and char is printable
if (bufpos < maxlen - 1 && vim_isprintc(ch)) {
// lazy buffer allocation
if (buf == NULL) {
buf = xmalloc(maxlen);
}
- {
- /* append character to the message */
- buf[bufpos++] = ch;
- buf[bufpos] = NUL;
- if (bufpos >= epromptlen
- && strcmp(&buf[bufpos - epromptlen], eprompt) == 0) {
- /* remove eprompt from buf */
- buf[bufpos - epromptlen] = NUL;
-
- /* print message to user */
- (void)EMSG2(cs_emsg, buf);
+ // append character to the message
+ buf[bufpos++] = (char)ch;
+ buf[bufpos] = NUL;
+ if (bufpos >= epromptlen
+ && strcmp(&buf[bufpos - epromptlen], eprompt) == 0) {
+ // remove eprompt from buf
+ buf[bufpos - epromptlen] = NUL;
+
+ // print message to user
+ (void)EMSG2(cs_emsg, buf);
- /* send RETURN to cscope */
- (void)putc('\n', csinfo[i].to_fp);
- (void)fflush(csinfo[i].to_fp);
+ // send RETURN to cscope
+ (void)putc('\n', csinfo[i].to_fp);
+ (void)fflush(csinfo[i].to_fp);
- /* clear buf */
- bufpos = 0;
- buf[bufpos] = NUL;
- }
+ // clear buf
+ bufpos = 0;
+ buf[bufpos] = NUL;
}
}
+ }
for (size_t n = 0; n < strlen(CSCOPE_PROMPT); ++n) {
if (n > 0)
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 6dcbf50750..76e3829bee 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -5925,8 +5925,7 @@ static void nv_replace(cmdarg_T *cap)
set_last_insert(cap->nchar);
}
- foldUpdateAll(curwin);
- foldOpenCursor();
+ foldUpdateAfterInsert();
}
/*
diff --git a/src/nvim/option.c b/src/nvim/option.c
index e2a5d38bee..81919c00d2 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1032,6 +1032,15 @@ void set_init_3(void)
xfree(p);
}
+ if (bufempty()) {
+ int idx_ffs = findoption((char_u *)"ffs");
+
+ // Apply the first entry of 'fileformats' to the initial buffer.
+ if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET)) {
+ set_fileformat(default_fileformat(), OPT_LOCAL);
+ }
+ }
+
set_title_defaults();
}
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index e9a3dcbff8..18ee008d66 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -545,6 +545,16 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
static void shell_write_cb(Stream *stream, void *data, int status)
{
+ if (status) {
+ // Can happen if system() tries to send input to a shell command that was
+ // backgrounded (:call system("cat - &", "foo")). #3529 #5241
+ EMSG2(_("E5677: Error writing input to shell-command: %s"),
+ uv_err_name(status));
+ }
+ if (stream->closed) { // Process may have exited before this write.
+ ELOG("stream was already closed");
+ return;
+ }
stream_close(stream, NULL, NULL);
}
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 4d21887240..67e7c97905 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -34,6 +34,7 @@ NEW_TESTS = \
test_cscope.res \
test_hardcopy.res \
test_help_tagjump.res \
+ test_history.res \
test_langmap.res \
test_syntax.res \
test_usercommands.res \
diff --git a/src/nvim/testdir/test_history.vim b/src/nvim/testdir/test_history.vim
new file mode 100644
index 0000000000..ee6acfffc3
--- /dev/null
+++ b/src/nvim/testdir/test_history.vim
@@ -0,0 +1,65 @@
+" Tests for the history functions
+
+if !has('cmdline_hist')
+ finish
+endif
+
+set history=7
+
+function History_Tests(hist)
+ " First clear the history
+ call histadd(a:hist, 'dummy')
+ call assert_true(histdel(a:hist))
+ call assert_equal(-1, histnr(a:hist))
+ call assert_equal('', histget(a:hist))
+
+ call assert_true(histadd(a:hist, 'ls'))
+ call assert_true(histadd(a:hist, 'buffers'))
+ call assert_equal('buffers', histget(a:hist))
+ call assert_equal('ls', histget(a:hist, -2))
+ call assert_equal('ls', histget(a:hist, 1))
+ call assert_equal('', histget(a:hist, 5))
+ call assert_equal('', histget(a:hist, -5))
+ call assert_equal(2, histnr(a:hist))
+ call assert_true(histdel(a:hist, 2))
+ call assert_false(histdel(a:hist, 7))
+ call assert_equal(1, histnr(a:hist))
+ call assert_equal('ls', histget(a:hist, -1))
+
+ call assert_true(histadd(a:hist, 'buffers'))
+ call assert_true(histadd(a:hist, 'ls'))
+ call assert_equal('ls', histget(a:hist, -1))
+ call assert_equal(4, histnr(a:hist))
+
+ " Test for removing entries matching a pattern
+ for i in range(1, 3)
+ call histadd(a:hist, 'text_' . i)
+ endfor
+ call assert_true(histdel(a:hist, 'text_\d\+'))
+ call assert_equal('ls', histget(a:hist, -1))
+
+ " Test for freeing the entire history list
+ for i in range(1, 7)
+ call histadd(a:hist, 'text_' . i)
+ endfor
+ call histdel(a:hist)
+ for i in range(1, 7)
+ call assert_equal('', histget(a:hist, i))
+ call assert_equal('', histget(a:hist, i - 7 - 1))
+ endfor
+endfunction
+
+function Test_History()
+ for h in ['cmd', ':', '', 'search', '/', '?', 'expr', '=', 'input', '@', 'debug', '>']
+ call History_Tests(h)
+ endfor
+
+ " Negative tests
+ call assert_false(histdel('abc'))
+ call assert_equal('', histget('abc'))
+ call assert_fails('call histdel([])', 'E730:')
+ call assert_equal('', histget(10))
+ call assert_fails('call histget([])', 'E730:')
+ call assert_equal(-1, histnr('abc'))
+ call assert_fails('call histnr([])', 'E730:')
+endfunction
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 399d19ae45..e24836306c 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -608,7 +608,7 @@ static int included_patches[] = {
// 1836,
// 1835,
// 1834,
- // 1833,
+ 1833,
1832,
1831,
// 1830 NA
@@ -824,7 +824,7 @@ static int included_patches[] = {
// 1622 NA
// 1621 NA
1620,
- // 1619,
+ 1619,
// 1618 NA
// 1617 NA
// 1616 NA
@@ -949,7 +949,7 @@ static int included_patches[] = {
// 1497 NA
// 1496 NA
// 1495 NA
- // 1494,
+ 1494,
// 1493 NA
1492,
1491,
@@ -2652,14 +2652,13 @@ void intro_message(int colon)
N_(NVIM_VERSION_LONG),
"",
N_("by Bram Moolenaar et al."),
- N_("Vim is open source and freely distributable"),
- "",
- N_("Type \":Tutor\" or \":help nvim\" to get started!"),
- "",
- N_("Still have questions? https://neovim.io/community"),
+ N_("Nvim is open source and freely distributable"),
+ N_("https://neovim.io/community"),
"",
+ N_("type :help nvim<Enter> if you are new! "),
+ N_("type :CheckHealth<Enter> to optimize Nvim"),
N_("type :q<Enter> to exit "),
- N_("type :help<Enter> or <F1> for on-line help"),
+ N_("type :help<Enter> for help "),
"",
N_("Help poor children in Uganda!"),
N_("type :help iccf<Enter> for information "),
diff --git a/src/nvim/window.c b/src/nvim/window.c
index a259654d52..29c670322a 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5716,45 +5716,46 @@ int win_getid(typval_T *argvars)
int win_gotoid(typval_T *argvars)
{
- win_T *wp;
- tabpage_T *tp;
int id = get_tv_number(&argvars[0]);
- for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) {
- for (wp = tp == curtab ? firstwin : tp->tp_firstwin;
- wp != NULL; wp = wp->w_next) {
- if (wp->handle == id) {
- goto_tabpage_win(tp, wp);
- return 1;
- }
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->handle == id) {
+ goto_tabpage_win(tp, wp);
+ return 1;
}
}
return 0;
}
-void win_id2tabwin(typval_T *argvars, list_T *list)
+void win_get_tabwin(handle_T id, int *tabnr, int *winnr)
{
- win_T *wp;
- tabpage_T *tp;
- int winnr = 1;
- int tabnr = 1;
- int id = get_tv_number(&argvars[0]);
+ *tabnr = 0;
+ *winnr = 0;
- for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) {
- for (wp = tp == curtab ? firstwin : tp->tp_firstwin;
- wp != NULL; wp = wp->w_next) {
+ int tnum = 1, wnum = 1;
+ FOR_ALL_TABS(tp) {
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
if (wp->handle == id) {
- list_append_number(list, tabnr);
- list_append_number(list, winnr);
+ *winnr = wnum;
+ *tabnr = tnum;
return;
}
- winnr++;
+ wnum++;
}
- tabnr++;
- winnr = 1;
+ tnum++;
+ wnum = 1;
}
- list_append_number(list, 0);
- list_append_number(list, 0);
+}
+
+void win_id2tabwin(typval_T *argvars, list_T *list)
+{
+ int winnr = 1;
+ int tabnr = 1;
+ int id = get_tv_number(&argvars[0]);
+
+ win_get_tabwin(id, &tabnr, &winnr);
+ list_append_number(list, tabnr);
+ list_append_number(list, winnr);
}
int win_id2win(typval_T *argvars)
diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua
index 47dede8b44..90940e9577 100644
--- a/test/functional/api/tabpage_spec.lua
+++ b/test/functional/api/tabpage_spec.lua
@@ -51,6 +51,22 @@ describe('tabpage_* functions', function()
end)
end)
+ describe('get_number', function()
+ it('works', function()
+ local tabs = nvim('list_tabpages')
+ eq(1, tabpage('get_number', tabs[1]))
+
+ nvim('command', 'tabnew')
+ local tab1, tab2 = unpack(nvim('list_tabpages'))
+ eq(1, tabpage('get_number', tab1))
+ eq(2, tabpage('get_number', tab2))
+
+ nvim('command', '-tabmove')
+ eq(2, tabpage('get_number', tab1))
+ eq(1, tabpage('get_number', tab2))
+ end)
+ end)
+
describe('is_valid', function()
it('works', function()
nvim('command', 'tabnew')
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 2c43e4db2c..bf2bf55fb3 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -200,6 +200,30 @@ describe('window_* functions', function()
end)
end)
+ describe('get_number', function()
+ it('works', function()
+ local wins = nvim('list_wins')
+ eq(1, window('get_number', wins[1]))
+
+ nvim('command', 'split')
+ local win1, win2 = unpack(nvim('list_wins'))
+ eq(1, window('get_number', win1))
+ eq(2, window('get_number', win2))
+
+ nvim('command', 'wincmd J')
+ eq(2, window('get_number', win1))
+ eq(1, window('get_number', win2))
+
+ nvim('command', 'tabnew')
+ local win3 = nvim('list_wins')[3]
+ -- First tab page
+ eq(2, window('get_number', win1))
+ eq(1, window('get_number', win2))
+ -- Second tab page
+ eq(1, window('get_number', win3))
+ end)
+ end)
+
describe('is_valid', function()
it('works', function()
nvim('command', 'split')
diff --git a/test/functional/eval/execute_spec.lua b/test/functional/eval/execute_spec.lua
index 10a6de6eb4..b5b481435a 100644
--- a/test/functional/eval/execute_spec.lua
+++ b/test/functional/eval/execute_spec.lua
@@ -70,16 +70,16 @@ describe('execute()', function()
end)
it('silences command run inside', function()
- local screen = Screen.new(20, 5)
+ local screen = Screen.new(40, 5)
screen:attach()
screen:set_default_attr_ids( {[0] = {bold=true, foreground=255}} )
feed(':let g:mes = execute("echon 42")<CR>')
screen:expect([[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :let g:mes = execute("echon 42") |
]])
eq('42', eval('g:mes'))
end)
diff --git a/test/functional/shell/viml_system_spec.lua b/test/functional/eval/system_spec.lua
index b8de7cc86f..b8f1f87f30 100644
--- a/test/functional/shell/viml_system_spec.lua
+++ b/test/functional/eval/system_spec.lua
@@ -1,7 +1,3 @@
--- Specs for
--- - `system()`
--- - `systemlist()`
-
local helpers = require('test.functional.helpers')(after_each)
local eq, clear, eval, feed, nvim =
helpers.eq, helpers.clear, helpers.eval, helpers.feed, helpers.nvim
@@ -120,12 +116,22 @@ describe('system()', function()
it('returns the program output', function()
eq("echoed", eval('system("echo -n echoed")'))
end)
+ it('to backgrounded command does not crash', function()
+ -- This is indeterminate, just exercise the codepath.
+ eval('system("echo -n echoed &")')
+ eq(2, eval("1+1")) -- Still alive?
+ end)
end)
describe('passing input', function()
it('returns the program output', function()
eq("input", eval('system("cat -", "input")'))
end)
+ it('to backgrounded command does not crash', function()
+ -- This is indeterminate, just exercise the codepath.
+ eval('system("cat - &", "input")')
+ eq(2, eval("1+1")) -- Still alive?
+ end)
end)
describe('passing a lot of input', function()
diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua
index 295c763d74..fba9466b78 100644
--- a/test/functional/eval/timer_spec.lua
+++ b/test/functional/eval/timer_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local ok, feed, eq, eval = helpers.ok, helpers.feed, helpers.eq, helpers.eval
local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run
local clear, execute, funcs = helpers.clear, helpers.execute, helpers.funcs
+local curbufmeths = helpers.curbufmeths
describe('timers', function()
before_each(function()
@@ -62,19 +63,76 @@ describe('timers', function()
end)
it('are paused when event processing is disabled', function()
- -- this is not the intended behavior, but at least there will
- -- not be a burst of queued up callbacks
- execute("call timer_start(50, 'MyHandler', {'repeat': 2})")
+ execute("call timer_start(50, 'MyHandler', {'repeat': -1})")
run(nil, nil, nil, 100)
local count = eval("g:val")
+ -- shows two line error message and thus invokes the return prompt.
+ -- if we start to allow event processing here, we need to change this test.
+ execute("throw 'fatal error'")
+ run(nil, nil, nil, 300)
+ feed("<cr>")
+ local diff = eval("g:val") - count
+ ok(0 <= diff and diff <= 4)
+ end)
+
+ it('are triggered in blocking getchar() call', function()
+ execute("call timer_start(50, 'MyHandler', {'repeat': -1})")
nvim_async("command", "let g:c = getchar()")
run(nil, nil, nil, 300)
feed("c")
- local diff = eval("g:val") - count
- ok(0 <= diff and diff <= 2)
+ local count = eval("g:val")
+ ok(count >= 5)
eq(99, eval("g:c"))
end)
+ it('can invoke redraw in blocking getchar() call', function()
+ local screen = Screen.new(40, 6)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold=true, foreground=Screen.colors.Blue},
+ })
+
+ curbufmeths.set_lines(0, -1, true, {"ITEM 1", "ITEM 2"})
+ source([[
+ func! AddItem(timer)
+ call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3'])
+ redraw
+ endfunc
+ call timer_start(200, 'AddItem')
+ ]])
+ nvim_async("command", "let g:c2 = getchar()")
+
+ screen:expect([[
+ ITEM 1 |
+ ITEM 2 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ^ |
+ ]])
+
+ screen:sleep(200)
+ screen:expect([[
+ ITEM 1 |
+ ITEM 2 |
+ ITEM 3 |
+ {1:~ }|
+ {1:~ }|
+ ^ |
+ ]])
+
+ feed("3")
+ eq(51, eval("g:c2"))
+ screen:expect([[
+ ^ITEM 1 |
+ ITEM 2 |
+ ITEM 3 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
it('can be stopped', function()
local t = eval("timer_start(50, 'MyHandler', {'repeat': -1})")
eq(0,eval("g:val"))
diff --git a/test/functional/shell/bang_filter_spec.lua b/test/functional/ex_cmds/bang_filter_spec.lua
index a320e6d018..a320e6d018 100644
--- a/test/functional/shell/bang_filter_spec.lua
+++ b/test/functional/ex_cmds/bang_filter_spec.lua
diff --git a/test/functional/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua
index dc87312911..dc87312911 100644
--- a/test/functional/dict_notifications_spec.lua
+++ b/test/functional/ex_cmds/dict_notifications_spec.lua
diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua
index 58d6c75940..045bdb0749 100644
--- a/test/functional/terminal/api_spec.lua
+++ b/test/functional/terminal/api_spec.lua
@@ -22,7 +22,7 @@ describe('api', function()
-- Start the socket from the child nvim.
child_session.feed_data(":echo serverstart('"..socket_name.."')\n")
- -- Wait for socket creation by abusing expect().
+ -- Wait for socket creation.
screen:expect([[
{1: } |
{4:~ }|
@@ -37,6 +37,16 @@ describe('api', function()
local socket_session2 = helpers.connect(socket_name)
child_session.feed_data("i[tui] insert-mode")
+ -- Wait for stdin to be processed.
+ screen:expect([[
+ [tui] insert-mode{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
ok(socket_session1:request("nvim_ui_attach", 42, 6, {rgb=true}))
ok(socket_session2:request("nvim_ui_attach", 25, 30, {rgb=true}))