aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.asan-blacklist2
-rw-r--r--.ci/common/test.sh19
-rw-r--r--CMakeLists.txt24
-rw-r--r--clint-ignored-files.txt1
-rwxr-xr-xclint.py112
-rw-r--r--runtime/CMakeLists.txt90
-rw-r--r--runtime/autoload/phpcomplete.vim74
-rw-r--r--runtime/autoload/provider/clipboard.vim14
-rw-r--r--runtime/autoload/provider/script_host.py8
-rw-r--r--runtime/autoload/remote/host.vim2
-rw-r--r--runtime/autoload/tutor.vim346
-rw-r--r--runtime/doc/change.txt3
-rw-r--r--runtime/doc/cmdline.txt3
-rw-r--r--runtime/doc/editing.txt26
-rw-r--r--runtime/doc/eval.txt133
-rw-r--r--runtime/doc/gui.txt15
-rw-r--r--runtime/doc/gui_w32.txt29
-rw-r--r--runtime/doc/indent.txt2
-rw-r--r--runtime/doc/index.txt3
-rw-r--r--runtime/doc/intro.txt5
-rw-r--r--runtime/doc/map.txt5
-rw-r--r--runtime/doc/motion.txt4
-rw-r--r--runtime/doc/nvim.txt24
-rw-r--r--runtime/doc/nvim_from_vim.txt49
-rw-r--r--runtime/doc/nvim_intro.txt26
-rw-r--r--runtime/doc/nvim_python.txt2
-rw-r--r--runtime/doc/options.txt91
-rw-r--r--runtime/doc/pi_tutor.txt50
-rw-r--r--runtime/doc/recover.txt4
-rw-r--r--runtime/doc/syntax.txt3
-rw-r--r--runtime/doc/term.txt13
-rw-r--r--runtime/doc/todo.txt162
-rw-r--r--runtime/doc/usr_01.txt42
-rw-r--r--runtime/doc/usr_02.txt2
-rw-r--r--runtime/doc/usr_09.txt4
-rw-r--r--runtime/doc/usr_40.txt4
-rw-r--r--runtime/doc/usr_42.txt7
-rw-r--r--runtime/doc/various.txt11
-rw-r--r--runtime/doc/vi_diff.txt59
-rw-r--r--runtime/doc/vim_diff.txt19
-rw-r--r--runtime/doc/windows.txt10
-rw-r--r--runtime/filetype.vim9
-rw-r--r--runtime/ftplugin/tutor.vim43
-rw-r--r--runtime/indent/php.vim87
-rw-r--r--runtime/macros/editexisting.vim4
-rw-r--r--runtime/plugin/tutor.vim6
-rw-r--r--runtime/syntax/tutor.vim83
-rw-r--r--runtime/syntax/vim.vim170
-rw-r--r--runtime/syntax/vimnormal.vim16
-rw-r--r--runtime/syntax/zimbu.vim64
-rw-r--r--runtime/tutor/en/vim-01-beginner.tutor955
-rw-r--r--runtime/tutor/tutor.tutor259
-rw-r--r--scripts/gen_events.lua65
-rw-r--r--scripts/genoptions.lua183
-rw-r--r--scripts/genvimvim.lua138
-rw-r--r--scripts/msgpack-gen.lua6
-rwxr-xr-xscripts/vim-patch.sh172
-rw-r--r--src/nvim/CMakeLists.txt28
-rw-r--r--src/nvim/api/buffer.c21
-rw-r--r--src/nvim/api/tabpage.c1
-rw-r--r--src/nvim/api/vim.c64
-rw-r--r--src/nvim/api/window.c5
-rw-r--r--src/nvim/auevents.lua106
-rw-r--r--src/nvim/buffer.c4
-rw-r--r--src/nvim/edit.c10
-rw-r--r--src/nvim/eval.c1578
-rw-r--r--src/nvim/eval.h4
-rw-r--r--src/nvim/eval_defs.h5
-rw-r--r--src/nvim/event/defs.h39
-rw-r--r--src/nvim/event/loop.c85
-rw-r--r--src/nvim/event/loop.h70
-rw-r--r--src/nvim/event/process.c343
-rw-r--r--src/nvim/event/process.h58
-rw-r--r--src/nvim/event/pty_process.c (renamed from src/nvim/os/pty_process.c)203
-rw-r--r--src/nvim/event/pty_process.h30
-rw-r--r--src/nvim/event/queue.c208
-rw-r--r--src/nvim/event/queue.h19
-rw-r--r--src/nvim/event/rstream.c201
-rw-r--r--src/nvim/event/rstream.h16
-rw-r--r--src/nvim/event/signal.c59
-rw-r--r--src/nvim/event/signal.h23
-rw-r--r--src/nvim/event/socket.c167
-rw-r--r--src/nvim/event/socket.h39
-rw-r--r--src/nvim/event/stream.c111
-rw-r--r--src/nvim/event/stream.h60
-rw-r--r--src/nvim/event/time.c62
-rw-r--r--src/nvim/event/time.h21
-rw-r--r--src/nvim/event/uv_process.c77
-rw-r--r--src/nvim/event/uv_process.h25
-rw-r--r--src/nvim/event/wstream.c164
-rw-r--r--src/nvim/event/wstream.h24
-rw-r--r--src/nvim/ex_cmds.c16
-rw-r--r--src/nvim/ex_cmds.lua12
-rw-r--r--src/nvim/ex_cmds2.c2
-rw-r--r--src/nvim/ex_docmd.c23
-rw-r--r--src/nvim/ex_getln.c9
-rw-r--r--src/nvim/fileio.c121
-rw-r--r--src/nvim/fileio.h96
-rw-r--r--src/nvim/func_attr.h2
-rw-r--r--src/nvim/getchar.c4
-rw-r--r--src/nvim/globals.h21
-rw-r--r--src/nvim/if_cscope.c1
-rw-r--r--src/nvim/keymap.h6
-rw-r--r--src/nvim/lib/klist.h2
-rw-r--r--src/nvim/lib/queue.h92
-rw-r--r--src/nvim/main.c46
-rw-r--r--src/nvim/map.c2
-rw-r--r--src/nvim/memline.c6
-rw-r--r--src/nvim/menu.c115
-rw-r--r--src/nvim/message.c16
-rw-r--r--src/nvim/misc1.c1
-rw-r--r--src/nvim/msgpack_rpc/channel.c222
-rw-r--r--src/nvim/msgpack_rpc/channel.h1
-rw-r--r--src/nvim/msgpack_rpc/defs.h5
-rw-r--r--src/nvim/msgpack_rpc/helpers.h2
-rw-r--r--src/nvim/msgpack_rpc/remote_ui.c23
-rw-r--r--src/nvim/msgpack_rpc/server.c223
-rw-r--r--src/nvim/normal.c41
-rw-r--r--src/nvim/ops.c11
-rw-r--r--src/nvim/option.c1422
-rw-r--r--src/nvim/option_defs.h15
-rw-r--r--src/nvim/options.lua2777
-rw-r--r--src/nvim/os/event.c177
-rw-r--r--src/nvim/os/event.h35
-rw-r--r--src/nvim/os/event_defs.h17
-rw-r--r--src/nvim/os/fs.c74
-rw-r--r--src/nvim/os/input.c61
-rw-r--r--src/nvim/os/job.c472
-rw-r--r--src/nvim/os/job.h21
-rw-r--r--src/nvim/os/job_defs.h63
-rw-r--r--src/nvim/os/job_private.h118
-rw-r--r--src/nvim/os/os.h1
-rw-r--r--src/nvim/os/os_defs.h5
-rw-r--r--src/nvim/os/pipe_process.c110
-rw-r--r--src/nvim/os/pipe_process.h7
-rw-r--r--src/nvim/os/pty_process.h7
-rw-r--r--src/nvim/os/rstream.c253
-rw-r--r--src/nvim/os/rstream.h13
-rw-r--r--src/nvim/os/rstream_defs.h20
-rw-r--r--src/nvim/os/shell.c109
-rw-r--r--src/nvim/os/signal.c60
-rw-r--r--src/nvim/os/signal.h2
-rw-r--r--src/nvim/os/stream.c30
-rw-r--r--src/nvim/os/time.c4
-rw-r--r--src/nvim/os/users.c5
-rw-r--r--src/nvim/os/uv_helpers.c98
-rw-r--r--src/nvim/os/uv_helpers.h13
-rw-r--r--src/nvim/os/win_defs.h8
-rw-r--r--src/nvim/os/wstream.c243
-rw-r--r--src/nvim/os/wstream.h13
-rw-r--r--src/nvim/os/wstream_defs.h19
-rw-r--r--src/nvim/os_unix.c3
-rw-r--r--src/nvim/path.c22
-rw-r--r--src/nvim/regexp.c22
-rw-r--r--src/nvim/regexp_nfa.c140
-rw-r--r--src/nvim/screen.c22
-rw-r--r--src/nvim/search.c8
-rw-r--r--src/nvim/spell.c12
-rw-r--r--src/nvim/terminal.c94
-rw-r--r--src/nvim/testdir/Makefile18
-rw-r--r--src/nvim/testdir/test57.in500
-rw-r--r--src/nvim/testdir/test57.ok459
-rw-r--r--src/nvim/testdir/test62.in191
-rw-r--r--src/nvim/testdir/test62.ok88
-rw-r--r--src/nvim/testdir/test79.inbin3381 -> 3335 bytes
-rw-r--r--src/nvim/testdir/test79.okbin574 -> 570 bytes
-rw-r--r--src/nvim/testdir/test80.in201
-rw-r--r--src/nvim/testdir/test80.ok131
-rw-r--r--src/nvim/testdir/test86.in1425
-rw-r--r--src/nvim/testdir/test86.ok1266
-rw-r--r--src/nvim/testdir/test87.in1402
-rw-r--r--src/nvim/testdir/test87.ok1266
-rw-r--r--src/nvim/tui/term_input.inl90
-rw-r--r--src/nvim/tui/tui.c122
-rw-r--r--src/nvim/ui.c43
-rw-r--r--src/nvim/ui.h3
-rw-r--r--src/nvim/version.c69
-rw-r--r--src/nvim/vim.h15
-rw-r--r--test/functional/api/buffer_spec.lua35
-rw-r--r--test/functional/api/vim_spec.lua9
-rw-r--r--test/functional/clipboard/clipboard_provider_spec.lua103
-rw-r--r--test/functional/eval/glob_spec.lua25
-rw-r--r--test/functional/eval/msgpack_functions_spec.lua615
-rw-r--r--test/functional/ex_cmds/grep_spec.lua22
-rw-r--r--test/functional/ex_cmds/menu_spec.lua38
-rw-r--r--test/functional/ex_cmds/recover_spec.lua4
-rw-r--r--test/functional/fixtures/autoload/provider/clipboard.vim (renamed from test/functional/clipboard/autoload/provider/clipboard.vim)16
-rw-r--r--test/functional/helpers.lua26
-rw-r--r--test/functional/job/job_spec.lua2
-rw-r--r--test/functional/legacy/057_sort_spec.lua603
-rw-r--r--test/functional/legacy/060_exists_and_has_functions_spec.lua28
-rw-r--r--test/functional/legacy/062_tab_pages_spec.lua240
-rw-r--r--test/functional/legacy/077_mf_hash_grow_spec.lua2
-rw-r--r--test/functional/legacy/080_substitute_spec.lua162
-rw-r--r--test/functional/legacy/mapping_spec.lua13
-rw-r--r--test/functional/provider/define_spec.lua (renamed from test/functional/runtime/autoload/remote/define_spec.lua)0
-rw-r--r--test/functional/provider/python3_spec.lua (renamed from test/functional/runtime/autoload/provider/python3_spec.lua)10
-rw-r--r--test/functional/provider/python_spec.lua (renamed from test/functional/runtime/autoload/provider/python_spec.lua)10
-rw-r--r--test/functional/shell/viml_system_spec.lua4
-rw-r--r--test/functional/terminal/highlight_spec.lua25
-rw-r--r--test/functional/ui/screen.lua16
-rw-r--r--test/functional/ui/screen_basic_spec.lua24
-rw-r--r--test/unit/fixtures/queue.c16
-rw-r--r--test/unit/fixtures/queue.h4
-rw-r--r--test/unit/os/fs_spec.lua129
-rw-r--r--test/unit/os/shell_spec.lua2
-rw-r--r--test/unit/queue_spec.lua123
-rw-r--r--third-party/CMakeLists.txt8
-rw-r--r--third-party/cmake/BuildLuarocks.cmake36
209 files changed, 12571 insertions, 12476 deletions
diff --git a/.asan-blacklist b/.asan-blacklist
new file mode 100644
index 0000000000..bd977dfe17
--- /dev/null
+++ b/.asan-blacklist
@@ -0,0 +1,2 @@
+# libuv queue.h pointer arithmetic is not accepted by asan
+fun:queue_node_data
diff --git a/.ci/common/test.sh b/.ci/common/test.sh
index 2eaaf0b2b1..c1bbd8dc9a 100644
--- a/.ci/common/test.sh
+++ b/.ci/common/test.sh
@@ -82,4 +82,23 @@ install_nvim() {
echo "Maybe the helptags have not been generated properly."
exit 1
}
+
+ # Check that all runtime files were installed
+ for file in doc/tags syntax/vim/generated.vim $(
+ cd runtime ; git ls-files | grep -e '.vim$' -e '.ps$' -e '.dict$' -e '.py$' -e '.tutor$'
+ ) ; do
+ if ! test -e "${INSTALL_PREFIX}/share/nvim/runtime/$file" ; then
+ echo "It appears that $file is not installed."
+ exit 1
+ fi
+ done
+
+ for file in $(
+ cd runtime ; git ls-files | grep -e '.awk$' -e '.sh$' -e '.bat$'
+ ) ; do
+ if ! test -x "${INSTALL_PREFIX}/share/nvim/runtime/$file" ; then
+ echo "It appears that $file is not installed or is not executable."
+ exit 1
+ fi
+ done
}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 06db4f473e..700bfdf7cf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -266,11 +266,6 @@ if(NOT BUSTED_OUTPUT_TYPE)
set(BUSTED_OUTPUT_TYPE "utfTerminal")
endif()
-# CMake is painful here. It will create the destination using the user's
-# current umask, and we don't want that. And we don't just want to install
-# the target directory, as it will mess with existing permissions. So this
-# seems like the best compromise. If we create it, then everyone can see it.
-# If it's preexisting, leave it alone.
include(InstallHelpers)
file(GLOB MANPAGES
@@ -281,24 +276,6 @@ install_helper(
FILES ${MANPAGES}
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
-install_helper(
- DIRECTORY runtime
- DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim)
-
-file(GLOB_RECURSE RUNTIME_PROGRAMS
- RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
- runtime/*.awk runtime/*.sh)
-
-foreach(PROG ${RUNTIME_PROGRAMS})
- get_filename_component(BASEDIR ${PROG} PATH)
- install_helper(PROGRAMS ${PROG} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/${BASEDIR})
-endforeach()
-
-configure_file(${PROJECT_SOURCE_DIR}/cmake/GenerateHelptags.cmake.in
- ${PROJECT_BINARY_DIR}/cmake/GenerateHelptags.cmake @ONLY)
-install(SCRIPT ${PROJECT_BINARY_DIR}/cmake/GenerateHelptags.cmake)
-
-
# Go down the tree.
add_subdirectory(src/nvim)
@@ -310,6 +287,7 @@ get_compile_flags(NVIM_VERSION_CFLAGS)
add_subdirectory(test/includes)
add_subdirectory(config)
add_subdirectory(test/functional/fixtures) # compile pty/shell test programs
+add_subdirectory(runtime)
# Setup some test-related bits. We do this after going down the tree because we
diff --git a/clint-ignored-files.txt b/clint-ignored-files.txt
index 2988b15fd2..98a26b7fbc 100644
--- a/clint-ignored-files.txt
+++ b/clint-ignored-files.txt
@@ -57,6 +57,7 @@ src/nvim/keymap.h
src/nvim/lib/khash.h
src/nvim/lib/klist.h
src/nvim/lib/kvec.h
+src/nvim/lib/queue.h
src/nvim/macros.h
src/nvim/main.c
src/nvim/main.h
diff --git a/clint.py b/clint.py
index 097b54f1c1..0eaab6e3f6 100755
--- a/clint.py
+++ b/clint.py
@@ -56,12 +56,15 @@ import sre_compile
import string
import sys
import unicodedata
+import json
+import collections # for defaultdict
_USAGE = """
Syntax: clint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
[--counting=total|toplevel|detailed] [--root=subdir]
- [--linelength=digits]
+ [--linelength=digits] [--record-errors=file]
+ [--suppress-errors=file]
<file> [file] ...
The style guidelines this tries to follow are those in
@@ -156,6 +159,13 @@ Syntax: clint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
Examples:
--extensions=hpp,cpp
+
+ record-errors=file
+ Record errors to the given location. This file may later be used for error
+ suppression using suppress-errors flag.
+
+ suppress-errors=file
+ Errors listed in the given file will not be reported.
"""
# We categorize each error message we print. Here are the categories.
@@ -270,6 +280,10 @@ _RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?')
# on which those errors are expected and should be suppressed.
_error_suppressions = {}
+# {(str, int)}: a set of error categories and line numbers which are expected to
+# be suppressed
+_error_suppressions_2 = set()
+
# The allowed line length of files.
# This is set by --linelength flag.
_line_length = 80
@@ -309,11 +323,30 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
'Unknown NOLINT error category: %s' % category)
+def ParseKnownErrorSuppressions(filename, raw_lines, linenum):
+ """Updates the global list of error-suppressions from suppress-file.
+
+ Args:
+ filename: str, the name of the input file.
+ raw_lines: list, all file lines
+ linenum: int, the number of the current line.
+ """
+ key = tuple(raw_lines[linenum - 1 if linenum else 0:linenum + 2])
+ if key in _cpplint_state.suppressed_errors[filename]:
+ for category in _cpplint_state.suppressed_errors[filename][key]:
+ _error_suppressions_2.add((category, linenum))
+
+
def ResetNolintSuppressions():
"Resets the set of NOLINT suppressions to empty."
_error_suppressions.clear()
+def ResetKnownErrorSuppressions():
+ "Resets the set of suppress-errors=file suppressions to empty."
+ _error_suppressions_2.clear()
+
+
def IsErrorSuppressedByNolint(category, linenum):
"""Returns true if the specified error category is suppressed on this line.
@@ -330,6 +363,19 @@ def IsErrorSuppressedByNolint(category, linenum):
linenum in _error_suppressions.get(None, set()))
+def IsErrorInSuppressedErrorsList(category, linenum):
+ """Returns true if the specified error is suppressed by suppress-errors=file
+
+ Args:
+ category: str, the category of the error.
+ linenum: int, the current line number.
+ Returns:
+ bool, True iff the error should be suppressed due to presense in
+ suppressions file.
+ """
+ return (category, linenum) in _error_suppressions_2
+
+
def Match(pattern, s):
"""Matches the string with the pattern, caching the compiled regexp."""
# The regexp compilation caching is inlined in both Match and Search for
@@ -454,6 +500,10 @@ class _CppLintState(object):
# "vs7" - format that Microsoft Visual Studio 7 can parse
self.output_format = 'emacs'
+ self.record_errors_file = None
+ self.suppressed_errors = collections.defaultdict(
+ lambda: collections.defaultdict(set))
+
def SetOutputFormat(self, output_format):
"""Sets the output format for errors."""
self.output_format = output_format
@@ -517,6 +567,25 @@ class _CppLintState(object):
(category, count))
sys.stderr.write('Total errors found: %d\n' % self.error_count)
+ def SuppressErrorsFrom(self, fname):
+ """Open file and read a list of suppressed errors from it"""
+ if fname is None:
+ return
+ try:
+ with open(fname) as fp:
+ for line in fp:
+ fname, lines, category = json.loads(line)
+ lines = tuple(lines)
+ self.suppressed_errors[fname][lines].add(category)
+ except IOError:
+ pass
+
+ def RecordErrorsTo(self, fname):
+ """Open file with suppressed errors for writing"""
+ if fname is None:
+ return
+ self.record_errors_file = open(fname, 'w')
+
_cpplint_state = _CppLintState()
@@ -545,6 +614,16 @@ def _SetCountingStyle(level):
_cpplint_state.SetCountingStyle(level)
+def _SuppressErrorsFrom(fname):
+ """Sets the file containing suppressed errors."""
+ _cpplint_state.SuppressErrorsFrom(fname)
+
+
+def _RecordErrorsTo(fname):
+ """Sets the file containing suppressed errors to write to."""
+ _cpplint_state.RecordErrorsTo(fname)
+
+
def _Filters():
"""Returns the module's list of output filters, as a list."""
return _cpplint_state.filters
@@ -687,6 +766,8 @@ def _ShouldPrintError(category, confidence, linenum):
# the verbosity level isn't high enough, or the filters filter it out.
if IsErrorSuppressedByNolint(category, linenum):
return False
+ if IsErrorInSuppressedErrorsList(category, linenum):
+ return False
if confidence < _cpplint_state.verbose_level:
return False
@@ -2986,6 +3067,23 @@ def ProcessFileData(filename, file_extension, lines, error,
nesting_state = _NestingState()
ResetNolintSuppressions()
+ ResetKnownErrorSuppressions()
+
+ for line in range(1, len(lines)):
+ ParseKnownErrorSuppressions(filename, lines, line)
+
+ if _cpplint_state.record_errors_file:
+ raw_lines = lines[:]
+
+ def RecordedError(filename, linenum, category, confidence, message):
+ if not IsErrorSuppressedByNolint(category, linenum):
+ key = raw_lines[linenum - 1 if linenum else 0:linenum + 2]
+ err = [filename, key, category]
+ json.dump(err, _cpplint_state.record_errors_file)
+ _cpplint_state.record_errors_file.write('\n')
+ Error(filename, linenum, category, confidence, message)
+
+ error = RecordedError
if file_extension == 'h':
CheckForHeaderGuard(filename, lines, error)
@@ -3113,7 +3211,9 @@ def ParseArguments(args):
'filter=',
'root=',
'linelength=',
- 'extensions='])
+ 'extensions=',
+ 'record-errors=',
+ 'suppress-errors='])
except getopt.GetoptError:
PrintUsage('Invalid arguments.')
@@ -3121,6 +3221,8 @@ def ParseArguments(args):
output_format = _OutputFormat()
filters = ''
counting_style = ''
+ record_errors_file = None
+ suppress_errors_file = None
for (opt, val) in opts:
if opt == '--help':
@@ -3153,6 +3255,10 @@ def ParseArguments(args):
_valid_extensions = set(val.split(','))
except ValueError:
PrintUsage('Extensions must be comma separated list.')
+ elif opt == '--record-errors':
+ record_errors_file = val
+ elif opt == '--suppress-errors':
+ suppress_errors_file = val
if not filenames:
PrintUsage('No files were specified.')
@@ -3161,6 +3267,8 @@ def ParseArguments(args):
_SetVerboseLevel(verbosity)
_SetFilters(filters)
_SetCountingStyle(counting_style)
+ _SuppressErrorsFrom(suppress_errors_file)
+ _RecordErrorsTo(record_errors_file)
return filenames
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
new file mode 100644
index 0000000000..3e90690c37
--- /dev/null
+++ b/runtime/CMakeLists.txt
@@ -0,0 +1,90 @@
+set(SYN_VIM_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genvimvim.lua)
+set(GENERATED_RUNTIME_DIR ${PROJECT_BINARY_DIR}/runtime)
+set(GENERATED_SYN_VIM ${GENERATED_RUNTIME_DIR}/syntax/vim/generated.vim)
+set(GENERATED_HELP_TAGS ${GENERATED_RUNTIME_DIR}/doc/tags)
+
+file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR})
+file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR}/syntax)
+file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR}/syntax/vim)
+
+add_custom_command(OUTPUT ${GENERATED_SYN_VIM}
+ COMMAND ${LUA_PRG} ${SYN_VIM_GENERATOR}
+ ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_SYN_VIM}
+ DEPENDS
+ ${SYN_VIM_GENERATOR}
+ ${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua
+ ${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua
+ ${PROJECT_SOURCE_DIR}/src/nvim/options.lua
+ ${PROJECT_SOURCE_DIR}/src/nvim/eval.c
+)
+
+file(GLOB DOCFILES ${PROJECT_SOURCE_DIR}/runtime/doc/*.txt)
+
+set(BUILDDOCFILES)
+foreach(DF ${DOCFILES})
+ get_filename_component(F ${DF} NAME)
+ list(APPEND BUILDDOCFILES ${GENERATED_RUNTIME_DIR}/doc/${F})
+endforeach()
+
+add_custom_command(OUTPUT ${BUILDDOCFILES}
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc
+ DEPENDS
+ ${DOCFILES})
+
+add_custom_command(OUTPUT ${GENERATED_HELP_TAGS}
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc
+ COMMAND "${PROJECT_BINARY_DIR}/bin/nvim"
+ -u NONE
+ -i NONE
+ -esX
+ -c "helptags ++t ."
+ -c quit
+ DEPENDS
+ ${BUILDDOCFILES}
+ nvim
+ WORKING_DIRECTORY "${GENERATED_RUNTIME_DIR}/doc"
+)
+
+add_custom_target(
+ runtime ALL
+ DEPENDS
+ ${GENERATED_SYN_VIM}
+ ${GENERATED_HELP_TAGS}
+)
+
+# CMake is painful here. It will create the destination using the user's
+# current umask, and we don't want that. And we don't just want to install
+# the target directory, as it will mess with existing permissions. So this
+# seems like the best compromise. If we create it, then everyone can see it.
+# If it's preexisting, leave it alone.
+
+install_helper(
+ FILES ${GENERATED_HELP_TAGS} ${BUILDDOCFILES}
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/doc)
+
+install_helper(
+ FILES ${GENERATED_SYN_VIM}
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/syntax/vim)
+
+file(GLOB_RECURSE RUNTIME_PROGRAMS
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ *.awk *.sh *.bat)
+
+foreach(PROG ${RUNTIME_PROGRAMS})
+ get_filename_component(BASEDIR ${PROG} PATH)
+ install_helper(PROGRAMS ${PROG}
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/${BASEDIR})
+endforeach()
+
+file(GLOB_RECURSE RUNTIME_FILES
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ *.vim *.dict *.py *.ps *.tutor)
+list(APPEND RUNTIME_FILES macros/dvorak)
+
+foreach(F ${RUNTIME_FILES})
+ get_filename_component(BASEDIR ${F} PATH)
+ install_helper(FILES ${F}
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/${BASEDIR})
+endforeach()
diff --git a/runtime/autoload/phpcomplete.vim b/runtime/autoload/phpcomplete.vim
index b014b4cdcf..5ddad88873 100644
--- a/runtime/autoload/phpcomplete.vim
+++ b/runtime/autoload/phpcomplete.vim
@@ -3,7 +3,7 @@
" Maintainer: Dávid Szabó ( complex857 AT gmail DOT com )
" Previous Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl )
" URL: https://github.com/shawncplus/phpcomplete.vim
-" Last Change: 2014 Oct 02
+" Last Change: 2014 Dec 01
"
" OPTIONS:
"
@@ -1172,11 +1172,11 @@ function! phpcomplete#GetCurrentInstruction(line_number, col_number, phpbegin) "
" break if we are on a "naked" stop_char (operators, colon, openparent...)
if index(stop_chars, current_char) != -1
let do_break = 1
- " dont break does not look like a "->"
+ " dont break if it does look like a "->"
if (prev_char == '-' && current_char == '>') || (current_char == '-' && next_char == '>')
let do_break = 0
endif
- " dont break if its looks like a "::"
+ " dont break if it does look like a "::"
if (prev_char == ':' && current_char == ':') || (current_char == ':' && next_char == ':')
let do_break = 0
endif
@@ -1356,8 +1356,12 @@ function! phpcomplete#GetCallChainReturnType(classname_candidate, class_candidat
endif
" make @return self, static, $this the same way
" (not exactly what php means by these)
- if returnclass == 'self' || returnclass == 'static' || returnclass == '$this'
- let classname_candidate = a:classname_candidate
+ if returnclass == 'self' || returnclass == 'static' || returnclass == '$this' || returnclass == 'self[]' || returnclass == 'static[]' || returnclass == '$this[]'
+ if returnclass =~ '\[\]$'
+ let classname_candidate = a:classname_candidate.'[]'
+ else
+ let classname_candidate = a:classname_candidate
+ endif
let class_candidate_namespace = a:class_candidate_namespace
else
let [classname_candidate, class_candidate_namespace] = phpcomplete#ExpandClassName(returnclass, fullnamespace, a:imports)
@@ -1527,7 +1531,7 @@ function! phpcomplete#GetClassName(start_line, context, current_namespace, impor
let function_boundary = phpcomplete#GetCurrentFunctionBoundaries()
let search_end_line = max([1, function_boundary[0][0]])
" -1 makes us ignore the current line (where the completion was invoked
- let lines = reverse(getline(search_end_line, line('.') - 1))
+ let lines = reverse(getline(search_end_line, a:start_line - 1))
" check Constant lookup
let constant_object = matchstr(a:context, '\zs'.class_name_pattern.'\ze::')
@@ -1638,9 +1642,32 @@ function! phpcomplete#GetClassName(start_line, context, current_namespace, impor
" assignment for the variable in question with a variable on the right hand side
if line =~# '^\s*'.object.'\s*=&\?\s*'.variable_name_pattern
- let tailing_semicolon = match(line, ';\s*$')
- let tailing_semicolon = tailing_semicolon != -1 ? tailing_semicolon : strlen(getline(a:start_line - i))
- let prev_context = phpcomplete#GetCurrentInstruction(a:start_line - i, tailing_semicolon - 1, b:phpbegin)
+
+ " try to find the next non-comment or string ";" char
+ let start_col = match(line, '^\s*'.object.'\C\s*=\zs&\?\s*'.variable_name_pattern)
+ let filelines = reverse(lines)
+ let [pos, char] = s:getNextCharWithPos(filelines, [a:start_line - i - 1, start_col])
+ let chars_read = 1
+ " read while end of the file
+ while char != 'EOF' && chars_read < 1000
+ let last_pos = pos
+ let [pos, char] = s:getNextCharWithPos(filelines, pos)
+ let chars_read += 1
+ " we got a candidate
+ if char == ';'
+ let synIDName = synIDattr(synID(pos[0] + 1, pos[1] + 1, 0), 'name')
+ " it's not a comment or string, end search
+ if synIDName !~? 'comment\|string'
+ break
+ endif
+ endif
+ endwhile
+
+ let prev_context = phpcomplete#GetCurrentInstruction(last_pos[0] + 1, last_pos[1], b:phpbegin)
+ if prev_context == ''
+ " cannot get previous context give up
+ return
+ endif
let prev_class = phpcomplete#GetClassName(a:start_line - i, prev_context, a:current_namespace, a:imports)
if stridx(prev_class, '\') != -1
@@ -1656,9 +1683,32 @@ function! phpcomplete#GetClassName(start_line, context, current_namespace, impor
" assignment for the variable in question with a function on the right hand side
if line =~# '^\s*'.object.'\s*=&\?\s*'.function_invocation_pattern
- let tailing_semicolon = match(line, ';\s*$')
- let tailing_semicolon = tailing_semicolon != -1 ? tailing_semicolon : strlen(getline(a:start_line - i))
- let prev_context = phpcomplete#GetCurrentInstruction(a:start_line - i, tailing_semicolon - 1, b:phpbegin)
+
+ " try to find the next non-comment or string ";" char
+ let start_col = match(line, '\C^\s*'.object.'\s*=\zs&\?\s*'.function_invocation_pattern)
+ let filelines = reverse(lines)
+ let [pos, char] = s:getNextCharWithPos(filelines, [a:start_line - i - 1, start_col])
+ let chars_read = 1
+ " read while end of the file
+ while char != 'EOF' && chars_read < 1000
+ let last_pos = pos
+ let [pos, char] = s:getNextCharWithPos(filelines, pos)
+ let chars_read += 1
+ " we got a candidate
+ if char == ';'
+ let synIDName = synIDattr(synID(pos[0] + 1, pos[1] + 1, 0), 'name')
+ " it's not a comment or string, end search
+ if synIDName !~? 'comment\|string'
+ break
+ endif
+ endif
+ endwhile
+
+ let prev_context = phpcomplete#GetCurrentInstruction(last_pos[0] + 1, last_pos[1], b:phpbegin)
+ if prev_context == ''
+ " cannot get previous context give up
+ return
+ endif
let function_name = matchstr(prev_context, '^'.function_invocation_pattern.'\ze')
let function_name = matchstr(function_name, '^\zs.\+\ze\s*($') " strip the trailing (
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index d20b3a9bf1..5d1ce7896d 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -55,13 +55,21 @@ endif
let s:clipboard = {}
function! s:clipboard.get(reg)
- if s:selections[a:reg].owner > 0
- return s:selections[a:reg].data
+ let reg = a:reg == '"' ? '+' : a:reg
+ if s:selections[reg].owner > 0
+ return s:selections[reg].data
end
- return s:try_cmd(s:paste[a:reg])
+ return s:try_cmd(s:paste[reg])
endfunction
function! s:clipboard.set(lines, regtype, reg)
+ if a:reg == '"'
+ call s:clipboard.set(a:lines,a:regtype,'+')
+ if s:copy['*'] != s:copy['+']
+ call s:clipboard.set(a:lines,a:regtype,'*')
+ end
+ return 0
+ end
if s:cache_enabled == 0
call s:try_cmd(s:copy[a:reg], a:lines)
return 0
diff --git a/runtime/autoload/provider/script_host.py b/runtime/autoload/provider/script_host.py
index bb87f63873..96d70e0330 100644
--- a/runtime/autoload/provider/script_host.py
+++ b/runtime/autoload/provider/script_host.py
@@ -35,10 +35,6 @@ class ScriptHost(object):
# it seems some plugins assume 'sys' is already imported, so do it now
exec('import sys', self.module.__dict__)
self.legacy_vim = nvim.with_hook(LegacyEvalHook())
- if IS_PYTHON3:
- self.legacy_vim = self.legacy_vim.with_hook(
- neovim.DecodeHook(
- encoding=nvim.options['encoding']))
sys.modules['vim'] = self.legacy_vim
def setup(self, nvim):
@@ -96,10 +92,6 @@ class ScriptHost(object):
stop -= 1
fname = '_vim_pydo'
- # Python3 code (exec) must be a string, mixing bytes with
- # function_def would use bytes.__repr__ instead
- if isinstance and isinstance(code, bytes):
- code = code.decode(nvim.options['encoding'])
# define the function
function_def = 'def %s(line, linenr):\n %s' % (fname, code,)
exec(function_def, self.module.__dict__)
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index ddbdc2d7f2..64f6ddb759 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -81,7 +81,7 @@ function! remote#host#RegisterPlugin(host, path, specs)
endif
endfor
- if remote#host#IsRunning(a:host)
+ if has_key(s:hosts, a:host) && remote#host#IsRunning(a:host)
" For now we won't allow registration of plugins when the host is already
" running.
throw 'Host "'.a:host.'" is already running'
diff --git a/runtime/autoload/tutor.vim b/runtime/autoload/tutor.vim
new file mode 100644
index 0000000000..d2881f7f34
--- /dev/null
+++ b/runtime/autoload/tutor.vim
@@ -0,0 +1,346 @@
+" vim: fdm=marker et ts=4 sw=4
+
+" Setup: {{{1
+function! tutor#SetupVim()
+ if has('syntax')
+ if !exists('g:syntax_on') || g:syntax_on == 0
+ syntax on
+ endif
+ endif
+endfunction
+
+" Mappings: {{{1
+
+function! s:CheckMaps()
+ nmap
+endfunction
+
+function! s:MapKeyWithRedirect(key, cmd)
+ if maparg(a:key) !=# ''
+ redir => l:keys
+ silent call s:CheckMaps()
+ redir END
+ let l:key_list = split(l:keys, '\n')
+
+ let l:raw_map = filter(copy(l:key_list), "v:val =~# '\\* ".a:key."'")
+ if len(l:raw_map) == 0
+ exe "nnoremap <buffer> <expr> ".a:key." ".a:cmd
+ return
+ endif
+ let l:map_data = split(l:raw_map[0], '\s*')
+
+ exe "nnoremap <buffer> <expr> ".l:map_data[0]." ".a:cmd
+ else
+ exe "nnoremap <buffer> <expr> ".a:key." ".a:cmd
+ endif
+endfunction
+
+function! tutor#MouseDoubleClick()
+ if foldclosed(line('.')) > -1
+ normal! zo
+ else
+ if match(getline('.'), '^#\{1,} ') > -1
+ normal! zc
+ else
+ call tutor#FollowLink(0)
+ endif
+ endif
+endfunction
+
+function! tutor#InjectCommand()
+ let l:cmd = substitute(getline('.'), '^\s*', '', '')
+ exe l:cmd
+ redraw | echohl WarningMsg | echon "tutor: ran" | echohl None | echon " " | echohl Statement | echon l:cmd
+endfunction
+
+function! tutor#SetNormalMappings()
+ call s:MapKeyWithRedirect('l', 'tutor#ForwardSkipConceal(v:count1)')
+ call s:MapKeyWithRedirect('h', 'tutor#BackwardSkipConceal(v:count1)')
+ call s:MapKeyWithRedirect('<right>', 'tutor#ForwardSkipConceal(v:count1)')
+ call s:MapKeyWithRedirect('<left>', 'tutor#BackwardSkipConceal(v:count1)')
+
+ nnoremap <silent> <buffer> <CR> :call tutor#FollowLink(0)<cr>
+ nnoremap <silent> <buffer> <2-LeftMouse> :call tutor#MouseDoubleClick()<cr>
+ nnoremap <buffer> >> :call tutor#InjectCommand()<cr>
+endfunction
+
+function! tutor#SetSampleTextMappings()
+ noremap <silent> <buffer> A :if match(getline('.'), '^--->') > -1 \| call search('\s{\@=', 'Wc') \| startinsert \| else \| startinsert! \| endif<cr>
+ noremap <silent> <buffer> $ :if match(getline('.'), '^--->') > -1 \| call search('.\s{\@=', 'Wc') \| else \| call search('$', 'Wc') \| endif<cr>
+ onoremap <silent> <buffer> $ :if match(getline('.'), '^--->') > -1 \| call search('.\s{\@=', 'Wc') \| else \| call search('$', 'Wc') \| endif<cr>
+ noremap <silent> <buffer> ^ :if match(getline('.'), '^--->') > -1 \| call search('\(--->\s\)\@<=.', 'bcW') \| else \| call search('^', 'bcW') \|endif<cr>
+ onoremap <silent> <buffer> ^ :if match(getline('.'), '^--->') > -1 \| call search('\(--->\s\)\@<=.', 'bcW') \| else \| call search('^', 'bcW') \|endif<cr>
+ nmap <silent> <buffer> 0 ^<esc>
+ nmap <silent> <buffer> <Home> ^<esc>
+ nmap <silent> <buffer> <End> $
+ imap <silent> <buffer> <Home> <esc>^<esc>:startinsert<cr>
+ imap <silent> <buffer> <End> <esc>$:startinsert<cr>
+ noremap <silent> <buffer> I :exe "normal! 0" \| startinsert<cr>
+endfunction
+
+" Navigation: {{{1
+
+" taken from http://stackoverflow.com/a/24224578
+
+function! tutor#ForwardSkipConceal(count)
+ let cnt=a:count
+ let mvcnt=0
+ let c=col('.')
+ let l=line('.')
+ let lc=col('$')
+ let line=getline('.')
+ while cnt
+ if c>=lc
+ let mvcnt+=cnt
+ break
+ endif
+ if stridx(&concealcursor, 'n')==-1
+ let isconcealed=0
+ else
+ let [isconcealed, cchar, group] = synconcealed(l, c)
+ endif
+ if isconcealed
+ let cnt-=strchars(cchar)
+ let oldc=c
+ let c+=1
+ while c < lc
+ let [isconcealed2, cchar2, group2] = synconcealed(l, c)
+ if !isconcealed2 || cchar2 != cchar
+ break
+ endif
+ let c+= 1
+ endwhile
+ let mvcnt+=strchars(line[oldc-1:c-2])
+ else
+ let cnt-=1
+ let mvcnt+=1
+ let c+=len(matchstr(line[c-1:], '.'))
+ endif
+ endwhile
+ return mvcnt.'l'
+endfunction
+
+function! tutor#BackwardSkipConceal(count)
+ let cnt=a:count
+ let mvcnt=0
+ let c=col('.')
+ let l=line('.')
+ let lc=0
+ let line=getline('.')
+ while cnt
+ if c<=1
+ let mvcnt+=cnt
+ break
+ endif
+ if stridx(&concealcursor, 'n')==-1 || c == 0
+ let isconcealed=0
+ else
+ let [isconcealed, cchar, group]=synconcealed(l, c-1)
+ endif
+ if isconcealed
+ let cnt-=strchars(cchar)
+ let oldc=c
+ let c-=1
+ while c>1
+ let [isconcealed2, cchar2, group2] = synconcealed(l, c-1)
+ if !isconcealed2 || cchar2 != cchar
+ break
+ endif
+ let c-=1
+ endwhile
+ let c = max([c, 1])
+ let mvcnt+=strchars(line[c-1:oldc-2])
+ else
+ let cnt-=1
+ let mvcnt+=1
+ let c-=len(matchstr(line[:c-2], '.$'))
+ endif
+ endwhile
+ return mvcnt.'h'
+endfunction
+
+" Hypertext: {{{1
+
+function! tutor#FollowLink(force)
+ let l:stack_s = join(map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")'), '')
+ if l:stack_s =~# 'tutorLink'
+ let l:link_start = searchpairpos('\[', '', ')', 'nbcW')
+ let l:link_end = searchpairpos('\[', '', ')', 'ncW')
+ if l:link_start[0] == l:link_end[0]
+ let l:linkData = getline(l:link_start[0])[l:link_start[1]-1:l:link_end[1]-1]
+ else
+ return
+ endif
+ let l:target = matchstr(l:linkData, '(\@<=.*)\@=')
+ if a:force != 1 && match(l:target, '\*.\+\*') > -1
+ call cursor(l:link_start[0], l:link_end[1])
+ call search(l:target, '')
+ normal! ^
+ elseif a:force != 1 && match(l:target, '^@tutor:') > -1
+ let l:tutor = matchstr(l:target, '@tutor:\zs.*')
+ exe "Tutor ".l:tutor
+ else
+ exe "help ".l:target
+ endif
+ endif
+endfunction
+
+" Folding And Info: {{{1
+
+function! tutor#TutorFolds()
+ if getline(v:lnum) =~# '^#\{1,6}'
+ return ">". len(matchstr(getline(v:lnum), '^#\{1,6}'))
+ else
+ return "="
+ endif
+endfunction
+
+function! tutor#InfoText()
+ let l:info_parts = []
+ if exists('b:tutor_infofunc')
+ call add(l:info_parts, eval(b:tutor_infofunc.'()'))
+ endif
+ return join(l:info_parts, " ")
+endfunction
+
+" Marks {{{1
+function! tutor#PlaceXMarks()
+ call cursor(1, 1)
+ let b:tutor_sign_id = 1
+ while search('^--->', 'W') > 0
+ call tutor#CheckText(getline('.'))
+ let b:tutor_sign_id+=1
+ endwhile
+ call cursor(1, 1)
+endfunction
+
+function! tutor#CheckText(text)
+ if match(a:text, '{expect:ANYTHING}\s*$') == -1
+ if match(getline('.'), '^--->\s*$') > -1
+ exe "sign place ".b:tutor_sign_id." line=".line('.')." name=tutorbad buffer=".bufnr('%')
+ else
+ if match(getline('.'), '|expect:.\+|') == -1
+ let l:cur_text = matchstr(a:text, '---> \zs.\{-}\ze {expect:')
+ let l:expected_text = matchstr(a:text, '{expect:\zs.*\ze}\s*$')
+ else
+ let l:cur_text = matchstr(a:text, '---> \zs.\{-}\ze |expect:')
+ let l:expected_text = matchstr(a:text, '|expect:\zs.*\ze|\s*$')
+ endif
+ if l:cur_text ==# l:expected_text
+ exe "sign place ".b:tutor_sign_id." line=".line('.')." name=tutorok buffer=".bufnr('%')
+ else
+ exe "sign place ".b:tutor_sign_id." line=".line('.')." name=tutorbad buffer=".bufnr('%')
+ endif
+ endif
+ endif
+endfunction
+
+function! tutor#OnTextChanged()
+ let l:text = getline('.')
+ if match(l:text, '^--->') > -1
+ call tutor#CheckText(l:text)
+ endif
+endfunction
+
+" Tutor Cmd: {{{1
+
+function! s:Locale()
+ let l:lang = ""
+ if exists('v:lang') && v:lang =~ '\a\a'
+ let l:lang = v:lang
+ elseif $LC_ALL =~ '\a\a'
+ let l:lang = $LC_ALL
+ elseif $LANG =~ '\a\a'
+ let l:lang = $LANG
+ endif
+ return split(l:lang, '_')
+endfunction
+
+function! s:GlobPath(lp, pat)
+ if version >= 704 && has('patch279')
+ return globpath(a:lp, a:pat, 1, 1)
+ else
+ return split(globpath(a:lp, a:pat, 1), '\n')
+ endif
+endfunction
+
+function! s:Sort(a, b)
+ let mod_a = fnamemodify(a:a, ':t')
+ let mod_b = fnamemodify(a:b, ':t')
+ if mod_a == mod_b
+ let retval = 0
+ elseif mod_a > mod_b
+ if match(mod_a, '^vim-') > -1 && match(mod_b, '^vim-') == -1
+ let retval = -1
+ else
+ let retval = 1
+ endif
+ else
+ if match(mod_b, '^vim-') > -1 && match(mod_a, '^vim-') == -1
+ let retval = 1
+ else
+ let retval = -1
+ endif
+ endif
+ return retval
+endfunction
+
+function! s:GlobTutorials(name)
+ " search for tutorials:
+ " 1. non-localized
+ let l:tutors = s:GlobPath(&rtp, 'tutor/'.a:name.'.tutor')
+ " 2. localized for current locale
+ let l:locale_tutors = s:GlobPath(&rtp, 'tutor/'.s:Locale()[0].'/'.a:name.'.tutor')
+ " 3. fallback to 'en'
+ if len(l:locale_tutors) == 0
+ let l:locale_tutors = s:GlobPath(&rtp, 'tutor/en/'.a:name.'.tutor')
+ endif
+ call extend(l:tutors, l:locale_tutors)
+ return uniq(sort(l:tutors, 's:Sort'), 's:Sort')
+endfunction
+
+function! tutor#TutorCmd(tutor_name)
+ if match(a:tutor_name, '[[:space:]]') > 0
+ echom "Only one argument accepted (check spaces)"
+ return
+ endif
+
+ if a:tutor_name == ''
+ let l:tutor_name = 'vim-01-beginner.tutor'
+ else
+ let l:tutor_name = a:tutor_name
+ endif
+
+ if match(l:tutor_name, '\.tutor$') > 0
+ let l:tutor_name = fnamemodify(l:tutor_name, ':r')
+ endif
+
+ let l:tutors = s:GlobTutorials(l:tutor_name)
+
+ if len(l:tutors) == 0
+ echom "No tutorial with that name found"
+ return
+ endif
+
+ if len(l:tutors) == 1
+ let l:to_open = l:tutors[0]
+ else
+ let l:idx = 0
+ let l:candidates = ['Several tutorials with that name found. Select one:']
+ for candidate in map(copy(l:tutors),
+ \'fnamemodify(v:val, ":h:h:t")."/".s:Locale()[0]."/".fnamemodify(v:val, ":t")')
+ let l:idx += 1
+ call add(l:candidates, l:idx.'. '.candidate)
+ endfor
+ let l:tutor_to_open = inputlist(l:candidates)
+ let l:to_open = l:tutors[l:tutor_to_open-1]
+ endif
+
+ exe "edit ".l:to_open
+endfunction
+
+function! tutor#TutorCmdComplete(lead,line,pos)
+ let l:tutors = s:GlobTutorials('*')
+ let l:names = uniq(sort(map(l:tutors, 'fnamemodify(v:val, ":t:r")'), 's:Sort'))
+ return join(l:names, "\n")
+endfunction
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 4dd515f3e0..813d741f5d 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -714,9 +714,6 @@ When the {string} starts with "\=" it is evaluated as an expression, see
characters.
Otherwise these characters in {string} have a special meaning:
- *:s%*
-When {string} is equal to "%" and '/' is included with the 'cpoptions' option,
-then the {string} of the previous substitute command is used, see |cpo-/|
magic nomagic action ~
& \& replaced with the whole matched pattern *s/\&*
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index 932d230a59..85f16ca8ca 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -54,8 +54,7 @@ history tables:
- one for debug mode commands
These are completely separate. Each history can only be accessed when
entering the same type of line.
-Use the 'history' option to set the number of lines that are remembered
-(default: 50).
+Use the 'history' option to set the number of lines that are remembered.
Notes:
- When you enter a command-line that is exactly the same as an older one, the
old one is removed (to avoid repeated commands moving older commands out of
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 63c27b2ff2..bb3d89e4ac 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -569,7 +569,10 @@ list of the current window.
Also see |++opt| and |+cmd|.
:[count]arga[dd] {name} .. *:arga* *:argadd* *E479*
- Add the {name}s to the argument list.
+:[count]arga[dd]
+ Add the {name}s to the argument list. When {name} is
+ omitted add the current buffer name to the argument
+ list.
If [count] is omitted, the {name}s are added just
after the current entry in the argument list.
Otherwise they are added after the [count]'th file.
@@ -579,7 +582,8 @@ list of the current window.
:argadd x a b x c
:0argadd x x a b c
:1argadd x a x b c
- :99argadd x a b c x
+ :$argadd x a b c x
+ :+2argadd y a b c x y
There is no check for duplicates, it is possible to
add a file to the argument list twice.
The currently edited file is not changed.
@@ -597,11 +601,19 @@ list of the current window.
Example: >
:argdel *.obj
-:{range}argd[elete] Delete the {range} files from the argument list.
+:[range]argd[elete] Delete the {range} files from the argument list.
+ Example: >
+ :10,$argdel
+< Deletes arguments 10 and further, keeping 1-9. >
+ :$argd
+< Deletes just the last one. >
+ :argd
+ :.argd
+< Deletes the current argument. >
+ :%argd
+< Removes all the files from the arglist.
When the last number in the range is too high, up to
- the last argument is deleted. Example: >
- :10,1000argdel
-< Deletes arguments 10 and further, keeping 1-9.
+ the last argument is deleted.
*:argu* *:argument*
:[count]argu[ment] [count] [++opt] [+cmd]
@@ -1018,7 +1030,7 @@ The names can be in upper- or lowercase.
:q[uit]! Quit without writing, also when currently visible
buffers have changes. Does not exit when this is the
- last window and there are is a changed hidden buffer.
+ last window and there is a changed hidden buffer.
In this case, the first changed hidden buffer becomes
the current buffer.
Use ":qall!" to exit always.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 6a0fef6d55..5c2b570695 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt* For Vim version 7.4. Last change: 2014 Nov 15
+*eval.txt* For Vim version 7.4. Last change: 2014 Nov 27
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1517,6 +1517,12 @@ v:mouse_col Column number for a mouse click obtained with |getchar()|.
This is the screen column number, like with |virtcol()|. The
value is zero when there was no mouse button click.
+ *v:msgpack_types* *msgpack_types-variable*
+v:msgpack_types Dictionary containing msgpack types used by |msgpackparse()|
+ and |msgpackdump()|. All types inside dictionary are fixed
+ (not editable) empty lists. To check whether some list is one
+ of msgpack types, use |is| operator.
+
*v:oldfiles* *oldfiles-variable*
v:oldfiles List of file names that is loaded from the |viminfo| file on
startup. These are the files that Vim remembers marks for.
@@ -1833,6 +1839,7 @@ getwinvar( {nr}, {varname} [, {def}])
any variable {varname} in window {nr}
glob( {expr} [, {nosuf} [, {list}]])
any expand file wildcards in {expr}
+glob2regpat( {expr}) String convert a glob pat into a search pat
globpath( {path}, {expr} [, {nosuf} [, {list}]])
String do glob({expr}) for all dirs in {path}
has( {feature}) Number TRUE if feature {feature} supported
@@ -1903,6 +1910,8 @@ min( {list}) Number minimum value of items in {list}
mkdir( {name} [, {path} [, {prot}]])
Number create directory {name}
mode( [expr]) String current editing mode
+msgpackdump( {list}) List dump a list of objects to msgpack
+msgpackparse( {list}) List parse msgpack to a list of objects
nextnonblank( {lnum}) Number line nr of non-blank line >= {lnum}
nr2char( {expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr}
or( {expr}, {expr}) Number bitwise OR
@@ -3302,6 +3311,17 @@ getchar([expr]) *getchar()*
: endif
: endwhile
:endfunction
+<
+ You may also receive syntetic characters, such as
+ |<CursorHold>|. Often you will want to ignore this and get
+ another character: >
+ :function GetKey()
+ : let c = getchar()
+ : while c == "\<CursorHold>"
+ : let c = getchar()
+ : endwhile
+ : return c
+ :endfunction
getcharmod() *getcharmod()*
The result is a Number which is the state of the modifiers for
@@ -3512,7 +3532,7 @@ getpos({expr}) Get the position for {expr}. For possible values of {expr}
This can be used to save and restore the position of a mark: >
let save_a_mark = getpos("'a")
...
- call setpos(''a', save_a_mark
+ call setpos("'a", save_a_mark)
< Also see |getcurpos()| and |setpos()|.
@@ -3646,6 +3666,14 @@ glob({expr} [, {nosuf} [, {list}]]) *glob()*
See |expand()| for expanding special Vim variables. See
|system()| for getting the raw output of an external command.
+glob2regpat({expr}) *glob2regpat()*
+ Convert a file pattern, as used by glob(), into a search
+ pattern. The result can be used to match with a string that
+ is a file name. E.g. >
+ if filename =~ glob2regpat('Make*.mak')
+< This is equivalent to: >
+ if filename =~ '^Make.*\.mak$'
+<
globpath({path}, {expr} [, {nosuf} [, {list}]]) *globpath()*
Perform glob() on all directories in {path} and concatenate
the results. Example: >
@@ -4564,15 +4592,16 @@ mkdir({name} [, {path} [, {prot}]])
If {prot} is given it is used to set the protection bits of
the new directory. The default is 0755 (rwxr-xr-x: r/w for
the user readable for others). Use 0700 to make it unreadable
- for others. This is only used for the last part of {name}.
- Thus if you create /tmp/foo/bar then /tmp/foo will be created
- with 0755.
- Example: >
+ for others.
+ {Nvim}
+ {prot} is applied for all parts of {name}. Thus if you create
+ /tmp/foo/bar then /tmp/foo will be created with 0700. Example: >
:call mkdir($HOME . "/tmp/foo/bar", "p", 0700)
< This function is not available in the |sandbox|.
- Not available on all systems. To check use: >
- :if exists("*mkdir")
-<
+
+ If you try to create an existing directory with {path} set to
+ "p" mkdir() will silently exit.
+
*mode()*
mode([expr]) Return a string that indicates the current mode.
If [expr] is supplied and it evaluates to a non-zero Number or
@@ -4604,6 +4633,92 @@ mode([expr]) Return a string that indicates the current mode.
"c" or "n".
Also see |visualmode()|.
+msgpackdump({list}) {Nvim} *msgpackdump()*
+ Convert a list of VimL objects to msgpack. Returned value is
+ |readfile()|-style list. Example: >
+ call writefile(msgpackdump([{}]), 'fname.mpack', 'b')
+< This will write the single 0x80 byte to `fname.mpack` file
+ (dictionary with zero items is represented by 0x80 byte in
+ messagepack).
+
+ Limitations:
+ 1. |Funcref|s cannot be dumped.
+ 2. Containers that reference themselves cannot be dumped.
+ 3. Dictionary keys are always dumped as STR strings.
+ 4. Other strings are always dumped as BIN strings.
+ 5. Points 3. and 4. do not apply to |msgpack-special-dict|s.
+
+msgpackparse({list}) {Nvim} *msgpackparse()*
+ Convert a |readfile()|-style list to a list of VimL objects.
+ Example: >
+ let fname = expand('~/.nvim/shada/main.shada')
+ let mpack = readfile(fname, 'b')
+ let shada_objects = msgpackparse(mpack)
+< This will read ~/.nvim/shada/main.shada file to
+ `shada_objects` list.
+
+ Limitations:
+ 1. Mapping ordering is not preserved unless messagepack
+ mapping is dumped using generic mapping
+ (|msgpack-special-map|).
+ 2. Since the parser aims to preserve all data untouched
+ (except for 1.) some strings are parsed to
+ |msgpack-special-dict| format which is not convenient to
+ use.
+ *msgpack-special-dict*
+ Some messagepack strings may be parsed to special
+ dictionaries. Special dictionaries are dictionaries which
+
+ 1. Contain exactly two keys: `_TYPE` and `_VAL`.
+ 2. `_TYPE` key is one of the types found in |v:msgpack_types|
+ variable.
+ 3. Value for `_VAL` has the following format (Key column
+ contains name of the key from |v:msgpack_types|):
+
+ Key Value ~
+ nil Zero, ignored when dumping.
+ boolean One or zero. When dumping it is only checked that
+ value is a |Number|.
+ integer |List| with four numbers: sign (-1 or 1), highest two
+ bits, number with bits from 62nd to 31st, lowest 31
+ bits. I.e. to get actual number one will need to use
+ code like >
+ _VAL[0] * ((_VAL[1] << 62)
+ & (_VAL[2] << 31)
+ & _VAL[3])
+< Special dictionary with this type will appear in
+ |msgpackparse()| output under one of the following
+ circumstances:
+ 1. |Number| is 32-bit and value is either above
+ INT32_MAX or below INT32_MIN.
+ 2. |Number| is 64-bit and value is above INT64_MAX. It
+ cannot possibly be below INT64_MIN because msgpack
+ C parser does not support such values.
+ float |Float|. This value cannot possibly appear in
+ |msgpackparse()| output.
+ string |readfile()|-style list of strings. This value will
+ appear in |msgpackparse()| output if string contains
+ zero byte or if string is a mapping key and mapping is
+ being represented as special dictionary for other
+ reasons.
+ binary |readfile()|-style list of strings. This value will
+ appear in |msgpackparse()| output if binary string
+ contains zero byte.
+ array |List|. This value cannot appear in |msgpackparse()|
+ output.
+ *msgpack-special-map*
+ map |List| of |List|s with two items (key and value) each.
+ This value will appear in |msgpackparse()| output if
+ parsed mapping contains one of the following keys:
+ 1. Any key that is not a string (including keys which
+ are binary strings).
+ 2. String with NUL byte inside.
+ 3. Duplicate key.
+ 4. Empty key.
+ ext |List| with two values: first is a signed integer
+ representing extension type. Second is
+ |readfile()|-style list of strings.
+
nextnonblank({lnum}) *nextnonblank()*
Return the line number of the first line at or below {lnum}
that is not blank. Example: >
diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt
index 8c87e5e4ac..12fca33d64 100644
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -489,18 +489,6 @@ Pressing <F4> will start the menu. You can now use the cursor keys to select
a menu entry. Hit <Enter> to execute it. Hit <Esc> if you want to cancel.
This does require the |+menu| feature enabled at compile time.
- *tear-off-menus*
-GTK+ and Motif support Tear-off menus. These are sort of sticky menus or
-pop-up menus that are present all the time. If the resizing does not work
-correctly, this may be caused by using something like "Vim*geometry" in the
-defaults. Use "Vim.geometry" instead.
-
-The Win32 GUI version emulates Motif's tear-off menus. Actually, a Motif user
-will spot the differences easily, but hopefully they're just as useful. You
-can also use the |:tearoff| command together with |hidden-menus| to create
-floating menus that do not appear on the main menu bar.
-
-
5.2 Creating New Menus *creating-menus*
*:me* *:menu* *:noreme* *:noremenu*
@@ -750,8 +738,7 @@ nr Name Normal action ~
*hidden-menus* *win32-hidden-menus*
In the Win32 and GTK+ GUI, starting a menu name with ']' excludes that menu
-from the main menu bar. You must then use the |:popup| or |:tearoff| command
-to display it.
+from the main menu bar. You must then use the |:popup| command to display it.
*popup-menu*
You can define the special menu "PopUp". This is the menu that is displayed
diff --git a/runtime/doc/gui_w32.txt b/runtime/doc/gui_w32.txt
index 8132d47cf1..2bf4d72343 100644
--- a/runtime/doc/gui_w32.txt
+++ b/runtime/doc/gui_w32.txt
@@ -353,35 +353,6 @@ changes this.
When prepending ":browse" before file editing commands, a file requester is
used to allow you to select an existing file. See |:browse|.
-
-6.3 Tearoff Menus
-
-The Win32 GUI emulates Motif's tear-off menus. At the top of each menu you
-will see a small graphic "rip here" sign. Selecting it will cause a floating
-window to be created with the same menu entries on it. The floating menu can
-then be accessed just as if it was the original (including sub-menus), but
-without having to go to the menu bar each time.
-This is most useful if you find yourself using a command buried in a sub-menu
-over and over again.
-The tearoff menus can be positioned where you like, and always stay just above
-the Main Vim window. You can get rid of them by closing them as usual; they
-also of course close when you exit Vim.
-
- *:tearoff* *:te*
-:te[aroff] {name} Tear-off the menu {name}. The menu named must have at
- least one subentry, but need not appear on the
- menu-bar (see |win32-hidden-menus|).
-
-Example: >
- :tearoff File
-will make the "File" menu (if there is one) appear as a tearoff menu. >
-
- :amenu ]Toolbar.Make :make<CR>
- :tearoff ]Toolbar
-This creates a floating menu that doesn't exist on the main menu-bar.
-
-Note that a menu that starts with ']' will not be displayed.
-
==============================================================================
7. Command line arguments *gui-w32-cmdargs*
diff --git a/runtime/doc/indent.txt b/runtime/doc/indent.txt
index fc16b1a7e7..3f61e28651 100644
--- a/runtime/doc/indent.txt
+++ b/runtime/doc/indent.txt
@@ -1,4 +1,4 @@
-*indent.txt* For Vim version 7.4. Last change: 2014 Apr 23
+*indent.txt* For Vim version 7.4. Last change: 2014 Dec 06
VIM REFERENCE MANUAL by Bram Moolenaar
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 2338906db2..a1f593765f 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -1070,7 +1070,6 @@ tag command action ~
|:@| :@ execute contents of a register
|:@@| :@@ repeat the previous ":@"
|:Next| :N[ext] go to previous file in the argument list
-|:Print| :P[rint] print lines
|:append| :a[ppend] append text
|:abbreviate| :ab[breviate] enter abbreviation
|:abclear| :abc[lear] remove all abbreviations
@@ -1522,7 +1521,7 @@ tag command action ~
|:tab| :tab create new tab when opening new window
|:tag| :ta[g] jump to tag
|:tags| :tags show the contents of the tag stack
-|:tearoff| :te[aroff] tear-off a menu
+|:terminal| :te[rminal] open a terminal buffer
|:tfirst| :tf[irst] jump to first matching tag
|:throw| :th[row] throw an exception
|:tjump| :tj[ump] like ":tselect", but jump directly when there
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index d15f8b3dd3..0825ca8848 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -269,11 +269,6 @@ Vi "the original". Without further remarks this is the version
to. Only runs under Unix. Source code only available with a
license. More information on Vi can be found through:
http://vi-editor.org [doesn't currently work...]
- *Posix*
-Posix From the IEEE standard 1003.2, Part 2: Shell and utilities.
- Generally known as "Posix". This is a textual description of
- how Vi is supposed to work.
- See |posix-compliance|.
*Nvi*
Nvi The "New" Vi. The version of Vi that comes with BSD 4.4 and FreeBSD.
Very good compatibility with the original Vi, with a few extensions.
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 699915a86f..37e1235a81 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1132,9 +1132,7 @@ For starters: See section |40.2| in the user manual.
All user defined commands must start with an uppercase letter, to avoid
confusion with builtin commands. Exceptions are these builtin commands:
:Next
- :X
-They cannot be used for a user defined command. ":Print" is also an existing
-command, but it is deprecated and can be overruled.
+They cannot be used for a user defined command.
The other characters of the user command can be uppercase letters, lowercase
letters or digits. When using digits, note that other commands that take a
@@ -1154,7 +1152,6 @@ Example: >
:Renu " Means "Renumber"
:Ren " Error - ambiguous
:command Paste ...
- :P " The built-in :Print
It is recommended that full names for user-defined commands are used in
scripts.
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index 7f64168663..8e96aedba6 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -469,9 +469,7 @@ the macros ".IP", ".LP", etc. (These are nroff macros, so the dot must be in
the first column). A section boundary is also a paragraph boundary.
Note that a blank line (only containing white space) is NOT a paragraph
boundary.
-Also note that this does not include a '{' or '}' in the first column. When
-the '{' flag is in 'cpoptions' then '{' in the first column is used as a
-paragraph boundary |posix|.
+Note: this does not include a '{' or '}' in the first column.
*section*
A section begins after a form-feed (<C-L>) in the first column and at each of
diff --git a/runtime/doc/nvim.txt b/runtime/doc/nvim.txt
new file mode 100644
index 0000000000..a7c512d1dc
--- /dev/null
+++ b/runtime/doc/nvim.txt
@@ -0,0 +1,24 @@
+*nvim.txt* For Nvim. {Nvim}
+
+
+ NVIM REFERENCE MANUAL *nvim*
+
+
+Introduction to Nvim *nvim-intro*
+
+This is an introduction for Vim users who are just getting started with Nvim.
+It is not meant for Vim beginners. For a basic introduction to Vim,
+see |help.txt|.
+
+1. Transitioning from Vim |nvim-from-vim|
+2. Differences from Vim |vim-differences|
+3. Msgpack-RPC |msgpack-rpc|
+4. Job control |job-control|
+5. Python plugins |nvim-python|
+6. Clipboard integration |nvim-clipboard|
+7. Remote plugins |remote-plugin|
+8. Provider infrastructure |nvim-provider|
+9. Integrated terminal emulator |nvim-terminal-emulator|
+
+==============================================================================
+ vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/nvim_from_vim.txt b/runtime/doc/nvim_from_vim.txt
new file mode 100644
index 0000000000..220e67d0e7
--- /dev/null
+++ b/runtime/doc/nvim_from_vim.txt
@@ -0,0 +1,49 @@
+*nvim_from_vim.txt* For Nvim. {Nvim}
+
+
+ NVIM REFERENCE MANUAL
+
+
+Transitioning from Vim *nvim-from-vim*
+
+Nvim is emphatically a fork of Vim, so compatibility to Vim should be pretty
+good.
+
+To start the transition, link your previous configuration so Nvim can use
+it:
+>
+ ln -s ~/.vimrc ~/.nvimrc
+ ln -s ~/.vim ~/.nvim
+<
+See |nvim-intro|, especially |nvim-python| and |nvim-clipboard|, for
+additional software you might need to install to use all of Nvim's features.
+
+Your Vim configuration might not be entirely compatible with Nvim. For a
+full list of differences between Vim and Nvim, see |vim-differences|.
+
+The |'ttymouse'| option, for example, was removed from Nvim (mouse support
+should work without it). If you use the same |vimrc| for Vim and Nvim,
+consider guarding |'ttymouse'| in your configuration like so:
+>
+ if !has('nvim')
+ set ttymouse=xterm2
+ endif
+<
+Conversely, if you have Nvim specific configuration items, you could do
+this:
+>
+ if has('nvim')
+ tnoremap <Esc> <C-\><C-n>
+ endif
+<
+For a more granular approach, use |exists()|:
+>
+ if exists(':tnoremap')
+ tnoremap <Esc> <C-\><C-n>
+ endif
+<
+Now you should be able to explore Nvim more comfortably. Check |nvim| for more
+information.
+
+==============================================================================
+ vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/nvim_intro.txt b/runtime/doc/nvim_intro.txt
deleted file mode 100644
index 40f65620af..0000000000
--- a/runtime/doc/nvim_intro.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-*nvim_intro.txt* For Nvim. {Nvim}
-
-
- NVIM REFERENCE MANUAL by Thiago de Arruda
-
-
-Introduction to Nvim *nvim* *nvim-intro*
-
-This is an introduction for Vim users who are just getting started with Nvim.
-It is not meant for Vim beginners. For a basic introduction to Vim,
-see |help.txt|.
-
-For now, it is just an index with the most relevant topics/features that
-differentiate Nvim from Vim:
-
-1. Differences from Vim |vim-differences|
-2. Msgpack-RPC |msgpack-rpc|
-3. Job control |job-control|
-4. Python plugins |nvim-python|
-5. Clipboard integration |nvim-clipboard|
-6. Remote plugins |remote-plugin|
-7. Provider infrastructure |nvim-provider|
-8. Integrated terminal emulator |nvim-terminal-emulator|
-
-==============================================================================
- vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/nvim_python.txt b/runtime/doc/nvim_python.txt
index a93e89303c..1c345b4532 100644
--- a/runtime/doc/nvim_python.txt
+++ b/runtime/doc/nvim_python.txt
@@ -70,7 +70,7 @@ To disable Python 2 interface, set `g:loaded_python_provider` to 1:
<
*g:loaded_python3_provider*
-To disable Python 3 interface, set `g:loaded_python3_provider` to 0:
+To disable Python 3 interface, set `g:loaded_python3_provider` to 1:
>
let g:loaded_python3_provider = 1
<
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 6c184a5a59..e8c844f7d2 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1402,8 +1402,8 @@ A jump table for the options with a short description can be found at |Q_op|.
register '*' for all yank, delete, change and put
operations which would normally go to the unnamed
register. When "unnamed" is also included to the
- option, yank operations (but not delete, change or
- put) will additionally copy the text into register
+ option, yank and delete operations (but not put)
+ will additionally copy the text into register
'*'. See |nvim-clipboard|.
<
*clipboard-autoselect*
@@ -1427,35 +1427,6 @@ A jump table for the options with a short description can be found at |Q_op|.
autoselectml Like "autoselect", but for the modeless selection
only. Compare to the 'A' flag in 'guioptions'.
- *clipboard-html*
- html When the clipboard contains HTML, use this when
- pasting. When putting text on the clipboard, mark it
- as HTML. This works to copy rendered HTML from
- Firefox, paste it as raw HTML in Vim, select the HTML
- in Vim and paste it in a rich edit box in Firefox.
- You probably want to add this only temporarily,
- possibly use BufEnter autocommands.
- Only supported for GTK version 2 and later.
- Only available with the |+multi_byte| feature.
-
- *clipboard-exclude*
- exclude:{pattern}
- Defines a pattern that is matched against the name of
- the terminal 'term'. If there is a match, no
- connection will be made to the X server. This is
- useful in this situation:
- - Running Vim in a console.
- - $DISPLAY is set to start applications on another
- display.
- - You do not want to connect to the X server in the
- console, but do want this in a terminal emulator.
- To never connect to the X server use: >
- exclude:.*
- The value of 'magic' is ignored, {pattern} is
- interpreted as if 'magic' was on.
- The rest of the option value will be used for
- {pattern}, this must be the last entry.
-
*'cmdheight'* *'ch'*
'cmdheight' 'ch' number (default 1)
global
@@ -1493,8 +1464,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'columns' 'co' number (default 80 or terminal width)
global
Number of columns of the screen. Normally this is set by the terminal
- initialization and does not have to be set by hand. Also see
- |posix-screen-size|.
+ initialization and does not have to be set by hand.
When Vim is running in the GUI or in a resizable window, setting this
option will cause the window size to be changed. When you only want
to use the size for the GUI, put the command in your |gvimrc| file.
@@ -1701,10 +1671,6 @@ A jump table for the options with a short description can be found at |Q_op|.
Commas can be added for readability.
To avoid problems with flags that are added in the future, use the
"+=" and "-=" feature of ":set" |add-option-flags|.
- NOTE: This option is set to the POSIX default value at startup when
- the Vi default value would be used and the $VIM_POSIX environment
- variable exists |posix|. This means Vim tries to behave like the
- POSIX specification.
contains behavior ~
*cpo-a*
@@ -1802,7 +1768,6 @@ A jump table for the options with a short description can be found at |Q_op|.
See |/[]|
'l' included: "/[ \t]" finds <Space>, '\' and 't'
'l' excluded: "/[ \t]" finds <Space> and <Tab>
- Also see |cpo-\|.
*cpo-L*
L When the 'list' option is set, 'wrapmargin',
'textwidth', 'softtabstop' and Virtual Replace mode
@@ -1942,38 +1907,6 @@ A jump table for the options with a short description can be found at |Q_op|.
the cursor would skip over it and jump to the
following occurrence.
- POSIX flags. These are not included in the Vi default value, except
- when $VIM_POSIX was set on startup. |posix|
-
- contains behavior ~
- *cpo-#*
- # A count before "D", "o" and "O" has no effect.
- *cpo-&*
- & When ":preserve" was used keep the swap file when
- exiting normally while this buffer is still loaded.
- This flag is tested when exiting.
- *cpo-\*
- \ Backslash in a [] range in a search pattern is taken
- literally, only "\]" is special See |/[]|
- '\' included: "/[ \-]" finds <Space>, '\' and '-'
- '\' excluded: "/[ \-]" finds <Space> and '-'
- Also see |cpo-l|.
- *cpo-/*
- / When "%" is used as the replacement string in a |:s|
- command, use the previous replacement string. |:s%|
- *cpo-{*
- { The |{| and |}| commands also stop at a "{" character
- at the start of a line.
- *cpo-.*
- . The ":chdir" and ":cd" commands fail if the current
- buffer is modified, unless ! is used. Vim doesn't
- need this, since it remembers the full path of an
- opened file.
- *cpo-bar*
- | The value of the $LINES and $COLUMNS environment
- variables overrule the terminal size values obtained
- with system specific functions.
-
*'cryptmethod'* *'cm'*
'cryptmethod' Removed. |vim-differences| {Nvim}
@@ -3256,8 +3189,8 @@ A jump table for the options with a short description can be found at |Q_op|.
screen.
*'guioptions'* *'go'*
-'guioptions' 'go' string (default "egmrLtT" (MS-Windows),
- "aegimrLtT" (GTK, Motif and Athena))
+'guioptions' 'go' string (default "egmrLT" (MS-Windows),
+ "aegimrLT" (GTK, Motif and Athena))
global
{only available when compiled with GUI enabled}
This option only has an effect in the GUI version of Vim. It is a
@@ -3319,9 +3252,6 @@ A jump table for the options with a short description can be found at |Q_op|.
'g' Grey menu items: Make menu items that are not active grey. If
'g' is not included inactive menu items are not shown at all.
Exception: Athena will always use grey menu items.
- *'go-t'*
- 't' Include tearoff menu items. Currently only works for Win32,
- GTK+, and Motif 1.2 GUI.
*'go-T'*
'T' Include Toolbar. Currently only in Win32, GTK+, Motif,
and Athena GUIs.
@@ -3555,7 +3485,7 @@ A jump table for the options with a short description can be found at |Q_op|.
with the 'h' flag in 'viminfo' |viminfo-h|.
*'history'* *'hi'*
-'history' 'hi' number (Vim default: 50, Vi default: 0)
+'history' 'hi' number (Vim default: 10000, Vi default: 0)
global
A history of ":" commands, and a history of previous search patterns
is remembered. This option decides how many entries may be stored in
@@ -4160,7 +4090,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global
Number of lines of the Vim window.
Normally you don't need to set this. It is done automatically by the
- terminal initialization code. Also see |posix-screen-size|.
+ terminal initialization code.
When Vim is running in the GUI or in a resizable window, setting this
option will cause the window size to be changed. When you only want
to use the size for the GUI, put the command in your |gvimrc| file.
@@ -4770,6 +4700,8 @@ A jump table for the options with a short description can be found at |Q_op|.
*'paste'* *'nopaste'*
'paste' boolean (default off)
global
+ You probably don't have to set this option: |bracketed-paste-mode|.
+
Put Vim in Paste mode. This is useful if you want to cut or copy
some text from one window and paste it in Vim. This will avoid
unexpected effects.
@@ -5231,7 +5163,7 @@ A jump table for the options with a short description can be found at |Q_op|.
print/ files for printing |postscript-print-encoding|
spell/ spell checking files |spell|
syntax/ syntax files |mysyntaxfile|
- tutor/ files for vimtutor |tutor|
+ tutor/ tutorial files |:Tutor|
And any other file searched for with the |:runtime| command.
@@ -5633,8 +5565,7 @@ A jump table for the options with a short description can be found at |Q_op|.
function to get the effective shiftwidth value.
*'shortmess'* *'shm'*
-'shortmess' 'shm' string (Vim default "filnxtToO", Vi default: "",
- POSIX default: "A")
+'shortmess' 'shm' string (Vim default "filnxtToO", Vi default: "")
global
This option helps to avoid all the |hit-enter| prompts caused by file
messages, for example with CTRL-G, and to avoid some other messages.
diff --git a/runtime/doc/pi_tutor.txt b/runtime/doc/pi_tutor.txt
new file mode 100644
index 0000000000..7ed47b24dd
--- /dev/null
+++ b/runtime/doc/pi_tutor.txt
@@ -0,0 +1,50 @@
+*pi_tutor.txt* Interactive tutorials.
+*vim-tutor-mode*
+
+vim-tutor-mode provides a system to follow and create interactive tutorials
+for vim and third party plugins. It replaces the venerable `vimtutor` system.
+
+==============================================================================
+1. Usage *vim-tutor-usage*
+
+vim-tutor-mode tutorials are hypertext documents, they have rich text and
+contain links. To stand out from the rest of the text, links are underlined.
+You can follow them by placing the cursor over them and pressing <Enter>, or
+by double-clicking them.
+
+1.1 Commands
+------------
+ *:Tutor*
+:Tutor {tutorial} Opens a tutorial. Command-line completion for
+ {tutorial} is provided, the candidates are a list of
+ '.tutor' files found in the 'tutor/' folder in
+ the 'runtimepath'. Tutorials prefixed with 'vim-' will
+ always be shown first.
+
+ If no {tutorial} is provided, the command starts the
+ 'vim-01-beginner' tutorial, which is equivalent to
+ Vim's `vimtutor`.
+
+=============================================================================
+2. Creating tutorials *vim-tutor-create*
+
+Writing vim-tutor-mode tutorials is easy. For an overview of the format used,
+please consult the 'tutor.tutor' file: >
+
+ :Tutor tutor
+<
+New tutorials must be placed in the 'tutor/' folder in the 'runtimepath'
+to be detected by the :Tutor command.
+
+It is recommended to use a less formal style when writing tutorials than in
+regular documentation (unless the content requires it).
+
+============================================================================
+3. Contributing
+
+Development of the plugin is done over at github [1]. Feel free to report
+issues and make suggestions.
+
+[1]: https://github.com/fmoralesc/vim-tutor-mode
+
+" vim: set ft=help :
diff --git a/runtime/doc/recover.txt b/runtime/doc/recover.txt
index 53cb31f813..0b67732cd1 100644
--- a/runtime/doc/recover.txt
+++ b/runtime/doc/recover.txt
@@ -111,10 +111,6 @@ command:
*:pre* *:preserve* *E313* *E314*
:pre[serve] Write all text for all buffers into swap file. The
original file is no longer needed for recovery.
- This sets a flag in the current buffer. When the '&'
- flag is present in 'cpoptions' the swap file will not
- be deleted for this buffer when Vim exits and the
- buffer is still loaded |cpo-&|.
A Vim swap file can be recognized by the first six characters: "b0VIM ".
After that comes the version number, e.g., "3.0".
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 6bc1b2873c..88f23e6c76 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -1,4 +1,4 @@
-*syntax.txt* For Vim version 7.4. Last change: 2014 Sep 27
+*syntax.txt* For Vim version 7.4. Last change: 2014 Nov 19
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -5055,6 +5055,7 @@ This will set the "w:current_syntax" variable to "foo". The value of
restoring "b:current_syntax", since the syntax files do set
"b:current_syntax". The value set by the syntax file is assigned to
"w:current_syntax".
+Note: This resets the 'spell', 'spellcapcheck' and 'spellfile' options.
Once a window has its own syntax, syntax commands executed from other windows
on the same buffer (including :syntax clear) have no effect. Conversely,
diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt
index d7b9395aeb..3b8bf4507f 100644
--- a/runtime/doc/term.txt
+++ b/runtime/doc/term.txt
@@ -592,6 +592,19 @@ before using the mouse:
"g<LeftMouse>" is "<C-LeftMouse> (jump to tag under mouse click)
"g<RightMouse>" is "<C-RightMouse> ("CTRL-T")
+ *bracketed-paste-mode*
+Bracketed paste mode allows terminal emulators to distinguish between typed
+text and pasted text.
+
+For terminal emulators that support it, this mode is enabled by default. Thus
+you can paste text without Neovim giving any special meaning to it. Most
+notably it won't try reindenting those lines.
+
+If your terminal emulator doesn't support it yet, you can get the old Vim
+behaviour by enabling |'paste'| temporarily.
+
+NOTE: See https://cirw.in/blog/bracketed-paste for technical details.
+
*mouse-mode-table* *mouse-overview*
A short overview of what the mouse buttons do, when 'mousemodel' is "extend":
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 75585e878b..78ae536c5a 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1,4 +1,4 @@
-*todo.txt* For Vim version 7.4. Last change: 2014 Nov 19
+*todo.txt* For Vim version 7.4. Last change: 2014 Dec 06
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -34,9 +34,23 @@ not be repeated below, unless there is extra information.
*known-bugs*
-------------------- Known bugs and current work -----------------------
+Patch to fix list range assign crash. (Yukihiro Nakadaira, 2014 Dec 1)
+
+Patch to fix range with user command. (Marcin Szamotulski, 2014 Dec 2)
+Update Dec 6, with support for user commands.
+
+When window number in Ex range is too high, give an error?
+Only when backwards compatible.
+
+:s/\n// doesn't change anything. Since 7.4.232? (Eliseo Martínez, 2014 Nov
+28) Patch on Issue 287
+
+Using vim_snprintf() in window.c can be in a function.
+
Regexp problems:
- The NFA engine does not implement the time limit passed to
nfa_regexec_multi()
+- Very slow with a long line and Ruby highlighting. (John Whitley, 2014 Dec 4)
- Bug with pattern: '\vblock (\d+)\.\n.*\d+%(\1)@<!\.$'
(Lech Lorens, 2014 Feb 3)
- Issue 164: freeze on regexp search.
@@ -64,17 +78,11 @@ Breaks test_eval. Inefficient, can we only compute y_width when needed?
Problem that a previous silent ":throw" causes a following try/catch not to
work. (ZyX, 2013 Sep 28)
+Patch to fix recognizing function name. (Ozaki Kiichi, 2014 Nov 28)
+
":cd C:\Windows\System32\drivers\etc*" does not work, even though the
directory exists. (Sergio Gallelli, 2013 Dec 29)
-Patch by Marcin Szamotulski to add count to :close (2014 Aug 10, update Aug
-14, Aug 30)
- Make ":1close" close the first window.
- Make ":+1close" close the next window.
- Make ":-1close" close the previous window.
-Doesn't look right, asked for updates.
-Update 2014 Nov 8. Replied with suggestions.
-
The entries added by matchaddpos() are returned by getmatches() but can't be
set with setmatches(). (lcd47, 2014 Jun 29)
@@ -84,34 +92,34 @@ Problem using ":try" inside ":execute". (ZyX, 2013 Sep 15)
Python: ":py raw_input('prompt')" doesn't work. (Manu Hack)
-Patch to fix issue 78. (Christian Brabandt, 2014 Oct 8)
-
-Patch to fix leak in map() with error. (Christian Brabandt, 2014 Oct 11)
-
-Patch to fix incsearch for "2/pattern/e".
-
-Patch to fix memory leak in :hardcopy. (Christian Brabandt, 2014 Nov 16)
-
-Patch to fix warnings in if_ruby.c. (Ken Takata, 2014 Nov 17)
-
-Patch to make test 63 pass when in a B&W terminal. (Christian Brabandt, 2014
-Nov 15) Other patch (better) on Nov 17.
-
Change behavior of v:hlsearch? Patch from Christian, 2014 Oct 22.
+Patch to recover from X server restart: hint on Issue 203 (2014 Nov 21 18:44)
+
MS-Windows: When editing a file with a leading space, writing it uses the
wrong name. (Aram, 2014 Nov 7) Vim 7.4.
+Add LessCss support. (Jenoma / Alessandro Vioni, 2014 Nov 24)
+Now with updated license, Nov 24.
+
patch to remove FEAT_OSFILETYPE from fileio.c. (Christian, 2014 Nov 12)
Value returned by virtcol() changes depending on how lines wrap. This is
inconsistent with the documentation.
-Patch to fix relatie numbers. (Christian Brabandt, 2014 Nov 17)
+Ukrainian vimtutor. (Issue 288)
+
+Regenerate the Unicode tables in mbyte.c.
+Diff from ZyX, 2014 Dec 6.
+
+Patch to fix relative numbers. (Christian Brabandt, 2014 Nov 17)
+Update Nov 26.
Patch to fix wrong formatting if 'linebreak' is set. (Christian Brabandt, 2014
Nov 12)
+Patch to avoid recognizing polkit as hog files. (Issue 292)
+
Patch to support hex values for setting option value.
(Zyx, 2015 Nov 6)
@@ -122,17 +130,29 @@ Update Nov 5.
MS-Windows: Crash opening very long file name starting with "\\".
(Christian Brock, 2012 Jun 29)
+Cursorline background color not mixed with character highlight.
+Patch by Yasuhiro Matsumoto, 2014 Dec 3.
+
Problem using diff syntax with cp932 encoding. Idea from Yasuhiro Matsumoto,
patch from Ken Takata (2014 Nov 6)
ml_updatechunk() is slow when retrying for another encoding. (John Little,
2014 Sep 11)
+Patch to add a different escape sequence for replace mode.
+(Omar Sandoval, 2014 Nov 30)
+
+Patch to allow values greater than 255 for ctermfg/ctermbg on Windows.
+(Yasuhiro Matsumoto, 2014 Dec 5)
+
When 'balloonexpr' returns a list the result has a trailing newline.
Just remove one trailing newline. (lcd, 2014 Oct 17)
Make comments in the test Makefile silent. (Kartik Agaram, 2014 Sep 24)
+Result of systemlist() does not show whether text ended in line break.
+(Bjorn Linse, 2014 Nov 27)
+
When in 'comments' "n:x" follows after three-part comment directly it repeats
any one-character from the previous line. (Kartik Agaram, 2014 Sep 19)
@@ -147,6 +167,15 @@ Plugins need to make a lot of effort, lots of mappings, to know what happened
before pressing the key that triggers a plugin action. How about keeping the
last N pressed keys, so that they do not need to be mapped?
+":q!" should reset modified flag for current buffer, if another buffer is
+modified no need to abandon it again.
+Patch from Yasuhiro Matsumoto, 2014 Nov 21.
+Update from Hirohito Higashi, 2014 Nov 21.
+With test, Nov 23.
+
+Wrong scrolling when using incsearch. Patch by Christian Brabandt, 2014 Dec 4.
+Is this a good solution?
+
Can assign to s:type when a function s:type has been defined.
Also the other way around: define a function while a variable with that name
was already defined.
@@ -175,6 +204,7 @@ Bug: Autocompleting ":tag/pat" replaces "/pat" with a match but does not
insert a space. (Micha Mos, 2014 Nov 7)
Patch to add the :bvimgrep command. (Christian Brabandt, 2014 Nov 12)
+Update Dec 6.
Patch to add argument to :cquit. (Thinca, 2014 Oct 12)
@@ -287,6 +317,10 @@ Yasuhiro Matsumoto, 2013 May 31.
Or should we add a more general mechanism, like a lambda() function?
Patch by Yasuhiro Matsumoto, 2014 Sep 16.
+Patch to fix display of listchars on the cursorline. (Nayuri Aohime, 2013)
+Update suggested by Yasuhiro Matsumoto, 2014 Nov 25:
+https://gist.github.com/presuku/d3d6b230b9b6dcfc0477
+
Patch for XDG base directory support. (Jean François Bignolles, 2014 Mar 4)
Remark on the docs. Should not be a compile time feature. But then what?
@@ -537,6 +571,14 @@ MS-Windows resizing problems:
causes the window to move unnecessarily. (William E. Skeith III, 2012 Jan
12) Patch: 2012 Jan 13 Needs more work (2012 Feb 2)
+Patch to use Modern UI 2.0 for the Nsis installer. (Guopeng Wen, 2010 Jul 30)
+Latest version: 2011 May 18
+8 Windows install with NSIS: make it possible to do a silent install, see
+ http://nsis.sourceforge.net/Docs/Chapter4.html#4.12
+ Version from Guopeng Wen that does this (2010 Dec 27)
+Alternative: MSI installer: https://github.com/petrkle/vim-msi/
+Or the one on Issue 279
+
'iminsert' global value set when using ":setlocal iminsert"? (Wu, 2012 Jun 23)
Patch to append regexp to tag commands to make it possible to select one out
@@ -847,7 +889,7 @@ Assume the system converts between the actual encoding of the filesystem to
the system encoding (usually utf-8).
Patch to add GUI colors to the terminal, when it supports it. (ZyX, 2013 Jan
-26, update 2013 Dec 14)
+26, update 2013 Dec 14, another 2014 Nov 22)
Problem producing tags file when hebrew.frx is present. It has a BOM.
Results in E670. (Tony Mechelynck, 2010 May 2)
@@ -1479,13 +1521,6 @@ with "gvim -nb:localhost:55555:foo". From nc do: '1:editFile!0 "foo"'. Then
go to Insert mode and add a few lines. Then backspacing every other time
moves the cursor instead of deleting. (Chris Kaiser, 2007 Sep 25)
-Patch to use Modern UI 2.0 for the Nsis installer. (Guopeng Wen, 2010 Jul 30)
-Latest version: 2011 May 18
-8 Windows install with NSIS: make it possible to do a silent install, see
- http://nsis.sourceforge.net/Docs/Chapter4.html#4.12
- Version from Guopeng Wen that does this (2010 Dec 27)
-Alternative: MSI installer: https://github.com/petrkle/vim-msi/
-
Windows installer should install 32-bit version of right-click handler also on
64-bit systems. (Brian Cunningham, 2011 Dec 28)
@@ -1994,71 +2029,6 @@ Awaiting updated patches:
- Patch for "paranoid mode" by Kevin Collins, March 7. Needs much more work.
-Vi incompatibility:
-- Try new POSIX tests, made after my comments. (Geoff Clare, 2005 April 7)
- Version 1.5 is in ~/src/posix/1.5. (Lynne Canal)
-8 With undo/redo only marks in the changed lines should be changed. Other
- marks should be kept. Vi keeps each mark at the same text, even when it
- is deleted or restored. (Webb)
- Also: A mark is lost after: make change, undo, redo and undo.
- Example: "{d''" then "u" then "d''": deletes an extra line, because the ''
- position is one line down. (Veselinovic)
-8 When stdin is not a tty, and Vim reads commands from it, an error should
- make Vim exit.
-7 Unix Vim (not gvim): Typing CTRL-C in Ex mode should finish the line
- (currently you can continue typing, but it's truncated later anyway).
- Requires a way to make CTRL-C interrupt select() when in cooked input.
-8 When loading a file in the .exrc, Vi loads the argument anyway. Vim skips
- loading the argument if there is a file already. When no file argument
- given, Vi starts with an empty buffer, Vim keeps the loaded file. (Bearded)
-6 In Insert mode, when using <BS> or <Del>, don't wipe out the text, but
- only move back the cursor. Behaves like '$' in 'cpoptions'. Use a flag
- in 'cpoptions' to switch this on/off.
-8 When editing a file which is a symbolic link, and then opening another
- symbolic link on the same file, Vim uses the name of the first one.
- Adjust the file name in the buffer to the last one used? Use several file
- names in one buffer???
- Also: When first editing file "test", which is symlink to "test2", and
- then editing "test2", you end up editing buffer "test" again. It's not
- logical that the name that was first used sticks with the buffer.
-7 The ":undo" command works differently in Ex mode. Edit a file, make some
- changes, "Q", "undo" and _all_ changes are undone, like the ":visual"
- command was one command.
- On the other hand, an ":undo" command in an Ex script only undoes the last
- change (e.g., use two :append commands, then :undo).
-7 The ":map" command output overwrites the command. Perhaps it should keep
- the ":map" when it's used without arguments?
-7 CTRL-L is not the end of a section? It is for Posix! Make it an option.
-7 Implement 'prompt' option. Init to off when stdin is not a tty.
-7 CTRL-T in Insert mode inserts 'shiftwidth' of spaces at the cursor. Add a
- flag in 'cpoptions' for this.
-7 Add a way to send an email for a crashed edit session. Create a file when
- making changes (containing name of the swap file), delete it when writing
- the file. Supply a program that can check for crashed sessions (either
- all, for a system startup, or for one user, for in a .login file).
-7 Vi doesn't do autoindenting when input is not from a tty (in Ex mode).
-7 "z3<CR>" should still use the whole window, but only redisplay 3 lines.
-7 ":tag xx" should move the cursor to the first non-blank. Or should it go
- to the match with the tag? Option?
-7 Implement 'autoprint'/'ap' option.
-7 Add flag in 'cpoptions' that makes <BS> after a count work like <Del>
- (Sayre).
-7 Add flag in 'cpoptions' that makes operator (yank, filter) not move the
- cursor, at least when cancelled. (default Vi compatible).
-7 This Vi-trick doesn't work: "Q" to go to Ex mode, then "g/pattern/visual".
- In Vi you can edit in visual mode, and when doing "Q" you jump to the next
- match. Nvi can do it too.
-7 Support '\' for line continuation in Ex mode for these commands: (Luebking)
- g/./a\ g/pattern1/ s/pattern2/rep1\\
- line 1\ line 2\\
- line 2\ line 3\\
- . line4/
-6 ":e /tmp/$tty" doesn't work. ":e $uid" does. Is $tty not set because of
- the way the shell is started?
-6 Vi compatibility (optional): make "ia<CR><ESC>10." do the same strange
- thing. (only repeat insert for the first line).
-
-
MSDOS and Win32:
8 Should $USERPROFILE be preferred above $HOMEDRIVE/$HOMEPATH? No, but it's
a good fallback, thus use:
diff --git a/runtime/doc/usr_01.txt b/runtime/doc/usr_01.txt
index cdb3035a40..c6d363ad5f 100644
--- a/runtime/doc/usr_01.txt
+++ b/runtime/doc/usr_01.txt
@@ -70,52 +70,18 @@ If the file already exists you probably want to keep it.
For more info see |vimrc|.
==============================================================================
-*01.3* Using the Vim tutor *tutor* *vimtutor*
+*01.3* Using the Vim tutor *tutor* *vimtutor*
Instead of reading the text (boring!) you can use the vimtutor to learn your
first Vim commands. This is a 30 minute tutorial that teaches the most basic
Vim functionality hands-on.
-On Unix, if Vim has been properly installed, you can start it from the shell:
->
- vimtutor
+To start the tutorial, execute >
-On MS-Windows you can find it in the Program/Vim menu. Or execute
-vimtutor.bat in the $VIMRUNTIME directory.
-
-This will make a copy of the tutor file, so that you can edit it without
-the risk of damaging the original.
- There are a few translated versions of the tutor. To find out if yours is
-available, use the two-letter language code. For French: >
-
- vimtutor fr
-
-On Unix, if you prefer using the GUI version of Vim, use "gvimtutor" or
-"vimtutor -g", optionally with a two-letter language code.
-
-
-On other systems, you have to do a little work:
-
-1. Copy the tutor file. You can do this with Vim (it knows where to find it):
->
- vim -u NONE -c 'e $VIMRUNTIME/tutor/tutor' -c 'w! TUTORCOPY' -c 'q'
-<
- This will write the file "TUTORCOPY" in the current directory. To use a
-translated version of the tutor, append the two-letter language code to the
-filename. For French:
->
- vim -u NONE -c 'e $VIMRUNTIME/tutor/tutor.fr' -c 'w! TUTORCOPY' -c 'q'
+ :Tutor
<
-2. Edit the copied file with Vim:
->
- vim -u NONE TUTORCOPY
-<
- The extra arguments make sure Vim is started in a good mood.
+from within nvim. The tutorial will lead you from that point. Have fun!
-3. Delete the copied file when you are finished with it:
->
- del TUTORCOPY
-<
==============================================================================
*01.4* Copyright *manual-copyright*
diff --git a/runtime/doc/usr_02.txt b/runtime/doc/usr_02.txt
index ebb918d7ec..cd25b14e32 100644
--- a/runtime/doc/usr_02.txt
+++ b/runtime/doc/usr_02.txt
@@ -164,7 +164,7 @@ right and j points down. In a picture: >
The best way to learn these commands is by using them. Use the "i" command to
insert some more lines of text. Then use the hjkl keys to move around and
insert a word somewhere. Don't forget to press <Esc> to go back to Normal
-mode. The |vimtutor| is also a nice way to learn by doing.
+mode. |:Tutor| is also a nice way to learn by doing.
For Japanese users, Hiroshi Iwatani suggested using this:
diff --git a/runtime/doc/usr_09.txt b/runtime/doc/usr_09.txt
index 68575f5184..05cc32bceb 100644
--- a/runtime/doc/usr_09.txt
+++ b/runtime/doc/usr_09.txt
@@ -81,10 +81,6 @@ is Edit/Global Settings. You will find these entries:
Toggle Left Scrollbar make a scrollbar appear/disappear at the left
Toggle Right Scrollbar make a scrollbar appear/disappear at the right
-On most systems you can tear-off the menus. Select the top item of the menu,
-the one that looks like a dashed line. You will get a separate window with
-the items of the menu. It will hang around until you close the window.
-
THE TOOLBAR
diff --git a/runtime/doc/usr_40.txt b/runtime/doc/usr_40.txt
index 9d706481df..b802c9534a 100644
--- a/runtime/doc/usr_40.txt
+++ b/runtime/doc/usr_40.txt
@@ -290,8 +290,8 @@ deletes the first line.
Note:
User-defined commands must start with a capital letter. You cannot
- use ":X", ":Next" and ":Print". The underscore cannot be used! You
- can use digits, but this is discouraged.
+ use ":Next". The underscore cannot be used! You can use digits, but
+ this is discouraged.
To list the user-defined commands, execute the following command: >
diff --git a/runtime/doc/usr_42.txt b/runtime/doc/usr_42.txt
index 1d16112aa0..b9102f3f7b 100644
--- a/runtime/doc/usr_42.txt
+++ b/runtime/doc/usr_42.txt
@@ -268,13 +268,6 @@ command like: >
but are completely removed. (Does not work on all
systems.)
- t When removed the tearoff feature is not enabled.
-
-The dotted line at the top of a menu is not a separator line. When you select
-this item, the menu is "teared-off": It is displayed in a separate window.
-This is called a tearoff menu. This is useful when you use the same menu
-often.
-
For translating menu items, see |:menutrans|.
Since the mouse has to be used to select a menu item, it is a good idea to use
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index 7d8853f4cd..5fb6dac402 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -91,13 +91,6 @@ g8 Print the hex values of the bytes used in the
current line |cmdline-ranges|).
See |ex-flags| for [flags].
- *:P* *:Print*
-:[range]P[rint] [count] [flags]
- Just as ":print". Was apparently added to Vi for
- people that keep the shift key pressed too long...
- Note: A user command can overrule this command.
- See |ex-flags| for [flags].
-
*:l* *:list*
:[range]l[ist] [count] [flags]
Same as :print, but display unprintable characters
@@ -213,8 +206,8 @@ g8 Print the hex values of the bytes used in the
*:sh* *:shell* *E371* *E360*
:sh[ell] Removed. |vim-differences| {Nvim}
- *:term* *:terminal*
-:term[inal][!] {cmd} Spawns {cmd} using the current value of 'shell' and
+ *:terminal* *:te*
+:te[rminal][!] {cmd} Spawns {cmd} using the current value of 'shell' and
'shellcmdflag' in a new terminal buffer. This is
equivalent to: >
diff --git a/runtime/doc/vi_diff.txt b/runtime/doc/vi_diff.txt
index 45d81bba2e..e76c0163b5 100644
--- a/runtime/doc/vi_diff.txt
+++ b/runtime/doc/vi_diff.txt
@@ -10,17 +10,12 @@ Throughout the help files differences between Vim and Vi/Ex are given in
curly braces, like "{not in Vi}". This file only lists what has not been
mentioned in other files and gives an overview.
-Vim is mostly POSIX 1003.2-1 compliant. The only command known to be missing
-is ":open". There are probably a lot of small differences (either because Vim
-is missing something or because Posix is beside the mark).
-
1. Simulated command |simulated-command|
2. Missing options |missing-options|
3. Limits |limits|
4. The most interesting additions |vim-additions|
5. Other vim features |other-features|
6. Command-line arguments |cmdline-arguments|
-7. POSIX compliance |posix-compliance|
==============================================================================
1. Simulated command *simulated-command*
@@ -919,59 +914,5 @@ Only Vim is able to accept options in between and after the file names.
@{cmdfile} Vile: use {cmdfile} as startup file.
-==============================================================================
-7. POSIX compliance *posix* *posix-compliance*
-
-In 2005 the POSIX test suite was run to check the compatibility of Vim. Most
-of the test was executed properly. There are the few things where Vim
-is not POSIX compliant, even when run in Vi compatibility mode.
-
-Set the $VIM_POSIX environment variable to have 'cpoptions' include the POSIX
-flags when Vim starts up. This makes Vim run as POSIX as it can. That's
-a bit different from being Vi compatible.
-
-This is where Vim does not behave as POSIX specifies and why:
-
- *posix-screen-size*
- The $COLUMNS and $LINES environment variables are ignored by Vim if
- the size can be obtained from the terminal in a more reliable way.
- Add the '|' flag to 'cpoptions' to have $COLUMNS and $LINES overrule
- sizes obtained in another way.
-
- The "{" and "}" commands don't stop at a "{" in the original Vi, but
- POSIX specifies it does. Add the '{' flag to 'cpoptions' if you want
- it the POSIX way.
-
- The "D", "o" and "O" commands accept a count. Also when repeated.
- Add the '#' flag to 'cpoptions' if you want to ignore the count.
-
- The ":cd" command fails if the current buffer is modified when the '.'
- flag is present in 'cpoptions'.
-
- There is no ATTENTION message, the "A" flag is added to 'shortmess'.
-
-These are remarks about running the POSIX test suite:
-- vi test 33 sometimes fails for unknown reasons
-- vi test 250 fails; behavior will be changed in a new revision
- http://www.opengroup.org/austin/mailarchives/ag-review/msg01710.html
- (link no longer works, perhaps it's now:
- https://www.opengroup.org/sophocles/show_mail.tpl?CALLER=show_archive.tpl&source=L&listname=austin-review-l&id=1711)
-- vi test 310 fails; exit code non-zero when any error occurred?
-- ex test 24 fails because test is wrong. Changed between SUSv2 and SUSv3.
-- ex tests 47, 48, 49, 72, 73 fail because .exrc file isn't read in silent
- mode and $EXINIT isn't used.
-- ex tests 76, 78 fail because echo is used instead of printf. (fixed)
- Also: problem with \s not changed to space.
-- ex test 355 fails because 'window' isn't used for "30z".
-- ex test 368 fails because shell command isn't echoed in silent mode.
-- ex test 394 fails because "=" command output isn't visible in silent mode.
-- ex test 411 fails because test file is wrong, contains stray ':'.
-- ex test 475 and 476 fail because reprint output isn't visible in silent mode.
-- ex test 480 and 481 fail because the tags file has spaces instead of a tab.
-- ex test 502 fails because .exrc isn't read in silent mode.
-- ex test 509 fails because .exrc isn't read in silent mode. and exit code is
- 1 instead of 2.
-- ex test 534 fails because .exrc isn't read in silent mode.
-
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 6ad3dab246..5d4e6861f5 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -28,13 +28,14 @@ these differences.
==============================================================================
2. Option defaults *nvim-option-defaults*
-- 'autoindent' is set by default.
+- 'autoindent' is set by default
- 'autoread' is set by default
- 'backspace' defaults to "indent,eol,start"
- 'complete' doesn't include "i"
- 'display' defaults to "lastline"
- 'encoding' defaults to "utf-8"
- 'formatoptions' defaults to "tcqj"
+- 'history' defaults to 10000 (the maximum)
- 'hlsearch' is set by default
- 'incsearch' is set by default
- 'langnoremap' is set by default
@@ -63,11 +64,21 @@ 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
|nvim-python|).
+|mkdir()| behaviour changed:
+1. Assuming /tmp/foo does not exist and /tmp can be written to
+ mkdir('/tmp/foo/bar', 'p', 0700) will create both /tmp/foo and /tmp/foo/bar
+ with 0700 permissions. Vim mkdir will create /tmp/foo with 0755.
+2. If you try to create an existing directory with `'p'` (e.g. mkdir('/',
+ 'p')) mkdir() will silently exit. In Vim this was an error.
+3. mkdir() error messages now include strerror() text when mkdir fails.
+
==============================================================================
4. New Features *nvim-features-new*
See |nvim-intro| for a list of Nvim's largest new features.
+|bracketed-paste-mode| is built-in and enabled by default.
+
Meta (alt) chords are recognized (even in the terminal).
<M-1>, <M-2>, ...
<M-BS>, <M-Del>, <M-Ins>, ...
@@ -135,6 +146,8 @@ Highlight groups:
|hl-VisualNOS|
Other options:
+ 'cpoptions' ('g', 'w', 'H', '*', '-', 'j', and all POSIX flags were removed)
+ 'guioptions' (only the 't' flag was removed)
'guipty'
'macatsui'
'shelltype'
@@ -147,9 +160,11 @@ Other options:
'weirdinvert'
Other commands:
+ :Print
:fixdel
- :mode no longer accepts an argument
+ :mode (no longer accepts an argument)
:shell
+ :tearoff
Other compile-time features:
EBCDIC
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index ba69b7cf2f..39d3c43d97 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -1,4 +1,4 @@
-*windows.txt* For Vim version 7.4. Last change: 2014 Sep 23
+*windows.txt* For Vim version 7.4. Last change: 2014 Dec 05
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -280,7 +280,7 @@ CTRL-W CTRL-Q *CTRL-W_CTRL-Q*
" if there are less than 9 windows opened
:-quit " quit the previous window
:+quit " quit the next window
- :+2quit " will also work as expected
+ :+2quit " quit the second next window
<
:q[uit]!
:{count}q[uit]!
@@ -324,9 +324,9 @@ CTRL-W CTRL-C *CTRL-W_CTRL-C*
screen. For {count} see |:quit|.
The buffer becomes hidden (unless there is another window
- editing it or 'bufhidden' is `unload` or `delete`). If the
- window is the last one in the current tab page the tab page is
- closed. |tab-page|
+ editing it or 'bufhidden' is `unload`, `delete` or `wipe`).
+ If the window is the last one in the current tab page the tab
+ page is closed. |tab-page|
The value of 'hidden' is irrelevant for this command.
Changes to the buffer are not written and won't get lost, so
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index d7bac1bdcf..66e747a06f 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -1,7 +1,7 @@
" Vim support file to detect file types
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2014 Nov 05
+" Last Change: 2014 Dec 06
" Listen very carefully, I will say this only once
if exists("did_load_filetypes")
@@ -1852,7 +1852,7 @@ au BufNewFile,BufRead sgml.catalog* call s:StarSetf('catalog')
" Shell scripts (sh, ksh, bash, bash2, csh); Allow .profile_foo etc.
" Gentoo ebuilds and Arch Linux PKGBUILDs are actually bash scripts
-au BufNewFile,BufRead .bashrc*,bashrc,bash.bashrc,.bash_profile*,.bash_logout*,*.bash,*.ebuild,PKGBUILD* call SetFileTypeSH("bash")
+au BufNewFile,BufRead .bashrc*,bashrc,bash.bashrc,.bash_profile*,.bash_logout*,.bash_aliases*,*.bash,*.ebuild,PKGBUILD* call SetFileTypeSH("bash")
au BufNewFile,BufRead .kshrc*,*.ksh call SetFileTypeSH("ksh")
au BufNewFile,BufRead */etc/profile,.profile*,*.sh,*.env call SetFileTypeSH(getline(1))
@@ -2259,6 +2259,9 @@ au BufNewFile,BufReadPost *.tssop setf tssop
" TSS - Command Line (temporary)
au BufNewFile,BufReadPost *.tsscl setf tsscl
+" Tutor mode
+au BufNewFile,BufReadPost *.tutor setf tutor
+
" TWIG files
au BufNewFile,BufReadPost *.twig setf twig
@@ -2506,6 +2509,8 @@ au BufNewFile,BufRead */etc/yum.conf setf dosini
" Zimbu
au BufNewFile,BufRead *.zu setf zimbu
+" Zimbu Templates
+au BufNewFile,BufRead *.zut setf zimbutempl
" Zope
" dtml (zope dynamic template markup language), pt (zope page template),
diff --git a/runtime/ftplugin/tutor.vim b/runtime/ftplugin/tutor.vim
new file mode 100644
index 0000000000..237176f5eb
--- /dev/null
+++ b/runtime/ftplugin/tutor.vim
@@ -0,0 +1,43 @@
+" vim: fdm=marker
+
+" Base: {{{1
+call tutor#SetupVim()
+
+" Buffer Settings: {{{1
+if !exists('g:tutor_debug') || g:tutor_debug == 0
+ setlocal buftype=nofile
+ setlocal concealcursor+=inv
+ setlocal conceallevel=2
+else
+ setlocal buftype=
+ setlocal concealcursor&
+ setlocal conceallevel=0
+endif
+setlocal noundofile
+
+setlocal keywordprg=:help
+setlocal iskeyword=@,-,_
+
+setlocal foldmethod=expr
+setlocal foldexpr=tutor#TutorFolds()
+setlocal foldcolumn=3
+setlocal foldlevel=4
+
+setlocal statusline=%{toupper(expand('%:t:r'))}\ tutorial%=
+setlocal statusline+=%{tutor#InfoText()}
+
+" Mappings: {{{1
+
+call tutor#SetNormalMappings()
+call tutor#SetSampleTextMappings()
+
+" Checks: {{{1
+
+sign define tutorok text=✓ texthl=tutorOK
+sign define tutorbad text=✗ texthl=tutorX
+
+if !exists('g:tutor_debug') || g:tutor_debug == 0
+ call tutor#PlaceXMarks()
+ autocmd! TextChanged <buffer> call tutor#OnTextChanged()
+ autocmd! TextChangedI <buffer> call tutor#OnTextChanged()
+endif
diff --git a/runtime/indent/php.vim b/runtime/indent/php.vim
index b83a1923ed..1bffa7f195 100644
--- a/runtime/indent/php.vim
+++ b/runtime/indent/php.vim
@@ -3,8 +3,8 @@
" Author: John Wellesz <John.wellesz (AT) teaser (DOT) fr>
" URL: http://www.2072productions.com/vim/indent/php.vim
" Home: https://github.com/2072/PHP-Indenting-for-VIm
-" Last Change: 2014 April 3rd
-" Version: 1.49
+" Last Change: 2014 November 26th
+" Version: 1.57
"
"
" Type :help php-indent for available options
@@ -48,7 +48,7 @@ endif
let b:did_indent = 1
-let php_sync_method = 0
+let g:php_sync_method = 0
@@ -112,7 +112,7 @@ setlocal nocindent
setlocal nolisp
setlocal indentexpr=GetPhpIndent()
-setlocal indentkeys=0{,0},0),:,!^F,o,O,e,*<Return>,=?>,=<?,=*/
+setlocal indentkeys=0{,0},0),0],:,!^F,o,O,e,*<Return>,=?>,=<?,=*/
@@ -128,11 +128,14 @@ if exists("*GetPhpIndent")
endif
+let s:PHP_validVariable = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
let s:notPhpHereDoc = '\%(break\|return\|continue\|exit\|die\|else\)'
let s:blockstart = '\%(\%(\%(}\s*\)\=else\%(\s\+\)\=\)\=if\>\|\%(}\s*\)\?else\>\|do\>\|while\>\|switch\>\|case\>\|default\>\|for\%(each\)\=\>\|declare\>\|class\>\|trait\>\|use\>\|interface\>\|abstract\>\|final\>\|try\>\|\%(}\s*\)\=catch\>\|\%(}\s*\)\=finally\>\)'
-let s:functionDecl = '\<function\>\%(\s\+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\)\=\s*(.*'
+let s:functionDecl = '\<function\>\%(\s\+'.s:PHP_validVariable.'\)\=\s*(.*'
let s:endline= '\s*\%(//.*\|#.*\|/\*.*\*/\s*\)\=$'
-let s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<''\=\a\w*''\=$\|^\s*}\)'.s:endline.'\)\|^[^''"`]*[''"`]$'
+
+
+let s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<''\=\a\w*''\=$\|^\s*}\|^\s*'.s:PHP_validVariable.':\)'.s:endline.'\)\|^[^''"`]*[''"`]$'
let s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!'
@@ -140,7 +143,7 @@ let s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!'
let s:escapeDebugStops = 0
function! DebugPrintReturn(scriptLine)
- if ! s:escapeDebugStops
+ if ! s:escapeDebugStops
echo "debug:" . a:scriptLine
let c = getchar()
if c == "\<Del>"
@@ -158,8 +161,6 @@ function! GetLastRealCodeLNum(startline) " {{{
let lnum = b:GetLastRealCodeLNum_ADD
endif
- let old_lnum = lnum
-
while lnum > 1
let lnum = prevnonblank(lnum)
let lastline = getline(lnum)
@@ -217,7 +218,7 @@ function! GetLastRealCodeLNum(startline) " {{{
let lnum=0
endif
- if b:InPHPcode_and_script && !b:InPHPcode
+ if b:InPHPcode_and_script && 1 > b:InPHPcode
let b:InPHPcode_and_script = 0
endif
@@ -237,7 +238,7 @@ endfun
function! Skippmatch() " {{{
let synname = synIDattr(synID(line("."), col("."), 0), "name")
- if synname == "Delimiter" || synname == "phpRegionDelimiter" || synname =~# "^phpParent" || synname == "phpArrayParens" || synname =~# '^php\%(Block\|Brace\)' || synname == "javaScriptBraces" || synname =~# "^phpComment" && b:UserIsTypingComment
+ if synname == "Delimiter" || synname == "phpRegionDelimiter" || synname =~# "^phpParent" || synname == "phpArrayParens" || synname =~# '^php\%(Block\|Brace\)' || synname == "javaScriptBraces" || synname =~# '^php\%(Doc\)\?Comment' && b:UserIsTypingComment
return 0
else
return 1
@@ -249,7 +250,7 @@ function! FindOpenBracket(lnum, blockStarter) " {{{
let line = searchpair('{', '', '}', 'bW', 'Skippmatch()')
if a:blockStarter == 1
- while line > 1
+ while line > 1
let linec = getline(line)
if linec =~ s:terminated || linec =~ '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline
@@ -310,7 +311,6 @@ let s:defaultORcase = '^\s*\%(default\|case\).*:'
function! FindTheSwitchIndent (lnum) " {{{
-
let test = GetLastRealCodeLNum(a:lnum - 1)
if test <= 1
@@ -353,7 +353,7 @@ function! IslinePHP (lnum, tofind) " {{{
if synname == 'phpStringSingle' || synname == 'phpStringDouble' || synname == 'phpBacktick'
if cline !~ '^\s*[''"`]'
- return ""
+ return "SpecStringEntrails"
else
return synname
end
@@ -372,7 +372,7 @@ if ! s:autoresetoptions
endif
function! ResetPhpOptions()
- if ! b:optionsset && &filetype == "php"
+ if ! b:optionsset && &filetype =~ "php"
if b:PHP_autoformatcomment
setlocal comments=s1:/*,mb:*,ex:*/,://,:#
@@ -418,7 +418,7 @@ function! GetPhpIndent()
let b:PHP_indentinghuge = 0
let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
endif
- let b:PHP_lastindented = v:lnum
+ let real_PHP_lastindented = v:lnum
let b:PHP_LastIndentedWasComment=0
let b:PHP_InsideMultilineComment=0
let b:PHP_indentbeforelast = 0
@@ -430,9 +430,12 @@ function! GetPhpIndent()
elseif v:lnum > b:PHP_lastindented
let real_PHP_lastindented = b:PHP_lastindented
- let b:PHP_lastindented = v:lnum
+ else
+ let real_PHP_lastindented = v:lnum
endif
+ let b:PHP_lastindented = v:lnum
+
if !b:InPHPcode_checked " {{{ One time check
let b:InPHPcode_checked = 1
@@ -443,11 +446,15 @@ function! GetPhpIndent()
endif
if synname!=""
- if synname != "phpHereDoc" && synname != "phpHereDocDelimiter"
+ if synname == "SpecStringEntrails"
+ let b:InPHPcode = -1 " thumb down
+ let b:UserIsTypingComment = 0
+ let b:InPHPcode_tofind = ""
+ elseif synname != "phpHereDoc" && synname != "phpHereDocDelimiter"
let b:InPHPcode = 1
let b:InPHPcode_tofind = ""
- if synname =~# "^phpComment"
+ if synname =~# '^php\%(Doc\)\?Comment'
let b:UserIsTypingComment = 1
else
let b:UserIsTypingComment = 0
@@ -483,9 +490,16 @@ function! GetPhpIndent()
if b:InPHPcode_tofind!=""
if cline =~? b:InPHPcode_tofind
- let b:InPHPcode = 1
let b:InPHPcode_tofind = ""
let b:UserIsTypingComment = 0
+
+ if b:InPHPcode == -1
+ let b:InPHPcode = 1
+ return -1
+ end
+
+ let b:InPHPcode = 1
+
if cline =~ '\*/'
call cursor(v:lnum, 1)
if cline !~ '^\*/'
@@ -510,7 +524,7 @@ function! GetPhpIndent()
endif
endif
- if b:InPHPcode
+ if 1 == b:InPHPcode
if !b:InPHPcode_and_script && last_line =~ '\%(<?.*\)\@<!?>\%(.*<?\)\@!' && IslinePHP(lnum, '?>')=~"Delimiter"
if cline !~? s:PHP_startindenttag
@@ -520,8 +534,8 @@ function! GetPhpIndent()
let b:InPHPcode_and_script = 1
endif
- elseif last_line =~ '^[^''"`]\+[''"`]$' " a string identifier with nothing after it and no other string identifier before
- let b:InPHPcode = 0
+ elseif last_line =~ '^[^''"`]\+[''"`]$'
+ let b:InPHPcode = -1
let b:InPHPcode_tofind = substitute( last_line, '^.*\([''"`]\).*$', '^[^\1]*\1[;,]$', '')
elseif last_line =~? '<<<''\=\a\w*''\=$'
let b:InPHPcode = 0
@@ -538,7 +552,7 @@ function! GetPhpIndent()
endif " }}}
- if !b:InPHPcode && !b:InPHPcode_and_script
+ if 1 > b:InPHPcode && !b:InPHPcode_and_script
return -1
endif
@@ -568,7 +582,7 @@ function! GetPhpIndent()
endif
endif
- if !b:PHP_InsideMultilineComment && cline =~ '^\s*/\*' && cline !~ '\*/\s*$'
+ if !b:PHP_InsideMultilineComment && cline =~ '^\s*/\*\%(.*\*/\)\@!'
if getline(v:lnum + 1) !~ '^\s*\*'
return -1
endif
@@ -669,17 +683,17 @@ function! GetPhpIndent()
endwhile
elseif last_line =~# unstated && cline !~ '^\s*);\='.endline
- let ind = ind + &sw " we indent one level further when the preceding line is not stated
+ let ind = ind + &sw
return ind + addSpecial
- elseif (ind != b:PHP_default_indenting || last_line =~ '^[)\]]' ) && last_line =~ terminated " Added || last_line =~ '^)' on 2007-12-30 (array indenting problem broke other things)
+ elseif (ind != b:PHP_default_indenting || last_line =~ '^[)\]]' ) && last_line =~ terminated
let previous_line = last_line
let last_line_num = lnum
let LastLineClosed = 1
let isSingleLineBlock = 0
while 1
- if ! isSingleLineBlock && previous_line =~ '^\s*}\|;\s*}'.endline " XXX
+ if ! isSingleLineBlock && previous_line =~ '^\s*}\|;\s*}'.endline
call cursor(last_line_num, 1)
if previous_line !~ '^}'
@@ -740,14 +754,19 @@ function! GetPhpIndent()
endif
endif
- let plinnum = GetLastRealCodeLNum(lnum - 1)
+ if (last_line !~ '^\s*}\%(}}\)\@!')
+ let plinnum = GetLastRealCodeLNum(lnum - 1)
+ else
+ let plinnum = GetLastRealCodeLNum(FindOpenBracket(lnum, 1) - 1)
+ endif
+
let AntepenultimateLine = getline(plinnum)
let last_line = substitute(last_line,"\\(//\\|#\\)\\(\\(\\([^\"']*\\([\"']\\)[^\"']*\\5\\)\\+[^\"']*$\\)\\|\\([^\"']*$\\)\\)",'','')
if ind == b:PHP_default_indenting
- if last_line =~ terminated
+ if last_line =~ terminated && last_line !~# s:defaultORcase
let LastLineClosed = 1
endif
endif
@@ -755,10 +774,10 @@ function! GetPhpIndent()
if !LastLineClosed
- if last_line =~# '[{(\[]'.endline || last_line =~? '\h\w*\s*(.*,$' && AntepenultimateLine !~ '[,(]'.endline
+ if last_line =~# '[{(\[]'.endline || last_line =~? '\h\w*\s*(.*,$' && AntepenultimateLine !~ '[,(\[]'.endline
let dontIndent = 0
- if last_line =~ '\S\+\s*{'.endline && last_line !~ '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline
+ if last_line =~ '\S\+\s*{'.endline && last_line !~ '^\s*)\s*{'.endline && last_line !~ '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline
let dontIndent = 1
endif
@@ -774,7 +793,7 @@ function! GetPhpIndent()
elseif last_line =~ '\S\+\s*),'.endline
call cursor(lnum, 1)
- call search('),'.endline, 'W') " line never begins with ) so no need for 'c' flag
+ call search('),'.endline, 'W')
let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()')
if openedparent != lnum
let ind = indent(openedparent)
@@ -784,7 +803,7 @@ function! GetPhpIndent()
let ind = ind + &sw
- elseif AntepenultimateLine =~ '\%(;\%(\s*\%(?>\|}\)\)\=\|<<<''\=\a\w*''\=$\|^\s*}\|{\)'.endline . '\|' . s:defaultORcase
+ elseif AntepenultimateLine =~ '{'.endline || AntepenultimateLine =~ terminated || AntepenultimateLine =~# s:defaultORcase
let ind = ind + &sw
endif
diff --git a/runtime/macros/editexisting.vim b/runtime/macros/editexisting.vim
index c18f22569f..3530e29dc4 100644
--- a/runtime/macros/editexisting.vim
+++ b/runtime/macros/editexisting.vim
@@ -1,6 +1,6 @@
" Vim Plugin: Edit the file with an existing Vim if possible
" Maintainer: Bram Moolenaar
-" Last Change: 2013 Feb 24
+" Last Change: 2014 Dec 06
" This is a plugin, drop it in your (Unix) ~/.vim/plugin or (Win32)
" $VIM/vimfiles/plugin directory. Or make a symbolic link, so that you
@@ -112,7 +112,7 @@ func! EditExisting(fname, command)
endif
if a:command != ''
- exe "normal " . a:command
+ exe "normal! " . a:command
endif
redraw
diff --git a/runtime/plugin/tutor.vim b/runtime/plugin/tutor.vim
new file mode 100644
index 0000000000..1411b1ac63
--- /dev/null
+++ b/runtime/plugin/tutor.vim
@@ -0,0 +1,6 @@
+if exists('g:loaded_tutor_mode_plugin') || &compatible
+ finish
+endif
+let g:loaded_tutor_mode_plugin = 1
+
+command! -nargs=? -complete=custom,tutor#TutorCmdComplete Tutor call tutor#TutorCmd(<q-args>)
diff --git a/runtime/syntax/tutor.vim b/runtime/syntax/tutor.vim
new file mode 100644
index 0000000000..99bcb78270
--- /dev/null
+++ b/runtime/syntax/tutor.vim
@@ -0,0 +1,83 @@
+if exists("b:current_syntax")
+ finish
+endif
+
+syn include @VIM syntax/vim.vim
+unlet b:current_syntax
+syn include @TUTORSHELL syntax/sh.vim
+unlet b:current_syntax
+syn include @VIMNORMAL syntax/vimnormal.vim
+
+syn match tutorLink /\[.\{-}\](.\{-})/ contains=tutorInlineNormal
+syn match tutorLinkBands /\[\|\]\|(\|)/ contained containedin=tutorLink,tutorLinkAnchor conceal
+syn match tutorLinkAnchor /(.\{-})/ contained containedin=tutorLink conceal
+syn match tutorURL /\(https\?\|file\):\/\/[[:graph:]]\+\>\/\?/
+syn match tutorEmail /\<[[:graph:]]\+@[[:graph:]]\+\>/
+syn match tutorInternalAnchor /\*[[:alnum:]-]\+\*/ contained conceal containedin=tutorSection
+
+syn match tutorSection /^#\{1,6}\s.\+$/ fold
+syn match tutorSectionBullet /#/ contained containedin=tutorSection
+
+syn match tutorTOC /\ctable of contents:/
+
+syn match tutorConcealedEscapes /\\[`*!\[\]()«»:$-]\@=/ conceal
+
+syn region tutorEmphasis matchgroup=Delimiter start=/[\*]\@<!\*\*\@!/ end=/[\*]\@<!\*\*\@!/
+ \ concealends contains=tutorInlineCommand,tutorInlineNormal
+syn region tutorBold matchgroup=Delimiter start=/\*\{2}/ end=/\*\{2}/
+ \ concealends contains=tutorInlineCommand,tutorInlineNormal
+
+syn keyword tutorMarks TODO NOTE IMPORTANT TIP ATTENTION EXERCISE
+syn keyword tutorMarks todo note tip attention exercise
+syn keyword tutorMarks Todo Note Tip Excersise
+
+syn match tutorTextMark /\\\@<!--->/ conceal cchar=→
+syn region tutorSampleText start=/^\(--->\)\@=/ end=/$/ keepend contains=@SPELL
+syn match tutorSampleTextMark /^--->/ contained containedin=tutorSampleText conceal cchar=→
+syn match tutorSampleTextExpect /\}\@<! {expect:.\+}\s*$/ contained containedin=tutorSampleText conceal
+syn match tutorSampleTextExpect /|\@<! |expect:.\+|\s*$/ contained containedin=tutorSampleText conceal
+
+syn region tutorCodeblock matchgroup=Delimiter start=/^\~\{3}.*$/ end=/^\~\{3}/
+
+syn region tutorShell matchgroup=Delimiter start=/^\~\{3} sh\s*$/ end=/^\~\{3}/ keepend contains=@TUTORSHELL concealends
+syn match tutorShellPrompt /\(^\s*\)\@<=[$#]/ contained containedin=tutorShell
+
+syn region tutorInlineCode matchgroup=Delimiter start=/\\\@<!`/ end=/\\\@<!\(`{\@!\|`\s\)/ concealends
+
+syn region tutorCommand matchgroup=Delimiter start=/^\~\{3} cmd\( :\)\?\s*$/ end=/^\~\{3}/ keepend contains=@VIM concealends
+syn region tutorInlineCommand matchgroup=Delimiter start=/\\\@<!`\(.*{vim}\)\@=/ end=/\\\@<!`\({vim}\)\@=/ nextgroup=tutorInlineType contains=@VIM concealends
+
+syn region tutorNormal matchgroup=Delimiter start=/^\~\{3} norm\(al\?\)\?\s*$/ end=/^\~\{3}/ contains=@VIMNORMAL concealends
+syn region tutorInlineNormal matchgroup=Delimiter start=/\\\@<!`\(\S*{normal}\)\@=/ end=/\\\@<!`\({normal}\)\@=/ nextgroup=tutorInlineType contains=@VIMNORMAL concealends
+
+syn match tutorInlineType /{\(normal\|vim\)}/ contained conceal
+
+syn match tutorInlineOK /✓/
+syn match tutorInlineX /✗/
+
+hi! tutorLink cterm=underline gui=underline ctermfg=lightblue guifg=#0088ff
+hi! link tutorLinkBands Delimiter
+hi! link tutorLinkAnchor Underlined
+hi! link tutorInternalAnchor Underlined
+hi! link tutorURL tutorLink
+hi! link tutorEmail tutorLink
+
+hi! link tutorSection Title
+hi! link tutorSectionBullet Delimiter
+
+hi! link tutorTOC Directory
+
+hi! tutorMarks cterm=bold gui=bold
+
+hi! tutorEmphasis gui=italic cterm=italic
+hi! tutorBold gui=bold cterm=bold
+
+hi! link tutorSampleText Special
+hi! tutorOK ctermfg=green guifg=#00ff88 cterm=bold gui=bold
+hi! tutorX ctermfg=red guifg=#ff2000 cterm=bold gui=bold
+hi! link tutorInlineOK tutorOK
+hi! link tutorInlineX tutorX
+
+hi! link tutorShellPrompt Delimiter
+
+let b:current_syntax = "tutor"
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index b200d43f73..e23232bbbe 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -1,8 +1,8 @@
" Vim syntax file
" Language: Vim 7.4 script
" Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz>
-" Last Change: Mar 20, 2014
-" Version: 7.4-27
+" Last Change: Apr 02, 2015
+" Version: 7.4-33
" Automatically generated keyword lists: {{{1
" Quit when a syntax file was already loaded {{{2
@@ -14,67 +14,48 @@ set cpo&vim
" vimTodo: contains common special-notices for comments {{{2
" Use the vimCommentGroup cluster to add your own.
+syn keyword vimTodo contained COMBAK FIXME TODO XXX
syn cluster vimCommentGroup contains=vimTodo,@Spell
-" regular vim commands {{{2
-syn keyword vimCommand contained a arga[dd] ar[gs] bd[elete] bN[ext] breakd[el] bufdo cabc[lear] cat[ch] cex[pr] c[hange] cla[st] cnew[er] cNf[ile] con cp[revious] cuna[bbrev] del deletep delm[arks] diffp[atch] dig[raphs] do e echon endf endw[hile] f[ile] fin[d] folddoc[losed] fu[nction] gvim helpt[ags] iabc[lear] intro k l lan lc[d] lefta[bove] lg[etfile] lla[st] lnew[er] lNf[ile] lockv[ar] ls lvimgrepa[dd] mat[ch] mk[exrc] mo n n[ext] o ownsyntax pre[serve] promptf[ind] ptl[ast] ptr[ewind] py3do qa[ll] r[ead] redr[aw] retu[rn] rub[y] rv[iminfo] sba[ll] sbN[ext] scripte[ncoding] setf[iletype] sh[ell] sim[alt] sm[ap] sni[ff] sor[t] spelli[nfo] spr[evious] start st[op] sunmenu syn ta tabf[ind] tabnew tabr[ewind] tj[ump] tN tr tu[nmenu] undoj[oin] uns[ilent] ve[rsion] vimgrepa[dd] vs[plit] winc[md] wN[ext] ws[verb] x[it] xnoremenu
-syn keyword vimCommand contained ab argd[elete] argu[ment] bel[owright] bo[tright] breakl[ist] b[uffer] cad cb[uffer] cf[ile] changes cl[ist] cn[ext] col[der] conf[irm] cq[uit] cw[indow] delc[ommand] deletl delp diffpu[t] dir doau ea e[dit] endfo[r] ene[w] files fini[sh] foldd[oopen] g h hi if is[earch] keepa la lan[guage] lch[dir] lex[pr] lgr[ep] lli[st] lne[xt] lo lol[der] lt[ag] lw[indow] menut mks[ession] mod[e] nbc[lose] nmapc[lear] ol[dfiles] p po[p] prev[ious] promptr[epl] ptn pts[elect] pydo q[uit] rec[over] redraws[tatus] rew[ind] sal[l] sbf[irst] sbp[revious] scrip[tnames] setg[lobal] si sl sme sno[magic] so[urce] spellr[epall] sre[wind] startg[replace] stopi[nsert] sus[pend] sync tab tabfir[st] tabn[ext] tabs tl[ast] tn[ext] tr[ewind] u undol[ist] up[date] vert[ical] vi[sual] w windo wp[revious] wundo xmapc[lear] xunme
-syn keyword vimCommand contained abc[lear] argdo as[cii] bf[irst] bp[revious] br[ewind] buffers caddb[uffer] cc cfir[st] chd[ir] clo[se] cN[ext] colo[rscheme] con[tinue] cr[ewind] d delel deletp dep diffs[plit] di[splay] dp earlier el[se] endfun ex filet fir[st] foldo[pen] go[to] ha[rdcopy] hid[e] ij[ump] isp[lit] keepalt lad la[st] lcl[ose] lf[ile] lgrepa[dd] lmak[e] lN[ext] loadk lop[en] ma menut[ranslate] mksp[ell] m[ove] nb[key] noa omapc[lear] pc[lose] popu p[rint] ps[earch] ptN pu[t] pyf[ile] quita[ll] red reg[isters] ri[ght] san[dbox] sbl[ast] sbr[ewind] scs setl[ocal] sig sla[st] smenu snoreme spe spellu[ndo] st star[tinsert] sts[elect] sv[iew] syncbind tabc[lose] tabl[ast] tabN[ext] ta[g] te[aroff] tm tN[ext] try un unh[ide] v vi viu[sage] wa[ll] winp[os] wq wv[iminfo] xme xunmenu
-syn keyword vimCommand contained abo[veleft] arge[dit] au bl[ast] br bro[wse] bun[load] cad[dexpr] ccl[ose] cgetb[uffer] che[ckpath] cmapc[lear] cnf com cope[n] cs de delep delf di difft[his] dj[ump] dr[op] ec elsei[f] endf[unction] exi[t] filetype fix[del] for gr[ep] h[elp] his[tory] il[ist] iuna[bbrev] keepj[umps] laddb[uffer] lat lcs lfir[st] lh[elpgrep] lmapc[lear] lnf loadkeymap lpf[ile] mak[e] mes mkv nbs[tart] noautocmd on[ly] pe popu[p] pro pta[g] ptn[ext] pw[d] py[thon] r redi[r] res[ize] rightb[elow] rundo sa[rgument] sbm[odified] sb[uffer] scscope sf[ind] sign sl[eep] sn[ext] snoremenu spelld[ump] spellw[rong] sta[g] startr[eplace] sun[hide] sw[apname] syntime tabd[o] tabm[ove] tabo[nly] tags tf[irst] tm[enu] to[pleft] ts[elect] una[bbreviate] unl ve vie[w] vmapc[lear] wh[ile] win[size] wqa[ll] x xmenu xwininfo
-syn keyword vimCommand contained al[l] argg[lobal] bad[d] bm[odified] brea[k] bu bw[ipeout] caddf[ile] cd cgete[xpr] checkt[ime] cn cNf comc[lear] co[py] cscope debug d[elete] delf[unction] diffg[et] diffu[pdate] dl ds[earch] echoe[rr] em[enu] en[dif] exu[sage] fin fo[ld] fu grepa[dd] helpf[ind] i imapc[lear] j[oin] kee[pmarks] lad[dexpr] later lcscope lgetb[uffer] l[ist] lN lNf lo[adview] lp[revious] ma[rk] messages mkvie[w] ne noh[lsearch] o[pen] ped[it] pp[op] profd[el] ptf[irst] ptN[ext] py python3 re red[o] ret[ab] ru ru[ntime] sav[eas] sbn[ext] scrip se[t] sfir[st] sil[ent] sm[agic] sN[ext] so spe[llgood] sp[lit] star stj[ump] sunme sy t tabe[dit] tabN tabp[revious] tc[l] th[row] tn tp[revious] tu u[ndo] unlo[ckvar] verb[ose] vim[grep] vne[w] win wn[ext] w[rite] xa[ll] xnoreme y[ank]
-syn keyword vimCommand contained ar argl[ocal] ba[ll] bn[ext] breaka[dd] buf c cal[l] ce[nter] cg[etfile] cl cN cnf[ile] comp[iler] cpf[ile] cstag debugg[reedy] deletel dell diffo[ff] dig dli[st] dsp[lit] echom[sg] en endt[ry] f fina[lly] foldc[lose] fun gui helpg[rep] ia in ju[mps] keepp[atterns] laddf[ile] lb[uffer] le[ft] lgete[xpr] ll lne lnf[ile] loc[kmarks] lr[ewind] lv[imgrep] marks mk mkv[imrc] new nu[mber] opt[ions] pe[rl] pr prof[ile] ptj[ump] ptp[revious] py3 q
+" Special and plugin vim commands {{{2
syn match vimCommand contained "\<z[-+^.=]\="
-syn keyword vimStdPlugin contained DiffOrig Man N[ext] P[rint] S TOhtml XMLent XMLns
-
-" vimOptions are caught only when contained in a vimSet {{{2
-syn keyword vimOption contained acd ambiwidth arabicshape autowriteall backupdir bdlay binary breakat bufhidden cd ci cinw co commentstring confirm cpoptions cscoperelative csre cursorcolumn delcombine diffopt ea efm ep et fdc fdo ffs filetype fo foldlevelstart formatexpr ft gfw gtt guipty hh hkmap ic imaf iminsert includeexpr inf isident langmap lines lmap ma matchtime mco ml modeline mousefocus mousetime nrformats ofu para pdev pi previewwindow printmbfont qe relativenumber rightleftcmd ru sbr scrolloff selection shellcmdflag shellxescape showbreak si smartcase softtabstop spelllang sps sta su swb synmaxcol tagbsearch thesaurus titlestring tpm ttm ttytype undodir ut vfile vop wcm whichwrap wildignore winaltkeys winminwidth wmnu write
-syn keyword vimOption contained ai ambw ari aw backupext beval brk buflisted cdpath cin cinwords cocu compatible cpt cscopetag cst cursorline dex digraph ead ei equalalways eventignore fde fdt fic fillchars foldclose foldmarker formatlistpat gcr ghr guicursor guitablabel hi hkmapp icon imak ims incsearch infercase isk keymap langmenu linespace loadplugins maxcombine mef mls modelines mousehide mp nu omnifunc paragraphs penc pm printdevice printoptions quoteescape remap rl ruf sc scrollopt selectmode shellpipe shellxquote showcmd sidescroll smartindent sol spellsuggest sr stal sua swf syntax taglength tbidi terse tildeop tl tr tty tw undofile vb vi wa wd wi wildignorecase window winwidth wmw writeany
-syn keyword vimOption contained akm anti arshape awa backupskip bex browsedir buftype cedit cindent clipboard cole complete crb cscopetagorder csto cwh dg dip eadirection ek equalprg ex fdi fen fileencoding fk foldcolumn foldmethod formatoptions gd go guifont guitabtooltip hid hkp iconstring imc imsearch inde insertmode iskeyword keymodel laststatus lisp lpl magic maxfuncdepth menuitems mm modifiable mousem mps number opendevice paste pex pmbcs printencoding prompt rdt report rlc ruler scb scs sessionoptions shellquote shiftround showfulltag sidescrolloff smarttab sp spf srr startofline suffixes switchbuf ta tagrelative tbis textauto timeout tm ts tx undolevels vbs viewdir wak wic wildmenu winfixheight wop writebackup
-syn keyword vimOption contained al antialias autochdir background balloondelay bexpr bk bs casemap cf cink cmdheight colorcolumn completefunc copyindent cscopeverbose csverb debug dict dir eb enc errorbells expandtab fdl fenc fileencodings fkmap foldenable foldminlines formatprg gdefault gp guifontset helpfile hidden hl ignorecase imcmdline imsf indentexpr is isp keywordprg lazyredraw lispwords ls makeef maxmapdepth mfd mmd modified mousemodel msm numberwidth operatorfunc pastetoggle pexpr pmbfn printexpr pt re restorescreen rnu rulerformat scr sect sft shellredir shiftwidth showmatch siso smc spc spl ss statusline suffixesadd sws tabline tags tbs textmode timeoutlen to uc undoreload vdir viewoptions warn wfh wig wildmode winfixwidth wiw wrap writedelay
-syn keyword vimOption contained aleph ar autoindent backspace ballooneval bg bkc bsdir cb cfu cinkeys cmdwinheight columns completeopt cot cscopepathcomp cspc cuc deco dictionary directory ed encoding errorfile exrc fdls fencs fileformat flp foldexpr foldnestmax fp gfm grepformat guifontwide helpheight highlight hlg im imd imstatusfunc indentkeys isf isprint km lbr list lsp makeprg maxmem mh mmp more mouses nuw opfunc patchexpr pfn popt printfont pumheight readonly revins ro runtimepath scroll sections sh shellslash shm showmode sj smd spell splitbelow ssl stl sw sxe tabpagemax tagstack textwidth title toolbar tsr udf updatecount ve viminfo wb wfw wildchar wildoptions winheight wm wrapmargin ws
-syn keyword vimOption contained allowrevins arab autoread backup balloonexpr bh bl bsk cc ch cino cmp com concealcursor cp cscopeprg csprg cul def diff display endofline errorformat fcl fdm fex fileformats fml foldignore foldopen fs gfn grepprg guiheadroom helplang history hls imactivatefunc imdisable inc indk isfname joinspaces kmp lcs listchars lw mat maxmempattern mis mmt mouse mouseshape odev patchmode ph preserveindent printheader pvh redrawtime ri rs sb scrollbind secure shcf shelltemp shortmess showtabline slm spellcapcheck splitright ssop stmp swapfile sxq tabstop tal term titlelen toolbariconsize ttimeout udir updatetime verbose virtualedit wc wh wildcharm wim winminheight wmh wrapscan ww
-syn keyword vimOption contained altkeymap arabic autowrite backupcopy bdir bin bomb bt ccv charconvert cinoptions cms comments conceallevel cpo cscopequickfix csqf cursorbind define diffexpr dy ef eol esckeys fcs fdn ff fileignorecase fmr foldlevel foldtext fsync gfs gtl guioptions hf hk hlsearch imactivatekey imi include inex isi js kp linebreak lm lz matchpairs maxmemtot mkspellmem mod mousef mouset nf pa path pheader previewheight printmbcharset pvw regexpengine rightleft rtp sbo scrolljump sel shell shq sm so spellfile spr st sts swapsync syn tag tb termbidi tgst titleold top ttimeoutlen ul ur unnamedclip unc verbosefile visualbell
-
-" vimOptions: These are the turn-off setting variants {{{2
-syn keyword vimOption contained noacd noallowrevins noantialias noarabic noarshape noautoread noaw noballooneval nobinary nobk nobuflisted nocin noconfirm nocopyindent nocscoperelative nocsre nocuc nocursorcolumn nodelcombine nodigraph noendofline noerrorbells noex nofen nofk nogd nohid nohkmap nohkp nohlsearch noicon noim noimcmdline noimdisable noinf noinsertmode nojoinspaces nolazyredraw nolinebreak nolist nolpl noma nomagic noml nomodeline nomodified nomousef nomousehide nonumber noopendevice nopi nopreviewwindow nopvw norelativenumber norestorescreen nori norl noro noru nosb noscb noscs nosft noshelltemp noshowfulltag noshowmode nosm nosmartindent nosmd nosol nosplitbelow nospr nossl nostartofline noswapfile nota notagrelative notbs noterse notextmode notgst notimeout noto notr notx noundofile novisualbell nowarn nowfw nowildignorecase nowinfixheight nowrap nowrite nowritebackup
-syn keyword vimOption contained noai noaltkeymap noar noarabicshape noautochdir noautowrite noawa nobeval nobl nocf nocindent nocp nocscopetag nocst nocul nocursorline nodg noea noeol noesckeys noexpandtab nofic nofkmap nogdefault nohidden nohkmapp nohls noic noignorecase noimc noimd noincsearch noinfercase nois nojs nolbr nolisp noloadplugins nolz nomh nomod nomodifiable nomore nomousefocus nonu noodev nopaste nopreserveindent noprompt noreadonly noremap norevins norightleft nornu nors noruler nosc noscrollbind nosecure noshellslash noshiftround noshowcmd noshowmatch nosi nosmartcase nosmarttab nospell nosplitright nosr nosta nostmp noswf notagbsearch notagstack notbidi notermbidi notextauto notildeop notitle notop nottimeout noudf novb nowa nowb nowfh nowic nowildmenu nowinfixwidth nowmnu nowrapscan nowriteany nows
-syn keyword vimOption contained noakm noanti noarab noari noautoindent noautowriteall nobackup nobin nobomb noci nocompatible nocrb nocscopeverbose nocsverb nocursorbind nodeco nodiff noeb noek noequalalways noet noexrc nofileignorecase nofoldenable noguipty nohk
-
-" vimOptions: These are the invertible variants {{{2
-syn keyword vimOption contained invacd invallowrevins invantialias invarabic invarshape invautoread invaw invballooneval invbinary invbk invbuflisted invcin invconfirm invcopyindent invcscoperelative invcsre invcuc invcursorcolumn invdelcombine invdigraph invendofline inverrorbells invex invfen invfk invgd invhid invhkmap invhkp invhlsearch invicon invim invimcmdline invimdisable invinf invinsertmode invjoinspaces invlazyredraw invlinebreak invlist invlpl invma invmagic invml invmodeline invmodified invmousef invmousehide invnumber invopendevice invpi invpreviewwindow invpvw invrelativenumber invrestorescreen invri invrl invro invru invsb invscb invscs invsft invshelltemp invshowfulltag invshowmode invsm invsmartindent invsmd invsol invsplitbelow invspr invssl invstartofline invswapfile invta invtagrelative invtbs invterse invtextmode invtgst invtimeout invto invtr invtx invundofile invvisualbell invwarn invwfw invwildignorecase invwinfixheight invwrap invwrite invwritebackup
-syn keyword vimOption contained invai invaltkeymap invar invarabicshape invautochdir invautowrite invawa invbeval invbl invcf invcindent invcp invcscopetag invcst invcul invcursorline invdg invea inveol invesckeys invexpandtab invfic invfkmap invgdefault invhidden invhkmapp invhls invic invignorecase invimc invimd invincsearch invinfercase invis invjs invlbr invlisp invloadplugins invlz invmh invmod invmodifiable invmore invmousefocus invnu invodev invpaste invpreserveindent invprompt invreadonly invremap invrevins invrightleft invrnu invrs invruler invsc invscrollbind invsecure invshellslash invshiftround invshowcmd invshowmatch invsi invsmartcase invsmarttab invspell invsplitright invsr invsta invstmp invswf invtagbsearch invtagstack invtbidi invtermbidi invtextauto invtildeop invtitle invtop invttimeout invudf invvb invwa invwb invwfh invwic invwildmenu invwinfixwidth invwmnu invwrapscan invwriteany invws
-syn keyword vimOption contained invakm invanti invarab invari invautoindent invautowriteall invbackup invbin invbomb invci invcompatible invcrb invcscopeverbose invcsverb invcursorbind invdeco invdiff inveb invek invequalalways invet invexrc invfileignorecase invfoldenable invguipty invhk
+syn keyword vimOnlyCommand contained fix[del] sh[ell] P[rint]
+syn keyword vimStdPlugin contained DiffOrig Man N[ext] S TOhtml XMLent XMLns
+" Vim-specific options {{{2
+syn keyword vimOnlyOption contained biosk bioskey cp compatible consk conskey cm cryptmethod edcompatible guipty key macatsui mzq mzquantum osfiletype oft renderoptions rop st shelltype sn shortname tenc termencoding ta textauto tx textmode tf ttyfast ttym ttymouse tbi ttybuiltin wiv weirdinvert
+
+" Turn-off setting variants
+syn keyword vimOnlyOption contained nobiosk nobioskey noconsk noconskey nocp nocompatible noguipty nomacatsui nosn noshortname nota notextauto notx notextmode notf nottyfast notbi nottybuiltin nowiv noweirdinvert
+
+" Invertible setting variants
+syn keyword vimOnlyOption contained invbiosk invbioskey invconsk invconskey invcp invcompatible invguipty invmacatsui invsn invshortname invta invtextauto invtx invtextmode invtf invttyfast invtbi invttybuiltin invwiv invweirdinvert
" termcap codes (which can also be set) {{{2
-syn keyword vimOption contained t_AB t_al t_bc t_ce t_cl t_Co t_Cs t_CS t_CV t_da t_db t_dl t_DL t_EI t_F1 t_F2 t_F3 t_F4 t_F5 t_F6 t_F7 t_F8 t_F9 t_fs t_IE t_IS t_k1 t_K1 t_k2 t_k3 t_K3 t_k4 t_K4 t_k5 t_K5 t_k6 t_K6 t_k7 t_K7 t_k8 t_K8 t_k9 t_K9 t_KA t_kb t_kB t_KB t_KC t_kd t_kD t_KD t_ke t_KE t_KF t_KG t_kh t_KH t_kI t_KI t_KJ t_KK t_kl t_KL t_kN t_kP t_kr t_ks t_ku t_le t_mb t_md t_me t_mr t_ms t_nd t_op t_RI t_RV t_Sb t_se t_Sf t_SI t_so t_sr t_te t_ti t_ts t_u7 t_ue t_us t_ut t_vb t_ve t_vi t_vs t_WP t_WS t_xs t_ZH t_ZR
-syn keyword vimOption contained t_AF t_AL t_cd t_Ce t_cm t_cs
-syn match vimOption contained "t_%1"
-syn match vimOption contained "t_#2"
-syn match vimOption contained "t_#4"
-syn match vimOption contained "t_@7"
-syn match vimOption contained "t_*7"
-syn match vimOption contained "t_&8"
-syn match vimOption contained "t_%i"
-syn match vimOption contained "t_k;"
-
-" AutoCmd Events {{{2
+syn keyword vimTermOption contained t_AB t_al t_bc t_ce t_cl t_Co t_Cs t_CS t_CV t_da t_db t_dl t_DL t_EI t_F1 t_F2 t_F3 t_F4 t_F5 t_F6 t_F7 t_F8 t_F9 t_fs t_IE t_IS t_k1 t_K1 t_k2 t_k3 t_K3 t_k4 t_K4 t_k5 t_K5 t_k6 t_K6 t_k7 t_K7 t_k8 t_K8 t_k9 t_K9 t_KA t_kb t_kB t_KB t_KC t_kd t_kD t_KD t_ke t_KE t_KF t_KG t_kh t_KH t_kI t_KI t_KJ t_KK t_kl t_KL t_kN t_kP t_kr t_ks t_ku t_le t_mb t_md t_me t_mr t_ms t_nd t_op t_RI t_RV t_Sb t_se t_Sf t_SI t_so t_sr t_te t_ti t_ts t_u7 t_ue t_us t_ut t_vb t_ve t_vi t_vs t_WP t_WS t_xs t_ZH t_ZR
+syn keyword vimTermOption contained t_AF t_AL t_cd t_Ce t_cm t_cs
+syn match vimTermOption contained "t_%1"
+syn match vimTermOption contained "t_#2"
+syn match vimTermOption contained "t_#4"
+syn match vimTermOption contained "t_@7"
+syn match vimTermOption contained "t_*7"
+syn match vimTermOption contained "t_&8"
+syn match vimTermOption contained "t_%i"
+syn match vimTermOption contained "t_k;"
+
+" unsupported settings: these are supported by vi but don't do anything in vim {{{2
+syn keyword vimErrSetting contained hardtabs ht w1200 w300 w9600
+"}}}2
syn case ignore
-syn keyword vimAutoEvent contained BufAdd BufCreate BufDelete BufEnter BufFilePost BufFilePre BufHidden BufLeave BufNew BufNewFile BufRead BufReadCmd BufReadPost BufReadPre BufUnload BufWinEnter BufWinLeave BufWipeout BufWrite BufWriteCmd BufWritePost BufWritePre Cmd-event CmdwinEnter CmdwinLeave ColorScheme CompleteDone CursorHold CursorHoldI CursorMoved CursorMovedI EncodingChanged FileAppendCmd FileAppendPost FileAppendPre FileChangedRO FileChangedShell FileChangedShellPost FileEncoding FileReadCmd FileReadPost FileReadPre FileType FileWriteCmd FileWritePost FileWritePre FilterReadPost FilterReadPre FilterWritePost FilterWritePre FocusGained FocusLost FuncUndefined GUIEnter GUIFailed InsertChange InsertCharPre InsertEnter InsertLeave MenuPopup QuickFixCmdPost QuickFixCmdPre QuitPre RemoteReply SessionLoadPost ShellCmdPost ShellFilterPost SourceCmd SourcePre SpellFileMissing StdinReadPost StdinReadPre SwapExists Syntax TabEnter TabLeave TabNew TabNewEntered TabClosed TermChanged TermResponse TextChanged TextChangedI User UserGettingBored VimEnter VimLeave VimLeavePre VimResized WinEnter WinLeave
-
" Highlight commonly used Groupnames {{{2
syn keyword vimGroup contained Comment Constant String Character Number Boolean Float Identifier Function Statement Conditional Repeat Label Operator Keyword Exception PreProc Include Define Macro PreCondit Type StorageClass Structure Typedef Special SpecialChar Tag Delimiter SpecialComment Debug Underlined Ignore Error Todo
" Default highlighting groups {{{2
-syn keyword vimHLGroup contained ColorColumn Cursor CursorColumn CursorIM CursorLine CursorLineNr DiffAdd DiffChange DiffDelete DiffText Directory EndOfBuffer ErrorMsg FoldColumn Folded IncSearch LineNr MatchParen Menu ModeMsg MoreMsg NonText Normal Pmenu PmenuSbar PmenuSel PmenuThumb Question Scrollbar Search SignColumn SpecialKey SpellBad SpellCap SpellLocal SpellRare StatusLine StatusLineNC TabLine TabLineFill TabLineSel TermCursor TermCursorNC Title Tooltip VertSplit Visual VisualNOS WarningMsg WildMenu
+syn keyword vimHLGroup contained ColorColumn Cursor CursorColumn CursorIM CursorLine CursorLineNr DiffAdd DiffChange DiffDelete DiffText Directory ErrorMsg FoldColumn Folded IncSearch LineNr MatchParen Menu ModeMsg MoreMsg NonText Normal Pmenu PmenuSbar PmenuSel PmenuThumb Question Scrollbar Search SignColumn SpecialKey SpellBad SpellCap SpellLocal SpellRare StatusLine StatusLineNC TabLine TabLineFill TabLineSel Title Tooltip VertSplit Visual WarningMsg WildMenu
syn match vimHLGroup contained "Conceal"
+syn keyword vimOnlyHLGroup contained VisualNOS
+syn keyword nvimHLGroup contained EndOfBuffer TermCursor TermCursorNC
+"}}}2
syn case match
-
-" Function Names {{{2
-syn keyword vimFuncName contained abs and argidx atan browsedir bufloaded bufwinnr byteidxcomp changenr clearmatches complete_add copy count deepcopy diff_filler escape executable expand feedkeys filter float2nr fnameescape foldclosedend foldtextresult garbagecollect getbufvar getcmdline getcwd getfsize getline getpid getreg gettabwinvar getwinvar has hasmapto histget hlID indent inputdialog inputsave invert items len line localtime mapcheck matcharg matchlist min or prevnonblank py3eval readfile remote_expr remote_read rename reverse screenchar search searchpairpos serverlist setcmdpos setloclist setpos setreg settabwinvar sha256 shiftwidth sin sort spellbadword split str2float strchars strftime string strpart strtrans submatch synconcealed synIDattr synstack tabpagebuflist tabpagewinnr taglist tanh tolower tr type undotree virtcol wildmenumode wincol winline winrestcmd winsaveview writefile
-syn keyword vimFuncName contained acos append argv atan2 bufexists bufname byte2line call char2nr col complete_check cos cscope_connection delete diff_hlID eval exists expr8 filereadable finddir floor fnamemodify foldlevel foreground get getchar getcmdpos getfontname getftime getloclist getpos getregtype getwinposx glob has_key histadd histnr hostname index inputlist inputsecret isdirectory join libcall line2byte log map match matchdelete matchstr mkdir nextnonblank pathshorten printf pyeval reltime remote_foreground remote_send repeat round screencol searchdecl searchpos setbufvar setline setmatches setqflist settabvar setwinvar shellescape simplify sinh soundfold spellsuggest sqrt str2nr strdisplaywidth stridx strlen strridx strwidth substitute synID synIDtrans system tabpagenr tagfiles tan tempname toupper trunc undofile values visualmode winbufnr winheight winnr winrestview winwidth xor
-syn keyword vimFuncName contained add argc asin browse buflisted bufnr byteidx ceil cindent complete confirm cosh cursor did_filetype empty eventhandler exp extend filewritable findfile fmod foldclosed foldtext function getbufline getcharmod getcmdtype getfperm getftype getmatches getqflist gettabvar getwinposy globpath haslocaldir histdel hlexists iconv input inputrestore insert islocked keys libcallnr lispindent log10 maparg matchadd matchend max mode nr2char pow pumvisible range reltimestr remote_peek remove resolve screenattr screenrow searchpair server2client jobsend jobstart jobstop rpcnotify rpcrequest rpcstart rpcstop
-
-"--- syntax here and above generated by mkvimvim ---
" Special Vim Highlighting (not automatic) {{{1
" commands not picked up by the generator (due to non-standard format)
@@ -96,11 +77,11 @@ endif
syn match vimNumber "\<\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=" skipwhite nextgroup=vimGlobal,vimSubst,vimCommand
syn match vimNumber "-\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=" skipwhite nextgroup=vimGlobal,vimSubst,vimCommand
syn match vimNumber "\<0[xX]\x\+"
-syn match vimNumber "#\x\{6}"
+syn match vimNumber "\%(^\|[^a-zA-Z]\)\zs#\x\{6}"
" All vimCommands are contained by vimIsCommands. {{{2
-syn match vimCmdSep "[:|]\+" skipwhite nextgroup=vimAddress,vimAutoCmd,vimCommand,vimExtCmd,vimFilter,vimLet,vimMap,vimMark,vimSet,vimSyntax,vimUserCmd
-syn match vimIsCommand "\<\h\w*\>" contains=vimCommand
+syn match vimCmdSep "[:|]\+" skipwhite nextgroup=vimAddress,vimAutoCmd,vimCommand,vimIsCommand,vimExtCmd,vimFilter,vimLet,vimMap,vimMark,vimSet,vimSyntax,vimUserCmd,vimOnlyCommand
+syn match vimIsCommand "\<\h\w*\>" contains=vimCommand,vimOnlyCommand
syn match vimVar contained "\<\h[a-zA-Z0-9#_]*\>"
syn match vimVar "\<[bwglsav]:\h[a-zA-Z0-9#_]*\>"
syn match vimFBVar contained "\<[bwglsav]:\h[a-zA-Z0-9#_]*\>"
@@ -131,13 +112,13 @@ syn keyword vimFTOption contained detect indent off on plugin
" Augroup : vimAugroupError removed because long augroups caused sync'ing problems. {{{2
" ======= : Trade-off: Increasing synclines with slower editing vs augroup END error checking.
-syn cluster vimAugroupList contains=vimIsCommand,vimCommand,vimUserCmd,vimExecute,vimNotFunc,vimFuncName,vimFunction,vimFunctionError,vimLineComment,vimSpecFile,vimOper,vimNumber,vimOperParen,vimComment,vimString,vimSubst,vimMark,vimRegister,vimAddress,vimFilter,vimCmplxRepeat,vimComment,vimLet,vimSet,vimAutoCmd,vimRegion,vimSynLine,vimNotation,vimCtrlChar,vimFuncVar,vimContinue
+syn cluster vimAugroupList contains=vimAugroup,vimIsCommand,vimCommand,vimUserCmd,vimExecute,vimNotFunc,vimFuncName,vimFunction,vimFunctionError,vimLineComment,vimMap,vimSpecFile,vimOper,vimNumber,vimOperParen,vimComment,vimString,vimSubst,vimMark,vimRegister,vimAddress,vimFilter,vimCmplxRepeat,vimComment,vimLet,vimSet,vimAutoCmd,vimRegion,vimSynLine,vimNotation,vimCtrlChar,vimFuncVar,vimContinue
if exists("g:vimsyn_folding") && g:vimsyn_folding =~ 'a'
- syn region vimAugroup fold start="\<aug\%[roup]\>\s\+\h\w*" end="\<aug\%[roup]\>\s\+[eE][nN][dD]\>" contains=vimAugroupKey,vimAutoCmd,@vimAugroupList keepend
+ syn region vimAugroup fold matchgroup=vimAugroupKey start="\<aug\%[roup]\>\ze\s\+\K\k*" end="\<aug\%[roup]\>\ze\s\+[eE][nN][dD]\>" contains=vimAutoCmd,@vimAugroupList
else
- syn region vimAugroup start="\<aug\%[roup]\>\s\+\h\w*" end="\<aug\%[roup]\>\s\+[eE][nN][dD]\>" contains=vimAugroupKey,vimAutoCmd,@vimAugroupList keepend
+ syn region vimAugroup matchgroup=vimAugroupKey start="\<aug\%[roup]\>\ze\s\+\K\k*" end="\<aug\%[roup]\>\ze\s\+[eE][nN][dD]\>" contains=vimAutoCmd,@vimAugroupList
endif
-syn match vimAugroup "aug\%[roup]!" contains=vimAugroupKey
+syn match vimAugroup "aug\%[roup]!" contains=vimAugroupKey
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_noaugrouperror")
syn match vimAugroupError "\<aug\%[roup]\>\s\+[eE][nN][dD]\>"
endif
@@ -145,7 +126,6 @@ syn keyword vimAugroupKey contained aug[roup]
" Operators: {{{2
" =========
-" COMBAK: vimOperParen used to have "oneline"
syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,vimContinue
syn match vimOper "\(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\|=\)[?#]\{0,2}" skipwhite nextgroup=vimString,vimSpecFile
syn match vimOper "||\|&&\|[-+.]" skipwhite nextgroup=vimString,vimSpecFile
@@ -158,15 +138,15 @@ endif
" Functions : Tag is provided for those who wish to highlight tagged functions {{{2
" =========
syn cluster vimFuncList contains=vimCommand,vimFunctionError,vimFuncKey,Tag,vimFuncSID
-syn cluster vimFuncBodyList contains=vimAbb,vimAddress,vimAugroupKey,vimAutoCmd,vimCmplxRepeat,vimComment,vimComment,vimContinue,vimCtrlChar,vimEcho,vimEchoHL,vimExecute,vimIf,vimIsCommand,vimFBVar,vimFunc,vimFunction,vimFuncVar,vimHighlight,vimIsCommand,vimLet,vimLineComment,vimMap,vimMark,vimNorm,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegion,vimRegister,vimSet,vimSpecFile,vimString,vimSubst,vimSynLine,vimUnmap,vimUserCommand
+syn cluster vimFuncBodyList contains=vimAbb,vimAddress,vimAugroupKey,vimAutoCmd,vimCmplxRepeat,vimComment,vimComment,vimContinue,vimCtrlChar,vimEcho,vimEchoHL,vimExecute,vimIf,vimIsCommand,vimFBVar,vimFunc,vimFunction,vimFuncVar,vimGlobal,vimHighlight,vimIsCommand,vimLet,vimLineComment,vimMap,vimMark,vimNorm,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegion,vimRegister,vimSet,vimSpecFile,vimString,vimSubst,vimSynLine,vimUnmap,vimUserCommand,nvimUnmap,nvimMap
syn match vimFunction "\<fu\%[nction]!\=\s\+\%(<[sS][iI][dD]>\|[sSgGbBwWtTlL]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)*\ze\s*(" contains=@vimFuncList nextgroup=vimFuncBody
if exists("g:vimsyn_folding") && g:vimsyn_folding =~ 'f'
- syn region vimFuncBody contained fold start="\ze(" matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\)" contains=@vimFuncBodyList
+ syn region vimFuncBody contained fold start="\ze\s*(" matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\)" contains=@vimFuncBodyList
else
- syn region vimFuncBody contained start="\ze(" matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\)" contains=@vimFuncBodyList
+ syn region vimFuncBody contained start="\ze\s*(" matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\)" contains=@vimFuncBodyList
endif
-syn match vimFuncVar contained "a:\(\h\w*\|\d\+\)"
+syn match vimFuncVar contained "a:\(\K\k*\|\d\+\)"
syn match vimFuncSID contained "\c<sid>\|\<s:"
syn keyword vimFuncKey contained fu[nction]
syn match vimFuncBlank contained "\s\+"
@@ -187,14 +167,16 @@ syn match vimSpecFileMod "\(:[phtre]\)\+" contained
" =======================
syn cluster vimUserCmdList contains=vimAddress,vimSyntax,vimHighlight,vimAutoCmd,vimCmplxRepeat,vimComment,vimCtrlChar,vimEscapeBrace,vimFilter,vimFunc,vimFuncName,vimFunction,vimFunctionError,vimIsCommand,vimMark,vimNotation,vimNumber,vimOper,vimRegion,vimRegister,vimLet,vimSet,vimSetEqual,vimSetString,vimSpecFile,vimString,vimSubst,vimSubstRep,vimSubstRange,vimSynLine
syn keyword vimUserCommand contained com[mand]
-syn match vimUserCmd "\<com\%[mand]!\=\>.*$" contains=vimUserAttrb,vimUserCommand,@vimUserCmdList
-syn match vimUserAttrb contained "-n\%[args]=[01*?+]" contains=vimUserAttrbKey,vimOper
-syn match vimUserAttrb contained "-com\%[plete]=" contains=vimUserAttrbKey,vimOper nextgroup=vimUserAttrbCmplt,vimUserCmdError
-syn match vimUserAttrb contained "-ra\%[nge]\(=%\|=\d\+\)\=" contains=vimNumber,vimOper,vimUserAttrbKey
-syn match vimUserAttrb contained "-cou\%[nt]=\d\+" contains=vimNumber,vimOper,vimUserAttrbKey
-syn match vimUserAttrb contained "-bang\=\>" contains=vimOper,vimUserAttrbKey
-syn match vimUserAttrb contained "-bar\>" contains=vimOper,vimUserAttrbKey
-syn match vimUserAttrb contained "-re\%[gister]\>" contains=vimOper,vimUserAttrbKey
+syn match vimUserCmd "\<com\%[mand]!\=\>.*$" contains=vimUserAttrb,vimUserAttrbError,vimUserCommand,@vimUserCmdList
+syn match vimUserAttrbError contained "-\a\+\ze\s"
+syn match vimUserAttrb contained "-nargs=[01*?+]" contains=vimUserAttrbKey,vimOper
+syn match vimUserAttrb contained "-complete=" contains=vimUserAttrbKey,vimOper nextgroup=vimUserAttrbCmplt,vimUserCmdError
+syn match vimUserAttrb contained "-range\(=%\|=\d\+\)\=" contains=vimNumber,vimOper,vimUserAttrbKey
+syn match vimUserAttrb contained "-count\(=\d\+\)\=" contains=vimNumber,vimOper,vimUserAttrbKey
+syn match vimUserAttrb contained "-bang\>" contains=vimOper,vimUserAttrbKey
+syn match vimUserAttrb contained "-bar\>" contains=vimOper,vimUserAttrbKey
+syn match vimUserAttrb contained "-buffer\>" contains=vimOper,vimUserAttrbKey
+syn match vimUserAttrb contained "-register\>" contains=vimOper,vimUserAttrbKey
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_nousercmderror")
syn match vimUserCmdError contained "\S\+\>"
endif
@@ -268,7 +250,7 @@ syn match vimMark "\<norm\%[al]\s\zs'[a-zA-Z0-9]" nextgroup=vimOper,vimMarkNumbe
syn match vimMarkNumber "[-+]\d\+" nextgroup=vimSubst contained contains=vimOper
syn match vimPlainMark contained "'[a-zA-Z0-9]"
-syn match vimRegister '[^,;[{]\zs"[a-zA-Z0-9.%#:_\-/]\ze[^a-zA-Z_":0-9]'
+syn match vimRegister '[^,;[{: \t]\zs"[a-zA-Z0-9.%#:_\-/]\ze[^a-zA-Z_":0-9]'
syn match vimRegister '\<norm\s\+\zs"[a-zA-Z0-9]'
syn match vimRegister '\<normal\s\+\zs"[a-zA-Z0-9]'
syn match vimRegister '@"'
@@ -285,10 +267,10 @@ syn match vimCmplxRepeat '[^a-zA-Z_/\\()]q[0-9a-zA-Z"]\>'lc=1
syn match vimCmplxRepeat '@[0-9a-z".=@:]\ze\($\|[^a-zA-Z]\>\)'
" Set command and associated set-options (vimOptions) with comment {{{2
-syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\." end="$" matchgroup=vimNotation end="<[cC][rR]>" keepend oneline contains=vimSetEqual,vimOption,vimErrSetting,vimComment,vimSetString,vimSetMod
+syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\." end="$" matchgroup=vimNotation end="<[cC][rR]>" keepend oneline contains=vimSetEqual,vimOption,vimErrSetting,vimComment,vimSetString,vimSetMod,vimTermOption,vimOnlyOption
syn region vimSetEqual contained start="[=:]\|[-+^]=" skip="\\\\\|\\\s" end="[| \t]\|$"me=e-1 contains=vimCtrlChar,vimSetSep,vimNotation,vimEnvvar oneline
syn region vimSetString contained start=+="+hs=s+1 skip=+\\\\\|\\"+ end=+"+ contains=vimCtrlChar
-syn match vimSetSep contained "[,:]"
+syn match vimSetSep contained "[,:]" skipwhite nextgroup=vimCommand
syn match vimSetMod contained "&vim\=\|[!&?<]\|all&"
" Let {{{2
@@ -301,7 +283,7 @@ syn keyword vimAbb ab[breviate] ca[bbrev] inorea[bbrev] cnorea[bbrev] norea[bbre
" Autocmd {{{2
" =======
-syn match vimAutoEventList contained "\(!\s\+\)\=\(\a\+,\)*\a\+" contains=vimAutoEvent nextgroup=vimAutoCmdSpace
+syn match vimAutoEventList contained "\(!\s\+\)\=\(\a\+,\)*\a\+" contains=vimAutoEvent,nvimAutoEvent nextgroup=vimAutoCmdSpace
syn match vimAutoCmdSpace contained "\s\+" nextgroup=vimAutoCmdSfxList
syn match vimAutoCmdSfxList contained "\S*"
syn keyword vimAutoCmd au[tocmd] do[autocmd] doautoa[ll] skipwhite nextgroup=vimAutoEventList
@@ -310,7 +292,7 @@ syn keyword vimAutoCmd au[tocmd] do[autocmd] doautoa[ll] skipwhite nextgroup=vim
" ================
syn region vimEcho oneline excludenl matchgroup=vimCommand start="\<ec\%[ho]\>" skip="\(\\\\\)*\\|" end="$\||" contains=vimFunc,vimFuncVar,vimString,vimVar
syn region vimExecute oneline excludenl matchgroup=vimCommand start="\<exe\%[cute]\>" skip="\(\\\\\)*\\|" end="$\||\|<[cC][rR]>" contains=vimFuncVar,vimIsCommand,vimOper,vimNotation,vimOperParen,vimString,vimVar
-syn match vimEchoHL "echohl\=" skipwhite nextgroup=vimGroup,vimHLGroup,vimEchoHLNone
+syn match vimEchoHL "echohl\=" skipwhite nextgroup=vimGroup,vimHLGroup,vimEchoHLNone,vimOnlyHLGroup,nvimHLGroup
syn case ignore
syn keyword vimEchoHLNone none
syn case match
@@ -319,15 +301,17 @@ syn case match
" ====
syn match vimMap "\<map\>!\=\ze\s*[^(]" skipwhite nextgroup=vimMapMod,vimMapLhs
syn keyword vimMap cm[ap] cno[remap] im[ap] ino[remap] lm[ap] ln[oremap] nm[ap] nn[oremap] no[remap] om[ap] ono[remap] smap snor[emap] vm[ap] vn[oremap] xm[ap] xn[oremap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
+syn keyword nvimMap tn[oremap] tm[ap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
syn keyword vimMap mapc[lear] smapc[lear]
syn keyword vimUnmap cu[nmap] iu[nmap] lu[nmap] nun[map] ou[nmap] sunm[ap] unm[ap] unm[ap] vu[nmap] xu[nmap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
+syn keyword nvimUnmap tunm[ap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
syn match vimMapLhs contained "\S\+" contains=vimNotation,vimCtrlChar skipwhite nextgroup=vimMapRhs
syn match vimMapBang contained "!" skipwhite nextgroup=vimMapMod,vimMapLhs
-syn match vimMapMod contained "\c<\(buffer\|expr\|\(local\)\=leader\|plug\|script\|sid\|unique\|silent\)\+>" contains=vimMapModKey,vimMapModErr skipwhite nextgroup=vimMapMod,vimMapLhs
+syn match vimMapMod contained "\c<\(buffer\|expr\|\(local\)\=leader\|nowait\|plug\|script\|sid\|unique\|silent\)\+>" contains=vimMapModKey,vimMapModErr skipwhite nextgroup=vimMapMod,vimMapLhs
syn match vimMapRhs contained ".*" contains=vimNotation,vimCtrlChar skipnl nextgroup=vimMapRhsExtend
-syn match vimMapRhsExtend contained "^\s*\\.*$" contains=vimNotation,vimCtrlChar,vimContinue skipnl nextgroup=vimMapRhsExtend
+syn match vimMapRhsExtend contained "^\s*\\.*$" contains=vimContinue
syn case ignore
-syn keyword vimMapModKey contained buffer expr leader localleader plug script sid silent unique
+syn keyword vimMapModKey contained buffer expr leader localleader nowait plug script sid silent unique
syn case match
" Menus {{{2
@@ -357,8 +341,8 @@ syn case match
" User Function Highlighting {{{2
" (following Gautam Iyer's suggestion)
" ==========================
-syn match vimFunc "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%([a-zA-Z0-9_]\+\.\)*\I[a-zA-Z0-9_.]*\)\ze\s*(" contains=vimFuncName,vimUserFunc,vimExecute
-syn match vimUserFunc contained "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%([a-zA-Z0-9_]\+\.\)*\I[a-zA-Z0-9_.]*\)\|\<\u[a-zA-Z0-9.]*\>\|\<if\>" contains=vimNotation
+syn match vimFunc "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%([a-zA-Z0-9_.]\+\.\)*\I[a-zA-Z0-9_.]*\)\ze\s*(" contains=vimFuncName,vimUserFunc,vimExecute
+syn match vimUserFunc contained "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%([a-zA-Z0-9_.]\+\.\)*\I[a-zA-Z0-9_.]*\)\|\<\u[a-zA-Z0-9.]*\>\|\<if\>" contains=vimNotation
syn match vimNotFunc "\<if\>\|\<el\%[seif]\>\|\<return\>\|\<while\>"
" Errors And Warnings: {{{2
@@ -404,7 +388,7 @@ syn keyword vimSynType contained clear skipwhite nextgroup=vimGroupList
" Syntax: cluster {{{2
syn keyword vimSynType contained cluster skipwhite nextgroup=vimClusterName
-syn region vimClusterName contained matchgroup=vimGroupName start="\h\w*" skip="\\\\\|\\|" matchgroup=vimSep end="$\||" contains=vimGroupAdd,vimGroupRem,vimSynContains,vimSynError
+syn region vimClusterName contained matchgroup=vimGroupName start="\k\+" skip="\\\\\|\\|" matchgroup=vimSep end="$\||" contains=vimGroupAdd,vimGroupRem,vimSynContains,vimSynError
syn match vimGroupAdd contained "add=" nextgroup=vimGroupList
syn match vimGroupRem contained "remove=" nextgroup=vimGroupList
syn cluster vimFuncBodyList add=vimSynType,vimGroupAdd,vimGroupRem
@@ -416,14 +400,14 @@ syn cluster vimFuncBodyList add=vimSynType
" Syntax: keyword {{{2
syn cluster vimSynKeyGroup contains=vimSynNextgroup,vimSynKeyOpt,vimSynKeyContainedin
syn keyword vimSynType contained keyword skipwhite nextgroup=vimSynKeyRegion
-syn region vimSynKeyRegion contained oneline keepend matchgroup=vimGroupName start="\h\w*" skip="\\\\\|\\|" matchgroup=vimSep end="|\|$" contains=@vimSynKeyGroup
+syn region vimSynKeyRegion contained oneline keepend matchgroup=vimGroupName start="\k\+" skip="\\\\\|\\|" matchgroup=vimSep end="|\|$" contains=@vimSynKeyGroup
syn match vimSynKeyOpt contained "\<\(conceal\|contained\|transparent\|skipempty\|skipwhite\|skipnl\)\>"
syn cluster vimFuncBodyList add=vimSynType
" Syntax: match {{{2
syn cluster vimSynMtchGroup contains=vimMtchComment,vimSynContains,vimSynError,vimSynMtchOpt,vimSynNextgroup,vimSynRegPat,vimNotation
syn keyword vimSynType contained match skipwhite nextgroup=vimSynMatchRegion
-syn region vimSynMatchRegion contained keepend matchgroup=vimGroupName start="\h\w*" matchgroup=vimSep end="|\|$" contains=@vimSynMtchGroup
+syn region vimSynMatchRegion contained keepend matchgroup=vimGroupName start="\k\+" matchgroup=vimSep end="|\|$" contains=@vimSynMtchGroup
syn match vimSynMtchOpt contained "\<\(conceal\|transparent\|contained\|excludenl\|skipempty\|skipwhite\|display\|extend\|skipnl\|fold\)\>"
if has("conceal")
syn match vimSynMtchOpt contained "\<cchar=" nextgroup=vimSynMtchCchar
@@ -438,10 +422,10 @@ syn keyword vimSynType contained enable list manual off on reset
syn cluster vimSynRegPatGroup contains=vimPatSep,vimNotPatSep,vimSynPatRange,vimSynNotPatRange,vimSubstSubstr,vimPatRegion,vimPatSepErr,vimNotation
syn cluster vimSynRegGroup contains=vimSynContains,vimSynNextgroup,vimSynRegOpt,vimSynReg,vimSynMtchGrp
syn keyword vimSynType contained region skipwhite nextgroup=vimSynRegion
-syn region vimSynRegion contained keepend matchgroup=vimGroupName start="\h\w*" skip="\\\\\|\\|" end="|\|$" contains=@vimSynRegGroup
+syn region vimSynRegion contained keepend matchgroup=vimGroupName start="\k\+" skip="\\\\\|\\|" end="|\|$" contains=@vimSynRegGroup
syn match vimSynRegOpt contained "\<\(conceal\(ends\)\=\|transparent\|contained\|excludenl\|skipempty\|skipwhite\|display\|keepend\|oneline\|extend\|skipnl\|fold\)\>"
syn match vimSynReg contained "\(start\|skip\|end\)="he=e-1 nextgroup=vimSynRegPat
-syn match vimSynMtchGrp contained "matchgroup=" nextgroup=vimGroup,vimHLGroup
+syn match vimSynMtchGrp contained "matchgroup=" nextgroup=vimGroup,vimHLGroup,vimOnlyHLGroup,nvimHLGroup
syn region vimSynRegPat contained extend start="\z([-`~!@#$%^&*_=+;:'",./?]\)" skip="\\\\\|\\\z1" end="\z1" contains=@vimSynRegPatGroup skipwhite nextgroup=vimSynPatMod,vimSynReg
syn match vimSynPatMod contained "\(hs\|ms\|me\|hs\|he\|rs\|re\)=[se]\([-+]\d\+\)\="
syn match vimSynPatMod contained "\(hs\|ms\|me\|hs\|he\|rs\|re\)=[se]\([-+]\d\+\)\=," nextgroup=vimSynPatMod
@@ -464,9 +448,9 @@ syn keyword vimSyncRegion contained region skipwhite nextgroup=vimSynReg
syn match vimSyncLinebreak contained "\<linebreaks=" skipwhite nextgroup=vimNumber
syn keyword vimSyncLinecont contained linecont skipwhite nextgroup=vimSynRegPat
syn match vimSyncLines contained "\(min\|max\)\=lines=" nextgroup=vimNumber
-syn match vimSyncGroupName contained "\h\w*" skipwhite nextgroup=vimSyncKey
+syn match vimSyncGroupName contained "\k\+" skipwhite nextgroup=vimSyncKey
syn match vimSyncKey contained "\<groupthere\|grouphere\>" skipwhite nextgroup=vimSyncGroup
-syn match vimSyncGroup contained "\h\w*" skipwhite nextgroup=vimSynRegPat,vimSyncNone
+syn match vimSyncGroup contained "\k\+" skipwhite nextgroup=vimSynRegPat,vimSyncNone
syn keyword vimSyncNone contained NONE
" Additional IsCommand, here by reasons of precedence {{{2
@@ -518,7 +502,7 @@ syn match vimHiNmbr contained '\d\+'
syn keyword vimHiClear contained clear nextgroup=vimHiGroup
" Highlight: link {{{2
-syn region vimHiLink contained oneline matchgroup=vimCommand start="\(\<hi\%[ghlight]\s\+\)\@<=\(\(def\%[ault]\s\+\)\=link\>\|\<def\>\)" end="$" contains=vimHiGroup,vimGroup,vimHLGroup,vimNotation
+syn region vimHiLink contained oneline matchgroup=vimCommand start="\(\<hi\%[ghlight]\s\+\)\@<=\(\(def\%[ault]\s\+\)\=link\>\|\<def\>\)" end="$" contains=vimHiGroup,vimGroup,vimHLGroup,vimNotation,vimOnlyHLGroup,nvimHLGroup
syn cluster vimFuncBodyList add=vimHiLink
" Control Characters {{{2
@@ -701,6 +685,10 @@ if !exists("g:vimsyn_noerror")
hi def link vimSubstFlagErr vimError
hi def link vimSynCaseError vimError
hi def link vimBufnrWarn vimWarn
+ hi def link vimOnlyCommand vimError
+ hi def link vimTermOption vimError
+ hi def link vimOnlyOption vimError
+ hi def link vimOnlyHLGroup vimError
endif
hi def link vimAbb vimCommand
@@ -710,6 +698,7 @@ hi def link vimAuHighlight vimHighlight
hi def link vimAutoCmdOpt vimOption
hi def link vimAutoCmd vimCommand
hi def link vimAutoEvent Type
+hi def link nvimAutoEvent vimAutoEvent
hi def link vimAutoSet vimCommand
hi def link vimBehaveModel vimBehave
hi def link vimBehave vimCommand
@@ -756,6 +745,7 @@ hi def link vimHiNmbr Number
hi def link vimHiStartStop vimHiTerm
hi def link vimHiTerm Type
hi def link vimHLGroup vimGroup
+hi def link nvimHLGroup vimHLGroup
hi def link vimHLMod PreProc
hi def link vimInsert vimString
hi def link vimKeyCode vimSpecFile
@@ -766,6 +756,7 @@ hi def link vimMapBang vimCommand
hi def link vimMapModKey vimFuncSID
hi def link vimMapMod vimBracket
hi def link vimMap vimCommand
+hi def link nvimMap vimMap
hi def link vimMark Number
hi def link vimMarkNumber vimNumber
hi def link vimMenuMod vimMapMod
@@ -834,6 +825,7 @@ hi def link vimSyntax vimCommand
hi def link vimSynType vimSpecial
hi def link vimTodo Todo
hi def link vimUnmap vimMap
+hi def link nvimUnmap vimMap
hi def link vimUserAttrbCmpltFunc Special
hi def link vimUserAttrbCmplt vimSpecial
hi def link vimUserAttrbKey vimOption
diff --git a/runtime/syntax/vimnormal.vim b/runtime/syntax/vimnormal.vim
new file mode 100644
index 0000000000..df672c5236
--- /dev/null
+++ b/runtime/syntax/vimnormal.vim
@@ -0,0 +1,16 @@
+syn match normalOp /[dcrypoaxv!"#%&.-\/:<>=?@ABCDGHIJKLMNOPQRSUVWXYZgmqstz~iu]/ nextgroup=normalMod
+syn match normalMod /m\@<![ia]/
+syn match normalObject /["'()<>BW\[\]`bstweE{}ftFT;,$]/
+syn match normalCount /[0-9]/
+syn region normalSearch start=/[/?]\@<=./ end=/.<CR>\@=/ contains=normalKey keepend
+syn region normalChange start=/\([cr][wWbBeE()\[\]{}pst]\)\@<=./ end=/.\@=/ contains=normalKey keepend
+syn match normalCharSearch /\c[ftr]\@<=\w/
+syn match normalMark /\(f\@<!m\)\@<=[a-zA-Z0-9]/
+syn match normalKey /<'\@!.\{-}>'\@!/
+
+hi! link normalOp Operator
+hi! link normalMod PreProc
+hi! link normalObject Structure
+hi! link normalCount Number
+hi! link normalMark Identifier
+hi! link normalKey Special
diff --git a/runtime/syntax/zimbu.vim b/runtime/syntax/zimbu.vim
index c859a2f815..1a7a485e6f 100644
--- a/runtime/syntax/zimbu.vim
+++ b/runtime/syntax/zimbu.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Zimbu
" Maintainer: Bram Moolenaar
-" Last Change: 2012 Jun 01
+" Last Change: 2014 Nov 23
if exists("b:current_syntax")
finish
@@ -12,7 +12,10 @@ syn include @Ccode syntax/c.vim
syn keyword zimbuTodo TODO FIXME XXX contained
syn match zimbuNoBar "|" contained
syn match zimbuParam "|[^| ]\+|" contained contains=zimbuNoBar
-syn match zimbuComment "#.*$" contains=zimbuTodo,zimbuParam,@Spell
+syn match zimbuNoBacktick "`" contained
+syn match zimbuCode "`[^`]\+`" contained contains=zimbuNoBacktick
+syn match zimbuComment "#.*$" contains=zimbuTodo,zimbuParam,zimbuCode,@Spell
+syn match zimbuComment "/\*.\{-}\*/" contains=zimbuTodo,zimbuParam,zimbuCode,@Spell
syn match zimbuChar "'\\\=.'"
@@ -28,27 +31,32 @@ syn keyword zimbuBasicType fixed1 fixed2 fixed3 fixed4 fixed5 fixed6
syn keyword zimbuBasicType fixed7 fixed8 fixed9 fixed10 fixed11 fixed12
syn keyword zimbuBasicType fixed13 fixed14 fixed15
-syn keyword zimbuCompType string stringval cstring varstring
-syn keyword zimbuCompType bytes varbytes
-syn keyword zimbuCompType tuple array list dict multiDict set multiSet
+syn keyword zimbuCompType string varString
+syn keyword zimbuCompType byteString varByteString
+syn keyword zimbuCompType tuple array list dict dictList set callback
+syn keyword zimbuCompType sortedList multiDict multiDictList multiSet
syn keyword zimbuCompType complex complex32 complex64 complex80 complex128
syn keyword zimbuCompType proc func def thread evalThread lock cond pipe
-syn keyword zimbuType VAR ANY USE GET
+syn keyword zimbuType VAR dyn type USE GET
syn match zimbuType "IO.File"
syn match zimbuType "IO.Stat"
-syn keyword zimbuStatement IF ELSE ELSEIF WHILE REPEAT FOR IN TO STEP
+syn keyword zimbuStatement IF ELSE ELSEIF IFNIL WHILE REPEAT FOR IN TO STEP
syn keyword zimbuStatement DO UNTIL SWITCH WITH
syn keyword zimbuStatement TRY CATCH FINALLY
syn keyword zimbuStatement GENERATE_IF GENERATE_ELSE GENERATE_ELSEIF
+syn keyword zimbuStatement GENERATE_ERROR
+syn keyword zimbuStatement BUILD_IF BUILD_ELSE BUILD_ELSEIF
syn keyword zimbuStatement CASE DEFAULT FINAL ABSTRACT VIRTUAL DEFINE REPLACE
syn keyword zimbuStatement IMPLEMENTS EXTENDS PARENT LOCAL
-syn keyword zimbuStatement PART ALIAS CONNECT WRAP
+syn keyword zimbuStatement PART ALIAS TYPE CONNECT WRAP
syn keyword zimbuStatement BREAK CONTINUE PROCEED
-syn keyword zimbuStatement RETURN EXIT THROW
+syn keyword zimbuStatement RETURN EXIT THROW DEFER
syn keyword zimbuStatement IMPORT AS OPTIONS MAIN
-syn keyword zimbuStatement INTERFACE MODULE ENUM BITS SHARED
+syn keyword zimbuStatement INTERFACE PIECE INCLUDE MODULE ENUM BITS
+syn keyword zimbuStatement SHARED STATIC
+syn keyword zimbuStatement LAMBDA
syn match zimbuStatement "\<\(FUNC\|PROC\|DEF\)\>"
syn match zimbuStatement "\<CLASS\>"
syn match zimbuStatement "}"
@@ -61,10 +69,13 @@ syn match zimbuAttribute "@default\>"
syn match zimbuAttribute "@define\>"
syn match zimbuAttribute "@replace\>"
syn match zimbuAttribute "@final\>"
+syn match zimbuAttribute "@primitive\>"
+syn match zimbuAttribute "@notOnExit\>"
syn match zimbuAttribute "@private\>"
syn match zimbuAttribute "@protected\>"
syn match zimbuAttribute "@public\>"
+syn match zimbuAttribute "@local\>"
syn match zimbuAttribute "@file\>"
syn match zimbuAttribute "@directory\>"
syn match zimbuAttribute "@read=private\>"
@@ -78,15 +89,22 @@ syn match zimbuAttribute "@items=public\>"
syn match zimbuAttribute "@items=file\>"
syn match zimbuAttribute "@items=directory\>"
-syn keyword zimbuMethod NEW EQUAL COPY COMPARE SIZE GET SET
+syn keyword zimbuMethod NEW EQUAL COPY COMPARE SIZE GET SET INIT EARLYINIT
syn keyword zimbuOperator IS ISNOT ISA ISNOTA
-syn keyword zimbuModule ARG CHECK E IO PROTO SYS HTTP ZC ZWT TIME THREAD
+syn keyword zimbuModule ARG CHECK E GC IO LOG PROTO SYS HTTP ZC ZWT T TIME THREAD
-syn match zimbuString +"\([^"\\]\|\\.\)*\("\|$\)+
+syn match zimbuImport "\.\zsPROTO"
+syn match zimbuImport "\.\zsCHEADER"
+
+"syn match zimbuString +"\([^"\\]\|\\.\)*\("\|$\)+ contains=zimbuStringExpr
+syn region zimbuString start=+"+ skip=+[^"\\]\|\\.+ end=+"\|$+ contains=zimbuStringExpr
syn match zimbuString +R"\([^"]\|""\)*\("\|$\)+
-syn region zimbuString start=+'''+ end=+'''+
+syn region zimbuLongString start=+''"+ end=+"''+
+syn match zimbuStringExpr +\\([^)]*)+hs=s+2,he=e-1 contained contains=zimbuString,zimbuParenPairOuter
+syn region zimbuParenPairOuter start=+(+ms=s+1 end=+)+me=e-1 contained contains=zimbuString,zimbuParenPair
+syn region zimbuParenPair start=+(+ end=+)+ contained contains=zimbuString,zimbuParenPair
syn keyword zimbuFixed TRUE FALSE NIL THIS THISTYPE FAIL OK
syn keyword zimbuError NULL
@@ -97,12 +115,18 @@ syn match zimbuSpaceError display excludenl "\S\s\+$"ms=s+1
syn match zimbuSpaceError display " \+\t"
syn match zimbuSpaceError display "\t\+ "
-syn match zimbuUses contained "uses([a-zA-Z_ ,]*)"
+syn match zimbuUses contained "\<uses([a-zA-Z_ ,]*)"
+syn match zimbuBlockgc contained "blockgc"
syn match zimbuBlockComment contained " #.*"
-syn region zimbuCregion matchgroup=zimbuCblock start="^>>>" end="^<<<.*" contains=@Ccode,zimbuUses,zimbuBlockComment keepend
+syn region zimbuCregion matchgroup=zimbuCblock start="^>>>" end="^<<<.*" contains=@Ccode,zimbuUses,zimbuBlockgc,zimbuBlockComment keepend
+
+" Assume long strings and C regions don't take more than 200 lines.
+syn sync minlines=200
-syn sync minlines=2000
+" When we find the start of a long string, without a # or " before it, we are
+" sure to be inside a long string.
+syn sync match zimbuLongStringSync grouphere zimbuLongString +^[^"#]*''\"+
hi def link zimbuBasicType Type
hi def link zimbuCompType Type
@@ -111,17 +135,23 @@ hi def link zimbuStatement Statement
hi def link zimbuOperator Statement
hi def link zimbuMethod PreProc
hi def link zimbuModule PreProc
+hi def link zimbuImport PreProc
hi def link zimbuUses PreProc
+hi def link zimbuBlockgc PreProc
hi def link zimbuAttribute PreProc
hi def link zimbuString Constant
+hi def link zimbuLongString Special
hi def link zimbuChar Constant
hi def link zimbuFixed Constant
hi def link zimbuComment Comment
+hi def link zimbuCommentStart zimbuComment
hi def link zimbuBlockComment Comment
hi def link zimbuCblock Comment
hi def link zimbuTodo Todo
hi def link zimbuParam Constant
+hi def link zimbuCode Statement
hi def link zimbuNoBar Ignore
+hi def link zimbuNoBacktick Ignore
hi def link zimbuSpaceError Error
hi def link zimbuError Error
diff --git a/runtime/tutor/en/vim-01-beginner.tutor b/runtime/tutor/en/vim-01-beginner.tutor
new file mode 100644
index 0000000000..bda4e3537e
--- /dev/null
+++ b/runtime/tutor/en/vim-01-beginner.tutor
@@ -0,0 +1,955 @@
+# Welcome to the VIM Tutor
+
+Vim is a very powerful editor that has many commands, too many to explain in a
+tutor such as this. This tutor is designed to describe enough of the commands
+that you will be able to easily use Vim as an all-purpose editor. It is
+IMPORTANT to remember that this tutor is set up to teach by use. That means
+that you need to do the exercises to learn them properly. If you only read
+the text, you will soon forget what is most important!
+
+NOTE: The commands in the lessons will modify the text, but those changes won't
+be saved. Don't worry about messing things up; just remember that pressing
+[<Esc>](<Esc>) and then [u](u) will undo the latest change.
+
+This tutorial is interactive, and there are a few things you should know.
+Pressing [<Enter>](<Enter>) over text highlighted [like this](holy-grail) will take you to some relevant
+help (hopefully), and pressing K over any word will try to do so too. Sometimes
+you will be required to modify text like
+---> this here {expect:this here}
+Once you have done the changes correctly, the ✗ sign at the left will change
+to ✓. I imagine you can already see how neat Vim can be ;)
+Other times, you'll be prompted to run a command (I'll explain this later):
+~~~ cmd
+ :help <Enter>
+~~~
+or press a sequence of keys
+~~~ normal
+ <Esc>0f<Space>d3wP$P
+~~~
+
+Text within <'s and >'s (like `<Enter>`{normal}) describes a key to press instead of text
+to type.
+
+Now, make sure that your Shift-Lock key is NOT depressed and press the `j`{normal}
+key enough times to move the cursor so that Lesson 1.1 completely fills the
+screen.
+
+## Lesson 1.1: MOVING THE CURSOR
+
+** To move the cursor, press the `h`, `j`, `k`, `l` keys as indicated. **
+
+ ↑
+ k Hint: The h key is at the left and moves left.
+ ← h l → The l key is at the right and moves right.
+ j The j key looks like a down arrow.
+ ↓
+
+ 1. Move the cursor around the screen until you are comfortable.
+
+ 2. Hold down the down key (j) until it repeats.
+ Now you know how to move to the next lesson.
+
+ 3. Using the down key, move to Lesson 1.2.
+
+NOTE: If you are ever unsure about something you typed, press <Esc> to place
+ you in Normal mode. Then retype the command you wanted.
+
+NOTE: The cursor keys should also work. But using hjkl you will be able to
+ move around much faster, once you get used to it. Really!
+
+# Lesson 1.2: EXITING VIM
+
+!! NOTE: Before executing any of the steps below, read this entire lesson !!
+
+ 1. Press the <Esc> key (to make sure you are in [Normal mode]().
+
+ 2. Type:
+
+ `:q!`{vim} `<Enter>`{normal}.
+
+ This exits the editor, DISCARDING any changes you have made.
+
+ 3. Open vim and get back here by executing the command that got you into this
+ tutor. That might be:
+
+ :Tutor <Enter>
+
+ 4. If you have these steps memorized and are confident, execute steps
+ 1 through 3 to exit and re-enter the editor.
+
+NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
+ will learn how to save the changes to a file.
+
+ 5. Move the cursor down to Lesson 1.3.
+
+## Lesson 1.3: TEXT EDITING - DELETION
+
+** Press `x`{normal} to delete the character under the cursor. **
+
+1. Move the cursor to the line below marked --->.
+
+2. To fix the errors, move the cursor until it is on top of the
+ character to be deleted.
+
+3. Press [the x key](x) to delete the unwanted character.
+
+4. Repeat steps 2 through 4 until the sentence is correct.
+
+---> The ccow jumpedd ovverr thhe mooon. {expect:The cow jumped over the moon.}
+
+5. Now that the line is correct, go on to Lesson 1.4.
+
+NOTE: As you go through this tutor, do not try to memorize, learn by usage.
+
+# Lesson 1.4: TEXT EDITING: INSERTION
+
+** Press `i`{normal} to insert text. **
+
+ 1. Move the cursor to the first line below marked --->.
+
+ 2. To make the first line the same as the second, move the cursor on top
+ of the first character AFTER where the text is to be inserted.
+
+ 3. Press i and type in the necessary additions.
+
+ 4. As each error is fixed press <Esc> to return to Normal mode.
+ Repeat steps 2 through 4 to correct the sentence.
+
+---> There is text misng this . {expect:There is some text missing from this line.}
+---> There is some text missing from this line. {expect:There is some text missing from this line.}
+
+ 5. When you are comfortable inserting text move to lesson 1.5.
+
+# Lesson 1.5: TEXT EDITING: APPENDING
+
+** Press `A`{normal} to append text. **
+
+ 1. Move the cursor to the first line below marked --->.
+ It does not matter on what character the cursor is in that line.
+
+ 2. Press [A](A) and type in the necessary additions.
+
+ 3. As the text has been appended press <Esc> to return to Normal mode.
+
+ 4. Move the cursor to the second line marked ---> and repeat
+ steps 2 and 3 to correct this sentence.
+
+---> There is some text missing from th {expect:There is some text missing from this line.}
+---> There is some text missing from this line. {expect:There is some text missing from this line.}
+---> There is also some text miss {expect:There is also some text missing here.}
+---> There is also some text missing here. {expect:There is also some text missing here.}
+
+ 5. When you are comfortable appending text move to lesson 1.6.
+
+# Lesson 1.6: EDITING A FILE
+
+** Use `:wq`{vim} to save a file and exit. **
+
+!! NOTE: Before executing any of the steps below, read this entire lesson !!
+
+ 1. Exit this tutor as you did in lesson 1.2: :q!
+ Or, if you have access to another terminal, do the following there.
+
+ 2. At the shell prompt type this command:
+~~~ sh
+ $ vim tutor
+~~~
+ 'vim' is the command to start the Vim editor, 'tutor' is the name of the
+ file you wish to edit. Use a file that may be changed.
+
+ 3. Insert and delete text as you learned in the previous lessons.
+
+ 4. Save the file with changes and exit Vim with:
+~~~ cmd
+ :wq
+~~~
+
+ Note you'll need to press `<Enter>` to execute the command.
+
+ 5. If you have quit vimtutor in step 1 restart the vimtutor and move down to
+ the following summary.
+
+ 6. After reading the above steps and understanding them: do it.
+
+# Lesson 1 SUMMARY
+
+ 1. The cursor is moved using either the arrow keys or the hjkl keys.
+ h (left) j (down) k (up) l (right)
+
+ 2. To start Vim from the shell prompt type:
+
+~~~ sh
+ $ vim FILENAME
+~~~
+
+ 3. To exit Vim type: <Esc> :q! <Enter> to trash all changes.
+ OR type: <Esc> :wq <Enter> to save the changes.
+
+ 4. To delete the character at the cursor type: `x`{normal}
+
+ 5. To insert or append text type:
+ `i`{normal} type inserted text `<Esc>`{normal} insert before the cursor
+ `A`{normal} type appended text `<Esc>`{normal} append after the line
+
+NOTE: Pressing `<Esc>`{normal} will place you in Normal mode or will cancel
+ an unwanted and partially completed command.
+
+Now continue with Lesson 2.
+
+# Lesson 2.1: DELETION COMMANDS
+
+** Type `dw`{normal} to delete a word. **
+
+ 1. Press `<Esc>`{normal} to make sure you are in Normal mode.
+
+ 2. Move the cursor to the line below marked --->.
+
+ 3. Move the cursor to the beginning of a word that needs to be deleted.
+
+ 4. Type [d](d)[w](w) to make the word disappear.
+
+---> There are a some words fun that don't belong paper in this sentence. {expect:There are some words that don't belong in this sentence.}
+
+ 5. Repeat steps 3 and 4 until the sentence is correct and go to Lesson 2.2.
+
+# Lesson 2.2: MORE DELETION COMMANDS
+
+** Type `d$`{normal} to delete to the end of the line. **
+
+ 1. Press <Esc> to make sure you are in Normal mode.
+
+ 2. Move the cursor to the line below marked --->.
+
+ 3. Move the cursor to the end of the correct line (AFTER the first . ).
+
+ 4. Type `d$`{normal} to delete to the end of the line.
+
+---> Somebody typed the end of this line twice. end of this line twice. {expect:ANYTHING}
+
+ 5. Move on to Lesson 2.3 to understand what is happening.
+
+# Lesson 2.3: ON OPERATORS AND MOTIONS
+
+
+Many commands that change text are made from an [operator](operator) and a [motion](navigation).
+The format for a delete command with the [d](d) delete operator is as follows:
+
+ d motion
+
+ Where:
+ d - is the delete operator.
+ motion - is what the operator will operate on (listed below).
+
+ A short list of motions:
+ [w](w) - until the start of the next word, EXCLUDING its first character.
+ [e](e) - to the end of the current word, INCLUDING the last character.
+ [$]($) - to the end of the line, INCLUDING the last character.
+
+ Thus typing `de`{normal} will delete from the cursor to the end of the word.
+
+NOTE: Pressing just the motion while in Normal mode without an operator will
+ move the cursor as specified.
+
+# Lesson 2.4: USING A COUNT FOR A MOTION
+
+** Typing a number before a motion repeats it that many times. **
+
+ 1. Move the cursor to the start of the line marked ---> below.
+
+ 2. Type `2w`{normal} to move the cursor two words forward.
+
+ 3. Type `3e`{normal} to move the cursor to the end of the third word forward.
+
+ 4. Type `0`{normal} ([zero](0)) to move to the start of the line.
+
+ 5. Repeat steps 2 and 3 with different numbers.
+
+---> This is just a line with words you can move around in. {expect:ANYTHING}
+
+ 6. Move on to Lesson 2.5.
+
+# Lesson 2.5: USING A COUNT TO DELETE MORE
+
+** Typing a number with an operator repeats it that many times. **
+
+In the combination of the delete operator and a motion mentioned above you
+insert a count before the motion to delete more:
+ d number motion
+
+ 1. Move the cursor to the first UPPER CASE word in the line marked --->.
+
+ 2. Type `d2w`{normal} to delete the two UPPER CASE words
+
+ 3. Repeat steps 1 and 2 with a different count to delete the consecutive
+ UPPER CASE words with one command
+
+---> this ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up. {expect:this line of words is cleaned up.}
+
+# Lesson 2.6: OPERATING ON LINES
+
+** Type dd to delete a whole line. **
+
+ Due to the frequency of whole line deletion, the designers of Vi decided
+ it would be easier to simply type two d's to delete a line.
+
+ 1. Move the cursor to the second line in the phrase below.
+ 2. Type [dd](dd) to delete the line.
+ 3. Now move to the fourth line.
+ 4. Type `2dd`{normal} to delete two lines.
+
+---> 1) Roses are red, {expect:ANYTHING}
+---> 2) Mud is fun, {expect:ANYTHING}
+---> 3) Violets are blue, {expect:ANYTHING}
+---> 4) I have a car, {expect:ANYTHING}
+---> 5) Clocks tell time, {expect:ANYTHING}
+---> 6) Sugar is sweet {expect:ANYTHING}
+---> 7) And so are you. {expect:ANYTHING}
+
+# Lesson 2.7: THE UNDO COMMAND
+
+** Press u to undo the last commands, U to fix a whole line. **
+
+ 1. Move the cursor to the line below marked ---> and place it on the
+ first error.
+ 2. Type `x`{normal} to delete the first unwanted character.
+ 3. Now type `u`{normal} to undo the last command executed.
+ 4. This time fix all the errors on the line using the `x`{normal} command.
+ 5. Now type a capital `U`{normal} to return the line to its original state.
+ 6. Now type `u`{normal} a few times to undo the U and preceding commands.
+ 7. Now type `<Ctrl-r>`{normal} a few times to redo the commands (undo the undo's).
+
+---> Fiix the errors oon thhis line and reeplace them witth undo. {expect:Fix the errors on this line and replace them with undo.}
+
+ 8. These are very useful commands. Now move on to the Lesson 2 Summary.
+
+# Lesson 2 SUMMARY
+
+ 1. To delete from the cursor up to the next word type: `dw`{normal}
+ 2. To delete from the cursor to the end of a line type: `d$`{normal}
+ 3. To delete a whole line type: `dd`{normal}
+ 4. To repeat a motion prepend it with a number: `2w`{normal}
+
+ 5. The format for a change command is:
+ operator [number] motion
+ where:
+ operator - is what to do, such as [d](d) for delete
+ [number] - is an optional count to repeat the motion
+ motion - moves over the text to operate on, such as:
+ [w](w) (word),
+ [$]($) (to the end of line), etc.
+
+ 6. To move to the start of the line use a zero: [0](0)
+
+ 7. To undo previous actions, type: `u`{normal} (lowercase u)
+ To undo all the changes on a line, type: `U`{normal} (capital U)
+ To undo the undo's, type: `<Ctrl-r>`{normal}
+
+# Lesson 3.1: THE PUT COMMAND
+
+** Type p to put previously deleted text after the cursor. **
+
+ 1. Move the cursor to the first ---> line below.
+
+ 2. Type `dd`{normal} to delete the line and store it in a Vim register.
+
+ 3. Move the cursor to the c) line, ABOVE where the deleted line should go.
+
+ 4. Type `p`{normal} to put the line below the cursor.
+
+ 5. Repeat steps 2 through 4 to put all the lines in correct order.
+
+---> d) Can you learn too? {expect:ANYTHING}
+---> b) Violets are blue, {expect:ANYTHING}
+---> c) Intelligence is learned, {expect:ANYTHING}
+---> a) Roses are red, {expect:ANYTHING}
+
+# Lesson 3.2: THE REPLACE COMMAND
+
+** Type `rx`{normal} to replace the character at the cursor with x. **
+
+ 1. Move the cursor to the first line below marked --->.
+
+ 2. Move the cursor so that it is on top of the first error.
+
+ 3. Type `r`{normal} and then the character which should be there.
+
+ 4. Repeat steps 2 and 3 until the first line is equal to the second one.
+
+---> Whan this lime was tuoed in, someone presswd some wrojg keys! {expect:When this line was typed in, someone pressed some wrong keys!}
+---> When this line was typed in, someone pressed some wrong keys! {expect:When this line was typed in, someone pressed some wrong keys!}
+
+ 5. Now move on to Lesson 3.3.
+
+NOTE: Remember that you should be learning by doing, not memorization.
+
+# Lesson 3.3: THE CHANGE OPERATOR
+
+** To change until the end of a word, type `ce`{normal} **
+
+ 1. Move the cursor to the first line below marked --->.
+
+ 2. Place the cursor on the "u" in "lubw".
+
+ 3. Type `ce`{normal} and the correct word (in this case, type "ine" ).
+
+ 4. Press `<Esc>`{normal} and move to the next character that needs to be changed.
+
+ 5. Repeat steps 3 and 4 until the first sentence is the same as the second.
+
+---> This lubw has a few wptfd that mrrf changing usf the change operator. {expect:This line has a few words that need changing using the change operator.}
+---> This line has a few words that need changing using the change operator. {expect:This line has a few words that need changing using the change operator.}
+
+Notice that [c](c)e deletes the word and places you in Insert mode.
+
+# Lesson 3.4: MORE CHANGES USING c
+
+** The change operator is used with the same motions as delete. **
+
+ 1. The change operator works in the same way as delete. The format is:
+
+ c [number] motion
+
+ 2. The motions are the same, such as `w`{normal} (word) and `$`{normal} (end of line).
+
+ 3. Move to the first line below marked --->.
+
+ 4. Move the cursor to the first error.
+
+ 5. Type `c$`{normal} and type the rest of the line like the second and press `<Esc>`{normal}.
+
+---> The end of this line needs some help to make it like the second. {expect:The end of this line needs to be corrected using the c$ command.}
+---> The end of this line needs to be corrected using the c$ command. {expect:The end of this line needs to be corrected using the c$ command.}
+
+NOTE: You can use the Backspace key to correct mistakes while typing.
+
+# Lesson 3 SUMMARY
+
+ 1. To put back text that has just been deleted, type [p](p). This puts the
+ deleted text AFTER the cursor (if a line was deleted it will go on the
+ line below the cursor).
+
+ 2. To replace the character under the cursor, type [r](r) and then the
+ character you want to have there.
+
+ 3. The [change operator](c) allows you to change from the cursor to where the
+ motion takes you. eg. Type `ce`{normal} to change from the cursor to the end of
+ the word, `c$`{normal} to change to the end of a line.
+
+ 4. The format for change is:
+
+ c [number] motion
+
+Now go on to the next lesson.
+
+# Lesson 4.1: CURSOR LOCATION AND FILE STATUS
+
+** Type `<Ctrl-g>`{normal} to show your location in the file and the file status.
+ Type `G`{normal} to move to a line in the file. **
+
+NOTE: Read this entire lesson before executing any of the steps!!
+
+ 1. Hold down the `<Ctrl>`{normal} key and press `g`{normal}. We call this `<Ctrl-g>`{normal}.
+ A message will appear at the bottom of the page with the filename and the
+ position in the file. Remember the line number for Step 3.
+
+NOTE: You may see the cursor position in the lower right corner of the screen
+ This happens when the ['ruler']('ruler') option is set (see :help 'ruler' )
+
+ 2. Press [G](G) to move you to the bottom of the file.
+ Type [gg](gg) to move you to the start of the file.
+
+ 3. Type the number of the line you were on and then `G`{normal} . This will
+ return you to the line you were on when you first pressed `<Ctrl-g>`{normal}.
+
+ 4. If you feel confident to do this, execute steps 1 through 3.
+
+# Lesson 4.2: THE SEARCH COMMAND
+
+** Type `/`{normal} followed by a phrase to search for the phrase. **
+
+ 1. In Normal mode type the `/`{normal} character. Notice that it and the cursor
+ appear at the bottom of the screen as with the : command.
+
+ 2. Now type 'errroor' `<Enter>`{normal}. This is the word you want to search for.
+
+ 3. To search for the same phrase again, simply type [n](n) .
+ To search for the same phrase in the opposite direction, type [N](N) .
+
+ 4. To search for a phrase in the backward direction, use [?](?) instead of / .
+
+ 5. To go back to where you came from press `<Ctrl-o>`{normal} (Keep Ctrl down while
+ pressing the letter o). Repeat to go back further. `<Ctrl-i>`{normal} goes forward.
+
+---> "errroor" is not the way to spell error; errroor is an error. {expect:ANYTHING}
+
+NOTE: When the search reaches the end of the file it will continue at the
+ start, unless the ['wrapscan']('wrapscan') option has been reset.
+
+# Lesson 4.3: MATCHING PARENTHESES SEARCH
+
+** Type `%`{normal} to find a matching ),], or }. **
+
+ 1. Place the cursor on any (, [, or { in the line below marked --->.
+
+ 2. Now type the [%](%) character.
+
+ 3. The cursor will move to the matching parenthesis or bracket.
+
+ 4. Type `%`{normal} to move the cursor to the other matching bracket.
+
+ 5. Move the cursor to another (,),[,],{ or } and see what `%`{normal} does.
+
+---> This ( is a test line with ('s, ['s ] and {'s } in it. )) {expect:ANYTHING}
+
+NOTE: This is very useful in debugging a program with unmatched parentheses!
+
+# Lesson 4.4: THE SUBSTITUTE COMMAND
+
+** Type `:s/old/new/g` to substitute "new" for "old". **
+
+ 1. Move the cursor to the line below marked --->.
+
+ 2. Type
+~~~ cmd
+ :s/thee/the/
+~~~
+
+ NOTE that the [:s](:s) command only changed the first occurrence of "thee" in the line.
+
+ 3. Now type
+~~~ cmd
+ :s/thee/the/g
+~~~
+
+ Adding the g [flag](:s_flags) means to substitute globally in the line, change
+ all occurrences of "thee" in the line.
+
+---> thee best time to see thee flowers is in thee spring. {expect:the best time to see the flowers is in the spring.}
+
+ 4. To change every occurrence of a character string between two lines, type
+~~~ cmd
+ :#,#s/old/new/g
+~~~
+ where #,# are the line numbers of the range of lines where the substitution is to be done.
+
+ Type
+~~~ cmd
+ :%s/old/new/g
+~~~
+ to change every occurrence in the whole file.
+
+ Type
+~~~ cmd
+ :%s/old/new/gc
+~~~
+ to find every occurrence in the whole file, with a prompt whether to substitute or not.
+
+# Lesson 4 SUMMARY
+
+ 1. `<Ctrl-g>`{normal} displays your location in the file and the file status.
+ `G`{normal} moves to the end of the file.
+ number `G`{normal} moves to that line number.
+ `gg`{normal} moves to the first line.
+
+ 2. Typing `/`{normal} followed by a phrase searches FORWARD for the phrase.
+ Typing `?`{normal} followed by a phrase searches BACKWARD for the phrase.
+ After a search type `n`{normal} to find the next occurrence in the same direction
+ or `N`{normal} to search in the opposite direction.
+ `<Ctrl-o>`{normal} takes you back to older positions, `<Ctrl-i>`{normal} to newer positions.
+
+ 3. Typing `%`{normal} while the cursor is on a (,),[,],{, or } goes to its match.
+
+ 4. To substitute new for the first old in a line type
+~~~ cmd
+ :s/old/new
+~~~
+ To substitute new for all 'old's on a line type
+~~~ cmd
+ :s/old/new/g
+~~~
+ To substitute phrases between two line #'s type
+~~~ cmd
+ :#,#s/old/new/g
+~~~
+ To substitute all occurrences in the file type
+~~~ cmd
+ :%s/old/new/g
+~~~
+ To ask for confirmation each time add 'c'
+~~~ cmd
+ :%s/old/new/gc
+~~~
+
+# Lesson 5.1: HOW TO EXECUTE AN EXTERNAL COMMAND
+
+** Type `:!`{vim} followed by an external command to execute that command. **
+
+ 1. Type the familiar command `:`{normal} to set the cursor at the bottom of the
+ screen. This allows you to enter a command-line command.
+
+ 2. Now type the [!](!cmd) (exclamation point) character. This allows you to
+ execute any external shell command.
+
+ 3. As an example type "ls" following the "!" and then hit `<Enter>`{normal}. This
+ will show you a listing of your directory, just as if you were at the
+ shell prompt.
+
+NOTE: It is possible to execute any external command this way, also with
+ arguments.
+
+NOTE: All : commands must be finished by hitting <Enter>
+ From here on we will not always mention it.
+
+# Lesson 5.2: MORE ON WRITING FILES
+
+** To save the changes made to the text, type `:w`{vim} FILENAME. **
+
+ 1. Type `:!ls`{vim} to get a listing of your directory.
+ You already know you must hit `<Enter>`{normal} after this.
+
+ 2. Choose a filename that does not exist yet, such as TEST.
+
+ 3. Now type:
+~~~ cmd
+ :w TEST
+~~~
+ (where TEST is the filename you chose.)
+
+ 4. This saves the whole file (the Vim Tutor) under the name TEST.
+ To verify this, type `:!ls`{vim} again to see your directory.
+
+NOTE: If you were to exit Vim and start it again with vim TEST , the file
+ would be an exact copy of the tutor when you saved it.
+
+ 5. Now remove the file by typing:
+~~~ cmd
+ :!rm TEST
+~~~
+
+# Lesson 5.3: SELECTING TEXT TO WRITE
+
+** To save part of the file, type `v`{normal} motion `:w FILENAME`{vim} **
+
+ 1. Move the cursor to this line.
+
+ 2. Press [v](v) and move the cursor to the fifth item below. Notice that the
+ text is highlighted.
+
+ 3. Press the `:`{normal} character. At the bottom of the screen
+
+ :'<,'>
+
+ will appear.
+
+ 4. Type
+
+ `:w TEST`{vim}
+
+ where TEST is a filename that does not exist yet. Verify that you see
+
+ `:'<,'>w TEST`{vim}
+
+ before you press `<Enter>`{normal}.
+
+ 5. Vim will write the selected lines to the file TEST. Use `:!ls`{vim} to see it.
+ Do not remove it yet! We will use it in the next lesson.
+
+NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move
+ the cursor around to make the selection bigger or smaller. Then you can
+ use an operator to do something with the text. For example, `d`{normal} deletes
+ the text.
+
+# Lesson 5.4: RETRIEVING AND MERGING FILES
+
+** To insert the contents of a file, type `:r FILENAME`{vim} **
+
+ 1. Place the cursor just above this line.
+
+NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
+ DOWN to see this lesson again.
+
+ 2. Now retrieve your TEST file using the command
+
+ `:r TEST`{vim}
+
+ where TEST is the name of the file you used.
+ The file you retrieve is placed below the cursor line.
+
+ 3. To verify that a file was retrieved, cursor back and notice that there
+ are now two copies of Lesson 5.3, the original and the file version.
+
+NOTE: You can also read the output of an external command. For example,
+
+ `:r !ls`{vim}
+
+ reads the output of the `ls` command and puts it below the cursor.
+
+# Lesson 5 SUMMARY
+
+ 1. [:!command](:!cmd) executes an external command.
+
+ Some useful examples are:
+ `:!ls`{vim} - shows a directory listing
+ `:!rm FILENAME`{vim} - removes file FILENAME
+
+ 2. [:w](:w) FILENAME writes the current Vim file to disk with
+ name FILENAME.
+
+ 3. [v](v) motion :w FILENAME saves the Visually selected lines in file
+ FILENAME.
+
+ 4. [:r](:r) FILENAME retrieves disk file FILENAME and puts it
+ below the cursor position.
+
+ 5. [:r !dir](:r!) reads the output of the dir command and
+ puts it below the cursor position.
+
+# Lesson 6.1: THE OPEN COMMAND
+
+** Type `o`{normal} to open a line below the cursor and place you in Insert mode. **
+
+ 1. Move the cursor to the line below marked --->.
+
+ 2. Type the lowercase letter `o`{normal} to [open](o) up a line BELOW the cursor and place
+ you in Insert mode.
+
+ 3. Now type some text and press `<Esc>`{normal} to exit Insert mode.
+
+---> After typing o the cursor is placed on the open line in Insert mode. {expect:ANYTHING}
+
+ 4. To open up a line ABOVE the cursor, simply type a [capital O](O), rather
+ than a lowercase `o`{normal}. Try this on the line below.
+
+---> Open up a line above this by typing O while the cursor is on this line. {expect:ANYTHING}
+
+# Lesson 6.2: THE APPEND COMMAND
+
+** Type `a`{normal} to insert text AFTER the cursor. **
+
+ 1. Move the cursor to the start of the line below marked --->.
+
+ 2. Press `e`{normal} until the cursor is on the end of "li".
+
+ 3. Type an `a`{normal} (lowercase) to [append](a) text AFTER the cursor.
+
+ 4. Complete the word like the line below it. Press `<Esc>`{normal} to exit Insert
+ mode.
+
+ 5. Use `e`{normal} to move to the next incomplete word and repeat steps 3 and 4.
+
+---> This li will allow you to pract appendi text to a line. {expect:This line will allow you to practice appending text to a line.}
+---> This line will allow you to practice appending text to a line. {expect:This line will allow you to practice appending text to a line.}
+
+NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only difference is where
+ the characters are inserted.
+
+# Lesson 6.3: ANOTHER WAY TO REPLACE
+
+** Type a capital `R`{normal} to replace more than one character. **
+
+ 1. Move the cursor to the first line below marked --->. Move the cursor to
+ the beginning of the first "xxx".
+
+ 2. Now press `R`{normal} ([capital R](R)) and type the number below it in the second line, so that it
+ replaces the "xxx".
+
+ 3. Press `<Esc>`{normal} to leave [Replace mode](mode-replace). Notice that the rest of the line
+ remains unmodified.
+
+ 4. Repeat the steps to replace the remaining "xxx".
+
+---> Adding 123 to xxx gives you xxx. {expect:Adding 123 to 456 gives you 579.}
+---> Adding 123 to 456 gives you 579. {expect:Adding 123 to 456 gives you 579.}
+
+NOTE: Replace mode is like Insert mode, but every typed character deletes an
+ existing character.
+
+# Lesson 6.4: COPY AND PASTE TEXT
+
+** Use the `y`{normal} operator to copy text and `p`{normal} to paste it **
+
+ 1. Go to the line marked with ---> below and place the cursor after "a)".
+
+ 2. Start Visual mode with `v`{normal} and move the cursor to just before "first".
+
+ 3. Type `y`{normal} to [yank](yank) (copy) the highlighted text.
+
+ 4. Move the cursor to the end of the next line: `j$`{normal}
+
+ 5. Type `p`{normal} to [put](put) (paste) the text. Then type: "a second"`<Esc>`{normal}.
+
+ 6. Use Visual mode to select " item.", yank it with `y`{normal}, move to the end of
+ the next line with `j$`{normal} and put the text there with `p`{normal}.
+
+---> a) this is the first item.
+---> b) {expect: b) this is the second item}
+
+ NOTE: you can also use `y`{normal} as an operator; `yw`{normal} yanks one word.
+
+# Lesson 6.5: SET OPTION
+
+** Set an option so a search or substitute ignores case **
+
+ 1. Search for 'ignore' by entering: `/ignore`
+ Repeat several times by pressing `n`{normal}.
+
+ 2. Set the 'ic' (Ignore case) option by entering:
+~~~ cmd
+ :set ic
+~~~
+ 3. Now search for 'ignore' again by pressing n
+ Notice that Ignore and IGNORE are now also found.
+
+ 4. Set the 'hlsearch' and 'incsearch' options:
+~~~ cmd
+ :set hls is
+~~~
+ 5. Now type the search command again and see what happens: /ignore <Enter>
+
+ 6. To disable ignoring case enter:
+~~~ cmd
+ :set noic
+~~~
+ 7. To toggle the value of a setting, prepend it with "inv":
+~~~ cmd
+ :set invic
+~~~
+NOTE: To remove the highlighting of matches enter:
+~~~ cmd
+ :nohlsearch
+~~~
+NOTE: If you want to ignore case for just one search command, use [\c](/\c)
+ in the phrase: /ignore\c <Enter>
+
+# Lesson 6 SUMMARY
+
+ 1. Type `o`{normal} to open a line BELOW the cursor and start Insert mode.
+ Type `O`{normal} to open a line ABOVE the cursor.
+
+ 2. Type `a`{normal} to insert text AFTER the cursor.
+ Type `A`{normal} to insert text after the end of the line.
+
+ 3. The `e`{normal} command moves to the end of a word.
+
+ 4. The `y`{normal} operator yanks (copies) text, `p`{normal} puts (pastes) it.
+
+ 5. Typing a capital `R`{normal} enters Replace mode until `<Esc>`{normal} is pressed.
+
+ 6. Typing "[:set](:set) xxx" sets the option "xxx". Some options are:
+
+ 'ic' 'ignorecase' ignore upper/lower case when searching
+ 'is' 'incsearch' show partial matches for a search phrase
+ 'hls' 'hlsearch' highlight all matching phrases
+
+ You can either use the long or the short option name.
+
+ 7. Prepend "no" to switch an option off:
+~~~ cmd
+ :set noic
+~~~
+ 8. Prepend "inv" to toggle an option:
+~~~ cmd
+ :set invic
+~~~
+
+# Lesson 7.1: GETTING HELP
+
+** Use the on-line help system **
+
+Vim has a comprehensive on-line help system. To get started, try one of
+these three:
+ - press the `<HELP>`{normal} key (if you have one)
+ - press the `<F1>`{normal} key (if you have one)
+ - type
+ `:help`{vim}
+
+Read the text in the help window to find out how the help works.
+Type `<Ctrl-w><Ctrl-w>`{normal} to jump from one window to another.
+Type `:q`{vim} to close the help window.
+
+You can find help on just about any subject, by giving an argument to the
+":help" command. Try these (don't forget pressing <Enter>):
+~~~ cmd
+ :help w
+ :help c_CTRL-D
+ :help insert-index
+ :help user-manual
+~~~
+# Lesson 7.2: CREATE A STARTUP SCRIPT
+
+** Enable Vim features **
+
+Vim has many more features than Vi, but most of them are disabled by
+default. To start using more features you have to create a "vimrc" file.
+
+ 1. Start editing the "vimrc" file. This depends on your system:
+ `:e ~/.vimrc`{vim} for Unix-like systems
+ `:e $VIM/_vimrc`{vim} for Microsoft Windows
+
+ 2. Now read the example "vimrc" file contents:
+ `:r $VIMRUNTIME/vimrc_example.vim`{vim}
+
+ 3. Write the file with:
+ `:w`{vim}
+
+ The next time you start Vim it will use syntax highlighting.
+ You can add all your preferred settings to this "vimrc" file.
+ For more information type :help vimrc-intro
+
+# Lesson 7.3: COMPLETION
+
+** Command line completion with `<Ctrl-d>`{normal} and `<Tab>`{normal} **
+
+ 1. Look what files exist in the directory: `:!ls`{vim}
+
+ 2. Type the start of a command: `:e`{vim}
+
+ 3. Press `<Ctrl-d>`{normal} and Vim will show a list of commands that start with "e".
+
+ 4. Press `<Tab>`{normal} and Vim will complete the command name to ":edit".
+
+ 5. Now add a space and the start of an existing file name: `:edit FIL`{vim}
+
+ 6. Press `<Tab>`{normal}. Vim will complete the name (if it is unique).
+
+NOTE: Completion works for many commands. It is especially useful for `:help`{vim}.
+
+# Lesson 7 SUMMARY
+
+ 1. Type `:help`{vim}
+ or press `<F1>`{normal} or `<Help>`{normal} to open a help window.
+
+ 2. Type `:help TOPIC`{vim} to find help on TOPIC.
+
+ 3. Type `<Ctrl-w><Ctrl-w>`{normal} to jump to another window
+
+ 4. Type `:q`{vim} to close the help window
+
+ 5. Create a vimrc startup script to keep your preferred settings.
+
+ 6. While in command mode, press `<Ctrl-d>`{normal} to see possible completions.
+ Press `<Tab>`{normal} to use one completion.
+
+# CONCLUSION
+
+This was intended to give a brief overview of the Vim editor, just enough to
+allow you to use the editor fairly easily. It is far from complete as Vim has
+many many more commands. Consult the help often.
+
+There are many resources online to learn more about vim. Here's a bunch of them:
+
+- *Learn Vim Progressively*: http://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/
+- *Learning Vim in 2014*: http://benmccormick.org/learning-vim-in-2014/
+- Vimcasts: http://vimcasts.org/
+- Vim Video-Tutorials by Derek Wyatt: http://derekwyatt.org/vim/tutorials/
+- *Learn Vimscript the Hard Way*: http://learnvimscriptthehardway.stevelosh.com/
+- *7 Habits of Effective Text Editing*: http://www.moolenaar.net/habits.html
+
+If you prefer a book, *Practival Vim* by Drew Neil is recommended often.
+
+This tutorial was written by Michael C. Pierce and Robert K. Ware, Colorado
+School of Mines using ideas supplied by Charles Smith, Colorado State
+University. E-mail: bware@mines.colorado.edu.
+
+Modified for Vim by Bram Moolenaar.
+Modified for vim-tutor-mode by Felipe Morales.
diff --git a/runtime/tutor/tutor.tutor b/runtime/tutor/tutor.tutor
new file mode 100644
index 0000000000..852c1ea74a
--- /dev/null
+++ b/runtime/tutor/tutor.tutor
@@ -0,0 +1,259 @@
+# CREATING A VIM TUTORIAL WITH VIM-TUTOR-MODE
+
+This tutorial will guide you through the steps required to create a tutorial
+file for vim-tutor-mode. It is also meant as a demo of vim-tutor-mode
+capabilities.
+
+Table of contents:
+
+- [Setting up](*setting-up*)
+- [vim-tutor-mode's markup](*markup*)
+ - [emphasis](*emphasis*)
+ - [headers](*headers*)
+ - [links](*links*)
+ - [codeblocks](*codeblocks*)
+- [Interactive elements](*interactive*)
+ - [expect](*expect*)
+
+## SETTING UP *setting-up*
+
+First, you'll need to enable "debug" mode
+~~~ cmd
+ :let g:tutor_debug = 1
+~~~
+This will allow saving changes to the tutor files and will disable conceals, so
+you can more easily check your changes.
+
+After this, create a new .tutor file (we will be practicing on this very file, so you
+don't need to do this now):
+~~~ cmd
+ :e new-tutorial.tutor
+~~~
+
+## VIM-TUTOR-MODE's MARKDOWN *markup*
+
+vim-tutor-mode uses a subset of markdown's syntax to format the tutorials. The
+subset supported should be enough for most tutorials and the maintainers will
+try to keep it as small as possible (if regular markdown allows for several
+ways to do the same thing, tutor markdown will only provide the one the
+maintainers think is easier to handle).
+
+### Emphasis *emphasis*
+
+For emphasized text (italics), as in normal markdown, you use \*. E.g.:
+
+ \*text\*
+
+is displayed like
+
+ *text*
+
+Note: The underscores variant is not supported.
+
+For strong emphasis (bold), you use \*\*. E.g.:
+
+ \*\*this\*\*
+
+is displayed like
+
+ **this**
+
+1. Format the line below so it becomes a lesson description:
+
+---> This is text with importat information {expect:This is text with **important information**}
+---> This is text with **important information** {expect:This is text with **important information**}
+
+Note: Some words (e.g., NOTE, IMPORTANT, tip, ATTENTION, etc.) will also be
+highlighted. You don't need to mark them specially.
+
+2. Turn the line below into a TODO item:
+
+---> Document '&variable' {expect:TODO: Document '&variable'}
+---> TODO: Document '&variable' {expect:TODO: Document '&variable'}
+
+### Headers *headers*
+
+3. Practice fixing the lines below:
+
+---> This is a level 1 header {expect:# This is a level 1 header}
+---> # This is a level 1 header {expect:# This is a level 1 header}
+---> This is a level 3 header {expect:### This is a level 3 header}
+---> ### This is a level 3 header {expect:### This is a level 3 header}
+---> This is a header with a label {expect:# This is a header with a label {*label*}}
+---> # This is a header with a label {*label*} {expect:# This is a header with a label {*label*}}
+
+4. Now, create a 4th level section here, and add a label like in the previous
+exercise:
+
+
+
+ ATTENTION We will use this label later, so remember it.
+
+### Links *links*
+
+It is good practice to include links in your tutorials to reference materials,
+like vim's own help or external documents. You can also link to other parts of
+the document.
+
+Links have the syntax
+
+ \[label\]\(target\)
+
+#### Help links
+
+If the target of a link matches a help topic, opening it will open it.
+
+5. Fix the following line:
+
+---> A link to help for the 'breakindent' option {expect:A link to help for the ['breakindent']('breakindent') option}
+---> A link to help for the ['breakindent']('breakindent') option {expect:A link to help for the ['breakindent']('breakindent') option}
+
+#### Anchor links
+
+A link can also lead to a place in the file itself. Anchors are written
+
+ \*anchor\*
+
+and are hidden by default. Links to them look like
+
+ \[label\]\(\*anchor\*\)
+
+6. Add the appropiate link:
+
+---> A link to the Links section {expect:A link to the [Links](*links*) section}
+---> A link to the [Links](*links*) section {expect:A link to the [Links](*links*) section}
+
+7. Now, create a link to the section you created on exercise 4
+ above.
+
+
+
+# Tutorial links
+
+You can also have links to other tutorials. For this, you'll write the wnchor in the format
+
+ @tutor:TUTORIAL
+
+7. Create a link to this tutorial:
+
+---> A link to the vim-tutor-mode tutorial {expect:A link to [the vim-tutor-mode tutorial](@tutor:tutor)}
+---> A link to [the vim-tutor-mode tutorial](@tutor:tutor) {expect:A link to [the vim-tutor-mode tutorial](@tutor:tutor)}
+
+### Codeblocks *codeblocks*
+
+vim-tutor-mode tutorials can include viml sections
+
+ ~~~ cmd
+ echom "hello"
+ ~~~
+
+is displayed as
+~~~ cmd
+echom "hello"
+~~~
+
+8. Copy the viml section below
+
+---> {expect:~~~ viml}
+---> {expect:echom "the value of &number is".string(&number)}
+---> {expect:~~~}
+
+---> ~~~ viml {expect:~~~ viml}
+---> echom "the value of &number is".string(&number) {expect:echom "the value of &number is".string(&number)}
+---> ~~~ {expect:~~~}
+
+You can inline viml code using "\`" and "\`{vim}":
+
+ \`call myFunction()\`{vim}
+
+is displayed as
+
+ `call myFunction()`{vim}
+
+[normal](Normal-mode) commands can also be embedded in tutorials.
+
+ ~~~ normal
+ ftdaW
+ ~~~
+
+is displayed as
+~~~ normal
+ftdaW
+~~~
+
+Note: you can also write `norm` or `normal`.
+
+9. Copy the normal section below
+
+---> {expect:~~~ normal}
+---> {expect:d2w}
+---> {expect:~~~}
+
+---> ~~~ normal {expect:~~~ normal}
+---> d2w {expect:d2w}
+---> ~~~ {expect:~~~}
+
+You can also inline normal commands by using "\`" and "\`{normal}":
+
+ \`gq\`{normal} is very useful.
+
+is displayed:
+
+ `gq`{normal} is very useful.
+
+10. Complete the line as shown
+
+---> d {expect:«d2w»}
+---> «d2w» {expect:«d2w»}
+
+Commands to run in the system shell can be highlighted by indenting a line starting with "$".
+
+~~~ sh
+ $ vim --version
+~~~
+
+## INTERACTIVE ELEMENTS *interactive*
+
+As visible in this very document, vim-tutor-mode includes some interactive
+elements, to provide feedback to the user about his progress. These elements
+all have the syntax
+
+ \---> TEXT {CLAUSE}
+
+where \---> must start at the beginning of the line. If TEXT satisfies CLAUSE,
+a ✓ sign will appear to the left. A ✗ sign is displayed otherwise. The CLAUSE
+itself is hidden unless debug mode is set or ['conceallevel']('conceallevel')
+is 2.
+
+### expect *expect*
+
+The basic clause is "expect", which is satisfied if TEXT is the same as the
+content of the clause. For example
+
+ \---> TEXT {expect:TEXT}
+
+is satisfied, but
+
+ \---> OTHER TEXT {expect:TEXT}
+
+is not.
+
+13. Make both lines the same:
+
+---> this is not right {expect:---> this is right} |expect:---> this is right {expect:---> this is right}|
+---> ---> this is right {expect:---> this is right} |expect:---> this is right {expect:---> this is right}|
+
+
+If the content of a expect clause is ANYTHING, no checks will be performed. This is
+useful to create a line that is highlighted you want the user to play with.
+
+ \---> TEXT {expect:ANYTHING}
+
+is displayed
+
+---> this is free text {expect:ANYTHING}
+
+14. Turn the line below into free text:
+
+---> this is some text |expect:---> this is some text {expect:ANYTHING}|
+---> ---> this is some text {expect:ANYTHING} |expect:---> this is some text {expect:ANYTHING}|
diff --git a/scripts/gen_events.lua b/scripts/gen_events.lua
new file mode 100644
index 0000000000..75e0b3da3a
--- /dev/null
+++ b/scripts/gen_events.lua
@@ -0,0 +1,65 @@
+if arg[1] == '--help' then
+ print('Usage: gen_events.lua src/nvim enum_file event_names_file')
+ os.exit(0)
+end
+
+local nvimsrcdir = arg[1]
+local fileio_enum_file = arg[2]
+local names_file = arg[3]
+
+package.path = nvimsrcdir .. '/?.lua;' .. package.path
+
+local auevents = require('auevents')
+local events = auevents.events
+local aliases = auevents.aliases
+
+enum_tgt = io.open(fileio_enum_file, 'w')
+names_tgt = io.open(names_file, 'w')
+
+enum_tgt:write('typedef enum auto_event {')
+names_tgt:write([[
+static const struct event_name {
+ size_t len;
+ char *name;
+ event_T event;
+} event_names[] = {]])
+
+for i, event in ipairs(events) do
+ if i > 1 then
+ comma = ',\n'
+ else
+ comma = '\n'
+ end
+ enum_tgt:write(('%s EVENT_%s = %u'):format(comma, event:upper(), i - 1))
+ names_tgt:write(('%s {%u, "%s", EVENT_%s}'):format(comma, #event, event, event:upper()))
+end
+
+for alias, event in pairs(aliases) do
+ names_tgt:write((',\n {%u, "%s", EVENT_%s}'):format(#alias, alias, event:upper()))
+end
+
+names_tgt:write(',\n {0, NULL, (event_T)0}')
+
+enum_tgt:write('\n} event_T;\n')
+names_tgt:write('\n};\n')
+
+enum_tgt:write(('\n#define NUM_EVENTS %u\n'):format(#events))
+names_tgt:write('\nstatic AutoPat *first_autopat[NUM_EVENTS] = {\n ')
+line_len = 1
+for i = 1,((#events) - 1) do
+ line_len = line_len + #(' NULL,')
+ if line_len > 80 then
+ names_tgt:write('\n ')
+ line_len = 1 + #(' NULL,')
+ end
+ names_tgt:write(' NULL,')
+end
+if line_len + #(' NULL') > 80 then
+ names_tgt:write('\n NULL')
+else
+ names_tgt:write(' NULL')
+end
+names_tgt:write('\n};\n')
+
+enum_tgt:close()
+names_tgt:close()
diff --git a/scripts/genoptions.lua b/scripts/genoptions.lua
new file mode 100644
index 0000000000..2859ca1795
--- /dev/null
+++ b/scripts/genoptions.lua
@@ -0,0 +1,183 @@
+if arg[1] == '--help' then
+ print('Usage: genoptions.lua src/nvim options_file')
+ os.exit(0)
+end
+
+local nvimsrcdir = arg[1]
+local options_file = arg[2]
+
+package.path = nvimsrcdir .. '/?.lua;' .. package.path
+
+local opt_fd = io.open(options_file, 'w')
+
+local w = function(s)
+ if s:match('^ %.') then
+ opt_fd:write(s .. ',\n')
+ else
+ opt_fd:write(s .. '\n')
+ end
+end
+
+local options = require('options')
+
+cstr = options.cstr
+
+local type_flags={
+ bool='P_BOOL',
+ number='P_NUM',
+ string='P_STRING',
+}
+
+local redraw_flags={
+ statuslines='P_RSTAT',
+ current_window='P_RWIN',
+ current_buffer='P_RBUF',
+ all_windows='P_RALL',
+ everything='P_RCLR',
+ curswant='P_CURSWANT',
+}
+
+local list_flags={
+ comma='P_COMMA',
+ flags='P_FLAGLIST',
+ flagscomma='P_COMMA|P_FLAGLIST',
+}
+
+local get_flags = function(o)
+ local ret = {type_flags[o.type]}
+ local add_flag = function(f)
+ ret[1] = ret[1] .. '|' .. f
+ end
+ if o.list then
+ add_flag(list_flags[o.list])
+ end
+ if o.redraw then
+ for _, r_flag in ipairs(o.redraw) do
+ add_flag(redraw_flags[r_flag])
+ end
+ end
+ for _, flag_desc in ipairs({
+ {'alloced'},
+ {'expand'},
+ {'nodefault'},
+ {'no_mkrc'},
+ {'vi_def'},
+ {'vim'},
+ {'secure'},
+ {'gettext'},
+ {'noglob'},
+ {'normal_fname_chars', 'P_NFNAME'},
+ {'pri_mkrc'},
+ {'deny_in_modelines', 'P_NO_ML'},
+ {'deny_duplicates', 'P_NODUP'},
+ }) do
+ local key_name = flag_desc[1]
+ local def_name = flag_desc[2] or ('P_' .. key_name:upper())
+ if o[key_name] then
+ add_flag(def_name)
+ end
+ end
+ return ret[1]
+end
+
+local get_cond
+get_cond = function(c, base_string)
+ local cond_string = base_string or '#if '
+ if type(c) == 'table' then
+ cond_string = cond_string .. get_cond(c[1], '')
+ for i, subc in ipairs(c) do
+ if i > 1 then
+ cond_string = cond_string .. ' && ' .. get_cond(subc, '')
+ end
+ end
+ elseif c:sub(1, 1) == '!' then
+ cond_string = cond_string .. '!defined(' .. c:sub(2) .. ')'
+ else
+ cond_string = cond_string .. 'defined(' .. c .. ')'
+ end
+ return cond_string
+end
+
+value_dumpers = {
+ ['function']=function(v) return v() end,
+ string=cstr,
+ boolean=function(v) return v and 'true' or 'false' end,
+ number=function(v) return ('%iL'):format(v) end,
+ ['nil']=function(v) return '0L' end,
+}
+
+local get_value = function(v)
+ return '(char_u *) ' .. value_dumpers[type(v)](v)
+end
+
+local get_defaults = function(d)
+ return '{' .. get_value(d.vi) .. ', ' .. get_value(d.vim) .. '}'
+end
+
+local defines = {}
+
+local dump_option = function(i, o)
+ w(' [' .. ('%u'):format(i - 1) .. ']={')
+ w(' .fullname=' .. cstr(o.full_name))
+ if o.abbreviation then
+ w(' .shortname=' .. cstr(o.abbreviation))
+ end
+ w(' .flags=' .. get_flags(o))
+ if o.enable_if then
+ w(get_cond(o.enable_if))
+ end
+ if o.varname then
+ w(' .var=(char_u *)&' .. o.varname)
+ elseif #o.scope == 1 and o.scope[1] == 'window' then
+ w(' .var=VAR_WIN')
+ end
+ if o.enable_if then
+ w('#endif')
+ end
+ if #o.scope == 1 and o.scope[1] == 'global' then
+ w(' .indir=PV_NONE')
+ else
+ assert (#o.scope == 1 or #o.scope == 2)
+ assert (#o.scope == 1 or o.scope[1] == 'global')
+ local min_scope = o.scope[#o.scope]
+ local varname = o.pv_name or o.varname or (
+ 'p_' .. (o.abbreviation or o.full_name))
+ local pv_name = (
+ 'OPT_' .. min_scope:sub(1, 3):upper() .. '(' .. (
+ min_scope:sub(1, 1):upper() .. 'V_' .. varname:sub(3):upper()
+ ) .. ')'
+ )
+ if #o.scope == 2 then
+ pv_name = 'OPT_BOTH(' .. pv_name .. ')'
+ end
+ defines['PV_' .. varname:sub(3):upper()] = pv_name
+ w(' .indir=' .. pv_name)
+ end
+ if o.defaults then
+ if o.defaults.condition then
+ w(get_cond(o.defaults.condition))
+ end
+ w(' .def_val=' .. get_defaults(o.defaults.if_true))
+ if o.defaults.condition then
+ if o.defaults.if_false then
+ w('#else')
+ w(' .def_val=' .. get_defaults(o.defaults.if_false))
+ end
+ w('#endif')
+ end
+ end
+ w(' },')
+end
+
+w('static vimoption_T options[] = {')
+for i, o in ipairs(options.options) do
+ dump_option(i, o)
+end
+w(' [' .. ('%u'):format(#options.options) .. ']={.fullname=NULL}')
+w('};')
+w('')
+
+for k, v in pairs(defines) do
+ w('#define ' .. k .. ' ' .. v)
+end
+opt_fd:close()
diff --git a/scripts/genvimvim.lua b/scripts/genvimvim.lua
new file mode 100644
index 0000000000..9135c8e3ab
--- /dev/null
+++ b/scripts/genvimvim.lua
@@ -0,0 +1,138 @@
+if arg[1] == '--help' then
+ print('Usage: genoptions.lua src/nvim runtime/syntax/vim/generated.vim')
+ os.exit(0)
+end
+
+local nvimsrcdir = arg[1]
+local syntax_file = arg[2]
+
+package.path = nvimsrcdir .. '/?.lua;' .. package.path
+
+local lld = {}
+local syn_fd = io.open(syntax_file, 'w')
+lld.line_length = 0
+local w = function(s)
+ syn_fd:write(s)
+ if s:find('\n') then
+ lld.line_length = #(s:gsub('.*\n', ''))
+ else
+ lld.line_length = lld.line_length + #s
+ end
+end
+
+local options = require('options')
+local auevents = require('auevents')
+local ex_cmds = require('ex_cmds')
+
+local cmd_kw = function(prev_cmd, cmd)
+ if not prev_cmd then
+ return cmd:sub(1, 1) .. '[' .. cmd:sub(2) .. ']'
+ else
+ local shift = 1
+ while cmd:sub(shift, shift) == prev_cmd:sub(shift, shift) do
+ shift = shift + 1
+ end
+ if shift >= #cmd then
+ return cmd
+ else
+ return cmd:sub(1, shift) .. '[' .. cmd:sub(shift + 1) .. ']'
+ end
+ end
+end
+
+vimcmd_start = 'syn keyword vimCommand contained '
+w(vimcmd_start)
+local prev_cmd = nil
+for _, cmd_desc in ipairs(ex_cmds) do
+ if lld.line_length > 850 then
+ w('\n' .. vimcmd_start)
+ end
+ local cmd = cmd_desc.command
+ if cmd:match('%w') and cmd ~= 'z' then
+ w(' ' .. cmd_kw(prev_cmd, cmd))
+ end
+ prev_cmd = cmd
+end
+
+local vimopt_start = 'syn keyword vimOption contained '
+w('\n\n' .. vimopt_start)
+
+for _, opt_desc in ipairs(options.options) do
+ if not opt_desc.varname or opt_desc.varname:sub(1, 7) ~= 'p_force' then
+ if lld.line_length > 850 then
+ w('\n' .. vimopt_start)
+ end
+ w(' ' .. opt_desc.full_name)
+ if opt_desc.abbreviation then
+ w(' ' .. opt_desc.abbreviation)
+ end
+ if opt_desc.type == 'bool' then
+ w(' inv' .. opt_desc.full_name)
+ w(' no' .. opt_desc.full_name)
+ if opt_desc.abbreviation then
+ w(' inv' .. opt_desc.abbreviation)
+ w(' no' .. opt_desc.abbreviation)
+ end
+ end
+ end
+end
+
+w('\n\nsyn case ignore')
+local vimau_start = 'syn keyword vimAutoEvent contained '
+w('\n\n' .. vimau_start)
+
+for _, au in ipairs(auevents.events) do
+ if not auevents.neovim_specific[au] then
+ if lld.line_length > 850 then
+ w('\n' .. vimau_start)
+ end
+ w(' ' .. au)
+ end
+end
+for au, _ in pairs(auevents.aliases) do
+ if not auevents.neovim_specific[au] then
+ if lld.line_length > 850 then
+ w('\n' .. vimau_start)
+ end
+ w(' ' .. au)
+ end
+end
+
+local nvimau_start = 'syn keyword nvimAutoEvent contained '
+w('\n\n' .. nvimau_start)
+
+for au, _ in pairs(auevents.neovim_specific) do
+ if lld.line_length > 850 then
+ w('\n' .. nvimau_start)
+ end
+ w(' ' .. au)
+end
+
+w('\n\nsyn case match')
+local vimfun_start = 'syn keyword vimFuncName contained '
+w('\n\n' .. vimfun_start)
+eval_fd = io.open(nvimsrcdir .. '/eval.c', 'r')
+local started = 0
+for line in eval_fd:lines() do
+ if line == '} functions[] =' then
+ started = 1
+ elseif started == 1 then
+ assert (line == '{')
+ started = 2
+ elseif started == 2 then
+ if line == '};' then
+ break
+ end
+ local func_name = line:match('^ {"(%w+)",')
+ if func_name then
+ if lld.line_length > 850 then
+ w('\n' .. vimfun_start)
+ end
+ w(' ' .. func_name)
+ end
+ end
+end
+eval_fd:close()
+
+w('\n')
+syn_fd:close()
diff --git a/scripts/msgpack-gen.lua b/scripts/msgpack-gen.lua
index bb37ae94da..581641ae06 100644
--- a/scripts/msgpack-gen.lua
+++ b/scripts/msgpack-gen.lua
@@ -34,8 +34,8 @@ c_params = Ct(c_void + c_param_list)
c_proto = Ct(
Cg(c_type, 'return_type') * Cg(c_id, 'name') *
fill * P('(') * fill * Cg(c_params, 'parameters') * fill * P(')') *
- Cg(Cc(false), 'deferred') *
- (fill * Cg((P('FUNC_ATTR_DEFERRED') * Cc(true)), 'deferred') ^ -1) *
+ Cg(Cc(false), 'async') *
+ (fill * Cg((P('FUNC_ATTR_ASYNC') * Cc(true)), 'async') ^ -1) *
fill * P(';')
)
grammar = Ct((c_proto + c_comment + c_preproc + ws) ^ 1)
@@ -279,7 +279,7 @@ for i = 1, #functions do
'(String) {.data = "'..fn.name..'", '..
'.size = sizeof("'..fn.name..'") - 1}, '..
'(MsgpackRpcRequestHandler) {.fn = handle_'.. fn.name..
- ', .defer = '..tostring(fn.deferred)..'});\n')
+ ', .async = '..tostring(fn.async)..'});\n')
if #fn.name > max_fname_len then
max_fname_len = #fn.name
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index f17b23101d..9ae9377d8f 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -e
+set -u
set -o pipefail
readonly NEOVIM_SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
@@ -12,21 +13,31 @@ usage() {
echo "Helper script for porting Vim patches. For more information, see"
echo "https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim"
echo
- echo "Usage: ${BASENAME} [option]"
- echo " ${BASENAME} vim-revision"
+ echo "Usage: ${BASENAME} [-h | -l | -p vim-revision | -r pr-number]"
echo
echo "Options:"
- echo " -h, --help Show this message."
- echo " -l, --list Show list of Vim patches missing from Neovim."
- echo
- echo "vim-revision can be a version number of the format '7.4.xxx'"
- echo "or a Mercurial commit hash."
+ echo " -h Show this message and exit."
+ echo " -l Show list of Vim patches missing from Neovim."
+ echo " -p {vim-revision} Download and apply the Vim patch vim-revision."
+ echo " vim-revision can be a version number of the "
+ echo " format '7.4.xxx' or a Mercurial commit hash."
+ echo " -r {pr-number} Review a vim-patch pull request to Neovim."
echo
echo "Set VIM_SOURCE_DIR to change where Vim's sources are stored."
echo "The default is '${VIM_SOURCE_DIR_DEFAULT}'."
}
+# Checks if a program is in the user's PATH, and is executable.
+check_executable() {
+ if [[ ! -x $(command -v "${1}") ]]; then
+ >&2 echo "${BASENAME}: '${1}' not found in PATH or not executable."
+ exit 1
+ fi
+}
+
get_vim_sources() {
+ check_executable hg
+
echo "Retrieving Vim sources."
if [[ ! -d ${VIM_SOURCE_DIR} ]]; then
echo "Cloning Vim sources into '${VIM_SOURCE_DIR}'."
@@ -41,20 +52,39 @@ get_vim_sources() {
fi
}
-get_vim_patch() {
+commit_message() {
+ echo "vim-patch:${vim_version}
+
+${vim_message}
+
+${vim_commit_url}"
+}
+
+assign_commit_details() {
if [[ ${1} =~ [0-9]\.[0-9]\.[0-9]{3,4} ]]; then
# Interpret parameter as version number.
vim_version="${1}"
vim_commit="v${1//./-}"
- strip_commit_line=true
+ local strip_commit_line=true
vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}"
else
# Interpret parameter as commit hash.
vim_version="${1:0:7}"
vim_commit="${1}"
- strip_commit_line=false
+ local strip_commit_line=false
vim_commit_url="https://code.google.com/p/vim/source/detail?r=${vim_commit}"
fi
+ vim_message="$(hg log --template "{desc}" --rev "${vim_commit}")"
+ if [[ ${strip_commit_line} == "true" ]]; then
+ # Remove first line of commit message.
+ vim_message="$(echo "${vim_message}" | sed -e '1d')"
+ fi
+}
+
+get_vim_patch() {
+ get_vim_sources
+
+ assign_commit_details "${1}"
hg log --rev "${vim_commit}" >/dev/null 2>&1 || {
>&2 echo "✘ Couldn't find Vim revision '${vim_commit}'."
@@ -65,19 +95,9 @@ get_vim_patch() {
# Collect patch details and store into variables.
vim_full="$(hg log --patch --git --verbose --rev "${vim_commit}")"
- vim_message="$(hg log --template "{desc}" --rev "${vim_commit}")"
- if [[ ${strip_commit_line} == "true" ]]; then
- # Remove first line of commit message.
- vim_message="$(echo "${vim_message}" | sed -e '1d')"
- fi
vim_diff="$(hg diff --show-function --git --change "${vim_commit}" \
| sed -e 's/\( [ab]\/src\)/\1\/nvim/g')" # Change directory to src/nvim.
- neovim_message="
-vim-patch:${vim_version}
-
-${vim_message}
-
-${vim_commit_url}"
+ neovim_message="$(commit_message)"
neovim_pr="
\`\`\`
${vim_message}
@@ -108,7 +128,7 @@ ${vim_diff}
echo
echo "Creating files."
echo "${vim_diff}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.diff"
- echo "✔ Saved patch to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.diff'."
+ echo "✔ Saved diff to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.diff'."
echo "${vim_full}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.patch"
echo "✔ Saved full commit details to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.patch'."
echo "${neovim_pr}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.pr"
@@ -132,6 +152,8 @@ ${vim_diff}
}
list_vim_patches() {
+ get_vim_sources
+
echo
echo "Vim patches missing from Neovim:"
@@ -184,24 +206,88 @@ list_vim_patches() {
echo " '${BASENAME} 1e8ebf870720e7b671f98f22d653009826304c4f'"
}
-if [[ ${1} == "--help" || ${1} == "-h" ]]; then
- usage
- exit 0
-elif [[ ${#} != 1 ]]; then
- usage
- exit 1
-fi
-
-# Checks if mercurial is in the user's PATH, and is executable.
-if [[ ! -x $(command -v hg) ]]; then
- >&2 echo "${BASENAME}: 'hg' (mercurial) not found in PATH or not executable"
- exit 1
-fi
-
-get_vim_sources
-
-if [[ ${1} == "--list" || ${1} == "-l" ]]; then
- list_vim_patches
-else
- get_vim_patch "${1}"
-fi
+review_pr() {
+ check_executable curl
+ check_executable nvim
+
+ get_vim_sources
+
+ local pr="${1}"
+ echo
+ echo "Downloading data for pull request #${pr}."
+
+ local git_patch_prefix='Subject: \[PATCH\] '
+ local neovim_patch="$(curl -Ssf "https://patch-diff.githubusercontent.com/raw/neovim/neovim/pull/${pr}.patch")"
+ echo "${neovim_patch}" > a
+ local vim_version="$(head -n 4 <<< "${neovim_patch}" | sed -n "s/${git_patch_prefix}vim-patch:\([a-z0-9.]*\)$/\1/p")"
+
+ if [[ -n "${vim_version}" ]]; then
+ echo "✔ Detected Vim patch '${vim_version}'."
+ else
+ echo "✘ Could not detect the Vim patch number."
+ echo " This script assumes that the PR contains a single commit"
+ echo " with 'vim-patch:XXX' as its title."
+ exit 1
+ fi
+
+ assign_commit_details "${vim_version}"
+
+ local expected_commit_message="$(commit_message)"
+ local message_length="$(wc -l <<< "${expected_commit_message}")"
+ local commit_message="$(tail -n +4 <<< "${neovim_patch}" | head -n "${message_length}")"
+ if [[ "${commit_message#${git_patch_prefix}}" == "${expected_commit_message}" ]]; then
+ echo "✔ Found expected commit message."
+ else
+ echo "✘ Wrong commit message."
+ echo " Expected:"
+ echo "${expected_commit_message}"
+ echo " Actual:"
+ echo "${commit_message#${git_patch_prefix}}"
+ exit 1
+ fi
+
+ local base_name="vim-${vim_version}"
+ echo
+ echo "Creating files."
+ curl -Ssfo "${NEOVIM_SOURCE_DIR}/n${base_name}.diff" "https://patch-diff.githubusercontent.com/raw/neovim/neovim/pull/${pr}.diff"
+ echo "✔ Saved pull request diff to '${NEOVIM_SOURCE_DIR}/n${base_name}.diff'."
+ echo "${neovim_patch}" > "${NEOVIM_SOURCE_DIR}/n${base_name}.patch"
+ echo "✔ Saved full pull request commit details to '${NEOVIM_SOURCE_DIR}/n${base_name}.patch'."
+ hg diff --show-function --git --change "${vim_commit}" > "${NEOVIM_SOURCE_DIR}/${base_name}.diff"
+ echo "✔ Saved Vim diff to '${NEOVIM_SOURCE_DIR}/${base_name}.diff'."
+ hg log --patch --git --verbose --rev "${vim_commit}" > "${NEOVIM_SOURCE_DIR}/${base_name}.patch"
+ echo "✔ Saved full Vim commit details to '${NEOVIM_SOURCE_DIR}/${base_name}.patch'."
+ echo "You can use 'git clean' to remove these files when you're done."
+
+ echo
+ echo "Launching nvim."
+ exec nvim -O "${NEOVIM_SOURCE_DIR}/${base_name}.diff" "${NEOVIM_SOURCE_DIR}/n${base_name}.diff"
+}
+
+while getopts "hlp:r:" opt; do
+ case ${opt} in
+ h)
+ usage
+ exit 0
+ ;;
+ l)
+ list_vim_patches
+ exit 0
+ ;;
+ p)
+ get_vim_patch "${OPTARG}"
+ exit 0
+ ;;
+ r)
+ review_pr "${OPTARG}"
+ exit 0
+ ;;
+ *)
+ exit 1
+ ;;
+ esac
+done
+
+usage
+
+# vim: et sw=2
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index ad5bac1898..747b63b1ba 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -18,8 +18,15 @@ set(HEADER_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gendeclarations.lua)
set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include)
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_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h)
+set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h)
+set(GENERATED_OPTIONS ${GENERATED_DIR}/options.generated.h)
set(EX_CMDS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genex_cmds.lua)
+set(EVENTS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gen_events.lua)
+set(OPTIONS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genoptions.lua)
+set(EVENTS_LIST_FILE ${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua)
set(EX_CMDS_DEFS_FILE ${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua)
+set(OPTIONS_LIST_FILE ${PROJECT_SOURCE_DIR}/src/nvim/options.lua)
include_directories(${GENERATED_DIR})
include_directories(${GENERATED_INCLUDES_DIR})
@@ -30,15 +37,17 @@ file(MAKE_DIRECTORY ${GENERATED_DIR}/api)
file(MAKE_DIRECTORY ${GENERATED_DIR}/api/private)
file(MAKE_DIRECTORY ${GENERATED_DIR}/msgpack_rpc)
file(MAKE_DIRECTORY ${GENERATED_DIR}/tui)
+file(MAKE_DIRECTORY ${GENERATED_DIR}/event)
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/os)
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/api)
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/api/private)
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/msgpack_rpc)
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/tui)
+file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/event)
file(GLOB NEOVIM_SOURCES *.c os/*.c api/*.c api/private/*.c msgpack_rpc/*.c
- tui/*.c)
+ tui/*.c event/*.c)
file(GLOB_RECURSE NEOVIM_HEADERS *.h)
file(GLOB UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c)
@@ -147,6 +156,9 @@ list(APPEND NEOVIM_GENERATED_SOURCES
"${MSGPACK_DISPATCH}"
"${GENERATED_EX_CMDS_ENUM}"
"${GENERATED_EX_CMDS_DEFS}"
+ "${GENERATED_EVENTS_ENUM}"
+ "${GENERATED_EVENTS_NAMES_MAP}"
+ "${GENERATED_OPTIONS}"
)
add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS}
@@ -155,6 +167,18 @@ add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS}
DEPENDS ${EX_CMDS_GENERATOR} ${EX_CMDS_DEFS_FILE}
)
+add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
+ COMMAND ${LUA_PRG} ${EVENTS_GENERATOR}
+ ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
+ DEPENDS ${EVENTS_GENERATOR} ${EVENTS_LIST_FILE}
+)
+
+add_custom_command(OUTPUT ${GENERATED_OPTIONS}
+ COMMAND ${LUA_PRG} ${OPTIONS_GENERATOR}
+ ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_OPTIONS}
+ DEPENDS ${OPTIONS_GENERATOR} ${OPTIONS_LIST_FILE}
+)
+
# Our dependencies come first.
if (LibIntl_FOUND)
@@ -193,7 +217,7 @@ install_helper(TARGETS nvim)
if(CLANG_ASAN_UBSAN)
message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.")
set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-sanitize-recover -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined ")
+ set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-sanitize-recover -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist")
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=address -fsanitize=undefined ")
elseif(CLANG_MSAN)
message(STATUS "Enabling Clang memory sanitizer for nvim.")
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index c9ada8dfc0..12c97cfffb 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -70,7 +70,6 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
/// @param line The new line.
/// @param[out] err Details of an error that may have occurred
void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)
- FUNC_ATTR_DEFERRED
{
Object l = STRING_OBJ(line);
Array array = {.items = &l, .size = 1};
@@ -83,7 +82,6 @@ void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)
/// @param index The line index
/// @param[out] err Details of an error that may have occurred
void buffer_del_line(Buffer buffer, Integer index, Error *err)
- FUNC_ATTR_DEFERRED
{
Array array = ARRAY_DICT_INIT;
buffer_set_line_slice(buffer, index, index, true, true, array, err);
@@ -108,7 +106,7 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer,
Array rv = ARRAY_DICT_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
- if (!buf) {
+ if (!buf || !inbounds(buf, start)) {
return rv;
}
@@ -171,7 +169,6 @@ void buffer_set_line_slice(Buffer buffer,
Boolean include_end,
ArrayOf(String) replacement,
Error *err)
- FUNC_ATTR_DEFERRED
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -179,6 +176,11 @@ void buffer_set_line_slice(Buffer buffer,
return;
}
+ if (!inbounds(buf, start)) {
+ api_set_error(err, Validation, _("Index out of bounds"));
+ return;
+ }
+
start = normalize_index(buf, start) + (include_start ? 0 : 1);
include_end = include_end || (end >= buf->b_ml.ml_line_count);
end = normalize_index(buf, end) + (include_end ? 1 : 0);
@@ -334,7 +336,6 @@ Object buffer_get_var(Buffer buffer, String name, Error *err)
/// @param[out] err Details of an error that may have occurred
/// @return The old value
Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
- FUNC_ATTR_DEFERRED
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -370,7 +371,6 @@ Object buffer_get_option(Buffer buffer, String name, Error *err)
/// @param value The option value
/// @param[out] err Details of an error that may have occurred
void buffer_set_option(Buffer buffer, String name, Object value, Error *err)
- FUNC_ATTR_DEFERRED
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -421,7 +421,6 @@ String buffer_get_name(Buffer buffer, Error *err)
/// @param name The buffer name
/// @param[out] err Details of an error that may have occurred
void buffer_set_name(Buffer buffer, String name, Error *err)
- FUNC_ATTR_DEFERRED
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -467,7 +466,6 @@ void buffer_insert(Buffer buffer,
Integer lnum,
ArrayOf(String) lines,
Error *err)
- FUNC_ATTR_DEFERRED
{
buffer_set_line_slice(buffer, lnum, lnum, false, true, lines, err);
}
@@ -550,3 +548,10 @@ static int64_t normalize_index(buf_T *buf, int64_t index)
index = index > buf->b_ml.ml_line_count ? buf->b_ml.ml_line_count : index;
return index;
}
+
+// Returns true if the 0-indexed `index` is within the 1-indexed buffer bounds.
+static bool inbounds(buf_T *buf, int64_t index)
+{
+ linenr_T nlines = buf->b_ml.ml_line_count;
+ return index >= -nlines && index < nlines;
+}
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index 1c958118e1..126ee4072d 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -62,7 +62,6 @@ Object tabpage_get_var(Tabpage tabpage, String name, Error *err)
/// @param[out] err Details of an error that may have occurred
/// @return The tab page handle
Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
- FUNC_ATTR_DEFERRED
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 22bdbc2ee5..b9900b5d5a 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -37,7 +37,6 @@
/// @param str The command str
/// @param[out] err Details of an error that may have occurred
void vim_command(String str, Error *err)
- FUNC_ATTR_DEFERRED
{
// Run the command
try_start();
@@ -54,7 +53,6 @@ void vim_command(String str, Error *err)
/// @see feedkeys()
/// @see vim_strsave_escape_csi
void vim_feedkeys(String keys, String mode, Boolean escape_csi)
- FUNC_ATTR_DEFERRED
{
bool remap = true;
bool insert = false;
@@ -100,6 +98,7 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi)
/// @return The number of bytes actually written, which can be lower than
/// requested if the buffer becomes full.
Integer vim_input(String keys)
+ FUNC_ATTR_ASYNC
{
return (Integer)input_enqueue(keys);
}
@@ -143,7 +142,6 @@ String vim_command_output(String str, Error *err)
/// @param[out] err Details of an error that may have occurred
/// @return The expanded object
Object vim_eval(String str, Error *err)
- FUNC_ATTR_DEFERRED
{
Object rv = OBJECT_INIT;
// Evaluate the expression
@@ -164,6 +162,55 @@ Object vim_eval(String str, Error *err)
return rv;
}
+/// Call the given function with the given arguments stored in an array.
+///
+/// @param fname Function to call
+/// @param args Functions arguments packed in an Array
+/// @param[out] err Details of an error that may have occurred
+/// @return Result of the function call
+Object vim_call_function(String fname, Array args, Error *err)
+{
+ Object rv = OBJECT_INIT;
+ if (args.size > MAX_FUNC_ARGS) {
+ api_set_error(err, Validation,
+ _("Function called with too many arguments."));
+ return rv;
+ }
+
+ // Convert the arguments in args from Object to typval_T values
+ typval_T vim_args[MAX_FUNC_ARGS + 1];
+ size_t i = 0; // also used for freeing the variables
+ for (; i < args.size; i++) {
+ if (!object_to_vim(args.items[i], &vim_args[i], err)) {
+ goto free_vim_args;
+ }
+ }
+
+ try_start();
+ // Call the function
+ typval_T rettv;
+ int dummy;
+ int r = call_func((char_u *) fname.data, (int) fname.size,
+ &rettv, (int) args.size, vim_args,
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy,
+ true,
+ NULL);
+ if (r == FAIL) {
+ api_set_error(err, Exception, _("Error calling function."));
+ }
+ if (!try_end(err)) {
+ rv = vim_to_object(&rettv);
+ }
+ clear_tv(&rettv);
+
+free_vim_args:
+ while (i > 0) {
+ clear_tv(&vim_args[--i]);
+ }
+
+ return rv;
+}
+
/// Calculates the number of display cells `str` occupies, tab is counted as
/// one cell.
///
@@ -262,7 +309,6 @@ String vim_get_current_line(Error *err)
/// @param line The line contents
/// @param[out] err Details of an error that may have occurred
void vim_set_current_line(String line, Error *err)
- FUNC_ATTR_DEFERRED
{
buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, err);
}
@@ -271,7 +317,6 @@ void vim_set_current_line(String line, Error *err)
///
/// @param[out] err Details of an error that may have occurred
void vim_del_current_line(Error *err)
- FUNC_ATTR_DEFERRED
{
buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, err);
}
@@ -293,7 +338,6 @@ Object vim_get_var(String name, Error *err)
/// @param[out] err Details of an error that may have occurred
/// @return the old value if any
Object vim_set_var(String name, Object value, Error *err)
- FUNC_ATTR_DEFERRED
{
return dict_set_value(&globvardict, name, value, err);
}
@@ -324,7 +368,6 @@ Object vim_get_option(String name, Error *err)
/// @param value The new option value
/// @param[out] err Details of an error that may have occurred
void vim_set_option(String name, Object value, Error *err)
- FUNC_ATTR_DEFERRED
{
set_option_to(NULL, SREQ_GLOBAL, name, value, err);
}
@@ -333,7 +376,6 @@ void vim_set_option(String name, Object value, Error *err)
///
/// @param str The message
void vim_out_write(String str)
- FUNC_ATTR_DEFERRED
{
write_msg(str, false);
}
@@ -342,7 +384,6 @@ void vim_out_write(String str)
///
/// @param str The message
void vim_err_write(String str)
- FUNC_ATTR_DEFERRED
{
write_msg(str, true);
}
@@ -352,7 +393,6 @@ void vim_err_write(String str)
///
/// @param str The message
void vim_report_error(String str)
- FUNC_ATTR_DEFERRED
{
vim_err_write(str);
vim_err_write((String) {.data = "\n", .size = 1});
@@ -392,7 +432,6 @@ Buffer vim_get_current_buffer(void)
/// @param id The buffer handle
/// @param[out] err Details of an error that may have occurred
void vim_set_current_buffer(Buffer buffer, Error *err)
- FUNC_ATTR_DEFERRED
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -443,7 +482,6 @@ Window vim_get_current_window(void)
///
/// @param handle The window handle
void vim_set_current_window(Window window, Error *err)
- FUNC_ATTR_DEFERRED
{
win_T *win = find_window_by_handle(window, err);
@@ -495,7 +533,6 @@ Tabpage vim_get_current_tabpage(void)
/// @param handle The tab page handle
/// @param[out] err Details of an error that may have occurred
void vim_set_current_tabpage(Tabpage tabpage, Error *err)
- FUNC_ATTR_DEFERRED
{
tabpage_T *tp = find_tab_by_handle(tabpage, err);
@@ -559,6 +596,7 @@ Dictionary vim_get_color_map(void)
Array vim_get_api_info(uint64_t channel_id)
+ FUNC_ATTR_ASYNC
{
Array rv = ARRAY_DICT_INIT;
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 5034c26c83..aad616c7bf 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -54,7 +54,6 @@ ArrayOf(Integer, 2) window_get_cursor(Window window, Error *err)
/// @param pos the (row, col) tuple representing the new position
/// @param[out] err Details of an error that may have occurred
void window_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
- FUNC_ATTR_DEFERRED
{
win_T *win = find_window_by_handle(window, err);
@@ -118,7 +117,6 @@ Integer window_get_height(Window window, Error *err)
/// @param height the new height in rows
/// @param[out] err Details of an error that may have occurred
void window_set_height(Window window, Integer height, Error *err)
- FUNC_ATTR_DEFERRED
{
win_T *win = find_window_by_handle(window, err);
@@ -162,7 +160,6 @@ Integer window_get_width(Window window, Error *err)
/// @param width the new width in columns
/// @param[out] err Details of an error that may have occurred
void window_set_width(Window window, Integer width, Error *err)
- FUNC_ATTR_DEFERRED
{
win_T *win = find_window_by_handle(window, err);
@@ -208,7 +205,6 @@ Object window_get_var(Window window, String name, Error *err)
/// @param[out] err Details of an error that may have occurred
/// @return The old value
Object window_set_var(Window window, String name, Object value, Error *err)
- FUNC_ATTR_DEFERRED
{
win_T *win = find_window_by_handle(window, err);
@@ -244,7 +240,6 @@ Object window_get_option(Window window, String name, Error *err)
/// @param value The option value
/// @param[out] err Details of an error that may have occurred
void window_set_option(Window window, String name, Object value, Error *err)
- FUNC_ATTR_DEFERRED
{
win_T *win = find_window_by_handle(window, err);
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
new file mode 100644
index 0000000000..af801c6f1a
--- /dev/null
+++ b/src/nvim/auevents.lua
@@ -0,0 +1,106 @@
+return {
+ events = {
+ 'BufAdd', -- after adding a buffer to the buffer list
+ 'BufDelete', -- deleting a buffer from the buffer list
+ 'BufEnter', -- after entering a buffer
+ 'BufFilePost', -- after renaming a buffer
+ 'BufFilePre', -- before renaming a buffer
+ 'BufHidden', -- just after buffer becomes hidden
+ 'BufLeave', -- before leaving a buffer
+ 'BufNew', -- after creating any buffer
+ 'BufNewFile', -- when creating a buffer for a new file
+ 'BufReadCmd', -- read buffer using command
+ 'BufReadPost', -- after reading a buffer
+ 'BufReadPre', -- before reading a buffer
+ 'BufUnload', -- just before unloading a buffer
+ 'BufWinEnter', -- after showing a buffer in a window
+ 'BufWinLeave', -- just after buffer removed from window
+ 'BufWipeout', -- just before really deleting a buffer
+ 'BufWriteCmd', -- write buffer using command
+ 'BufWritePost', -- after writing a buffer
+ 'BufWritePre', -- before writing a buffer
+ 'CmdUndefined', -- command undefined
+ 'CmdWinEnter', -- after entering the cmdline window
+ 'CmdWinLeave', -- before leaving the cmdline window
+ 'ColorScheme', -- after loading a colorscheme
+ 'CompleteDone', -- after finishing insert complete
+ 'CursorHold', -- cursor in same position for a while
+ 'CursorHoldI', -- idem, in Insert mode
+ 'CursorMoved', -- cursor was moved
+ 'CursorMovedI', -- cursor was moved in Insert mode
+ 'EncodingChanged', -- after changing the 'encoding' option
+ 'FileAppendCmd', -- append to a file using command
+ 'FileAppendPost', -- after appending to a file
+ 'FileAppendPre', -- before appending to a file
+ 'FileChangedRO', -- before first change to read-only file
+ 'FileChangedShell', -- after shell command that changed file
+ 'FileChangedShellPost', -- after (not) reloading changed file
+ 'FileReadCmd', -- read from a file using command
+ 'FileReadPost', -- after reading a file
+ 'FileReadPre', -- before reading a file
+ 'FileType', -- new file type detected (user defined)
+ 'FileWriteCmd', -- write to a file using command
+ 'FileWritePost', -- after writing a file
+ 'FileWritePre', -- before writing a file
+ 'FilterReadPost', -- after reading from a filter
+ 'FilterReadPre', -- before reading from a filter
+ 'FilterWritePost', -- after writing to a filter
+ 'FilterWritePre', -- before writing to a filter
+ 'FocusGained', -- got the focus
+ 'FocusLost', -- lost the focus to another app
+ 'FuncUndefined', -- if calling a function which doesn't exist
+ 'GUIEnter', -- after starting the GUI
+ 'GUIFailed', -- after starting the GUI failed
+ 'InsertChange', -- when changing Insert/Replace mode
+ 'InsertCharPre', -- before inserting a char
+ 'InsertEnter', -- when entering Insert mode
+ 'InsertLeave', -- when leaving Insert mode
+ 'JobActivity', -- when job sent some data
+ 'MenuPopup', -- just before popup menu is displayed
+ 'QuickFixCmdPost', -- after :make, :grep etc.
+ 'QuickFixCmdPre', -- before :make, :grep etc.
+ 'QuitPre', -- before :quit
+ 'RemoteReply', -- upon string reception from a remote vim
+ 'SessionLoadPost', -- after loading a session file
+ 'ShellCmdPost', -- after ":!cmd"
+ 'ShellFilterPost', -- after ":1,2!cmd", ":w !cmd", ":r !cmd".
+ 'SourceCmd', -- sourcing a Vim script using command
+ 'SourcePre', -- before sourcing a Vim script
+ 'SpellFileMissing', -- spell file missing
+ 'StdinReadPost', -- after reading from stdin
+ 'StdinReadPre', -- before reading from stdin
+ 'SwapExists', -- found existing swap file
+ 'Syntax', -- syntax selected
+ 'TabClosed', -- a tab has closed
+ 'TabEnter', -- after entering a tab page
+ 'TabLeave', -- before leaving a tab page
+ 'TabNew', -- when creating a new tab
+ 'TabNewEntered', -- after entering a new tab
+ 'TermChanged', -- after changing 'term'
+ 'TermResponse', -- after setting "v:termresponse"
+ 'TermOpen', -- after opening a terminal buffer
+ 'TextChanged', -- text was modified
+ 'TextChangedI', -- text was modified in Insert mode
+ 'User', -- user defined autocommand
+ 'VimEnter', -- after starting Vim
+ 'VimLeave', -- before exiting Vim
+ 'VimLeavePre', -- before exiting Vim and writing .viminfo
+ 'VimResized', -- after Vim window was resized
+ 'WinEnter', -- after entering a window
+ 'WinLeave', -- before leaving a window
+ },
+ aliases = {
+ BufCreate = 'BufAdd',
+ BufRead = 'BufReadPost',
+ BufWrite = 'BufWritePre',
+ FileEncoding = 'EncodingChanged',
+ },
+ -- List of neovim-specific events or aliases for the purpose of generating
+ -- syntax file
+ neovim_specific = {
+ TabNew=true,
+ TabNewEntered=true,
+ TabClosed=true,
+ TermEnter=true,
+ },
+}
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index b4b36f7fc0..2f87c9cbd2 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -2679,7 +2679,7 @@ void maketitle(void)
append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE);
- STRCAT(buf, " - VIM");
+ STRCAT(buf, " - NVIM");
if (maxlen > 0) {
/* make it shorter by removing a bit in the middle */
@@ -3576,7 +3576,7 @@ void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname)
*sfname = *ffname;
*ffname = (char_u *)fix_fname((char *)*ffname); /* expand to full path */
-#ifdef FEAT_SHORTCUT
+#ifdef WIN32
if (!buf->b_p_bin) {
char_u *rfname;
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index dd82b06158..6bcf5e804a 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -59,7 +59,7 @@
#include "nvim/terminal.h"
#include "nvim/undo.h"
#include "nvim/window.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
#include "nvim/os/input.h"
#include "nvim/os/time.h"
@@ -254,7 +254,7 @@ edit (
)
{
if (curbuf->terminal) {
- terminal_enter(true);
+ terminal_enter();
return false;
}
@@ -601,15 +601,15 @@ edit (
* Get a character for Insert mode. Ignore K_IGNORE.
*/
lastc = c; /* remember previous char for CTRL-D */
- event_enable_deferred();
+ input_enable_events();
do {
c = safe_vgetc();
} while (c == K_IGNORE);
- event_disable_deferred();
+ input_disable_events();
if (c == K_EVENT) {
c = lastc;
- event_process();
+ queue_process_events(loop.events);
continue;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index d3ab47a505..bf9a219e28 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -20,6 +20,7 @@
#include <stdbool.h>
#include <math.h>
#include <limits.h>
+#include <msgpack.h>
#include "nvim/assert.h"
#include "nvim/vim.h"
@@ -55,6 +56,7 @@
#include "nvim/misc1.h"
#include "nvim/misc2.h"
#include "nvim/keymap.h"
+#include "nvim/map.h"
#include "nvim/file_search.h"
#include "nvim/garray.h"
#include "nvim/move.h"
@@ -82,17 +84,20 @@
#include "nvim/version.h"
#include "nvim/window.h"
#include "nvim/os/os.h"
-#include "nvim/os/job.h"
-#include "nvim/os/rstream.h"
-#include "nvim/os/rstream_defs.h"
+#include "nvim/event/uv_process.h"
+#include "nvim/event/pty_process.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
#include "nvim/os/time.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/server.h"
+#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
#include "nvim/os/dl.h"
-#include "nvim/os/event.h"
#include "nvim/os/input.h"
+#include "nvim/event/loop.h"
+#include "nvim/lib/kvec.h"
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
@@ -158,6 +163,13 @@ typedef struct lval_S {
char_u *ll_newkey; /* New key for Dict in alloc. mem or NULL. */
} lval_T;
+/// Structure defining state for read_from_list()
+typedef struct {
+ const listitem_T *li; ///< Item currently read.
+ size_t offset; ///< Byte offset inside the read item.
+ size_t li_length; ///< Length of the string inside the read item.
+} ListReaderState;
+
static char *e_letunexp = N_("E18: Unexpected characters in :let");
static char *e_listidx = N_("E684: list index out of range: %" PRId64);
@@ -288,7 +300,6 @@ static ufunc_T dumuf;
#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
-#define MAX_FUNC_ARGS 20 /* maximum number of function arguments */
#define VAR_SHORT_LEN 20 /* short variable name length */
#define FIXVAR_CNT 12 /* number of fixed variables */
@@ -428,6 +439,7 @@ static struct vimvar {
{VV_NAME("progpath", VAR_STRING), VV_RO},
{VV_NAME("command_output", VAR_STRING), 0},
{VV_NAME("completed_item", VAR_DICT), VV_RO},
+ {VV_NAME("msgpack_types", VAR_DICT), VV_RO},
};
/* shorthand */
@@ -443,40 +455,103 @@ static dictitem_T vimvars_var; /* variable used for v: */
#define vimvarht vimvardict.dv_hashtab
typedef struct {
- Job *job;
+ union {
+ UvProcess uv;
+ PtyProcess pty;
+ } proc;
+ Stream in, out, err;
Terminal *term;
+ bool stopped;
bool exited;
- bool stdin_closed;
int refcount;
ufunc_T *on_stdout, *on_stderr, *on_exit;
dict_T *self;
int *status_ptr;
+ uint64_t id;
+ Queue *events;
} TerminalJobData;
+/// Structure representing current VimL to messagepack conversion state
+typedef struct {
+ enum {
+ kMPConvDict, ///< Convert dict_T *dictionary.
+ kMPConvList, ///< Convert list_T *list.
+ kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs.
+ } type;
+ union {
+ struct {
+ const dict_T *dict; ///< Currently converted dictionary.
+ const hashitem_T *hi; ///< Currently converted dictionary item.
+ size_t todo; ///< Amount of items left to process.
+ } d; ///< State of dictionary conversion.
+ struct {
+ const list_T *list; ///< Currently converted list.
+ const listitem_T *li; ///< Currently converted list item.
+ } l; ///< State of list or generic mapping conversion.
+ } data; ///< Data to convert.
+} MPConvStackVal;
+
+/// Stack used to convert VimL values to messagepack.
+typedef kvec_t(MPConvStackVal) MPConvStack;
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "eval.c.generated.h"
-#endif
-
-#define FNE_INCL_BR 1 /* find_name_end(): include [] in name */
-#define FNE_CHECK_START 2 /* find_name_end(): check name starts with
- valid character */
-// Memory pool for reusing JobEvent structures
typedef struct {
- int job_id;
TerminalJobData *data;
ufunc_T *callback;
const char *type;
list_T *received;
int status;
} JobEvent;
-static int disable_job_defer = 0;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval.c.generated.h"
+#endif
+
+#define FNE_INCL_BR 1 /* find_name_end(): include [] in name */
+#define FNE_CHECK_START 2 /* find_name_end(): check name starts with
+ valid character */
+static uint64_t current_job_id = 1;
+static PMap(uint64_t) *jobs = NULL;
+
+typedef enum {
+ kMPNil,
+ kMPBoolean,
+ kMPInteger,
+ kMPFloat,
+ kMPString,
+ kMPBinary,
+ kMPArray,
+ kMPMap,
+ kMPExt,
+} MessagePackType;
+static const char *const msgpack_type_names[] = {
+ [kMPNil] = "nil",
+ [kMPBoolean] = "boolean",
+ [kMPInteger] = "integer",
+ [kMPFloat] = "float",
+ [kMPString] = "string",
+ [kMPBinary] = "binary",
+ [kMPArray] = "array",
+ [kMPMap] = "map",
+ [kMPExt] = "ext",
+};
+static const list_T *msgpack_type_lists[] = {
+ [kMPNil] = NULL,
+ [kMPBoolean] = NULL,
+ [kMPInteger] = NULL,
+ [kMPFloat] = NULL,
+ [kMPString] = NULL,
+ [kMPBinary] = NULL,
+ [kMPArray] = NULL,
+ [kMPMap] = NULL,
+ [kMPExt] = NULL,
+};
/*
* Initialize the global and v: variables.
*/
void eval_init(void)
{
+ jobs = pmap_new(uint64_t)();
int i;
struct vimvar *p;
@@ -503,6 +578,27 @@ void eval_init(void)
/* add to compat scope dict */
hash_add(&compat_hashtab, p->vv_di.di_key);
}
+
+ dict_T *const msgpack_types_dict = dict_alloc();
+ for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
+ list_T *const type_list = list_alloc();
+ type_list->lv_lock = VAR_FIXED;
+ type_list->lv_refcount = 1;
+ dictitem_T *const di = dictitem_alloc((char_u *) msgpack_type_names[i]);
+ di->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ di->di_tv = (typval_T) {
+ .v_type = VAR_LIST,
+ .vval = { .v_list = type_list, },
+ };
+ msgpack_type_lists[i] = type_list;
+ if (dict_add(msgpack_types_dict, di) == FAIL) {
+ // There must not be duplicate items in this dictionary by definition.
+ assert(false);
+ }
+ }
+ msgpack_types_dict->dv_lock = VAR_FIXED;
+
+ set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict);
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
set_vim_var_nr(VV_HLSEARCH, 1L);
@@ -5148,24 +5244,40 @@ void list_append_dict(list_T *list, dict_T *dict)
++dict->dv_refcount;
}
-/*
- * Make a copy of "str" and append it as an item to list "l".
- * When "len" >= 0 use "str[len]".
- */
-void list_append_string(list_T *l, char_u *str, int len)
+/// Make a copy of "str" and append it as an item to list "l"
+///
+/// @param[out] l List to append to.
+/// @param[in] str String to append.
+/// @param[in] len Length of the appended string. May be negative, in this
+/// case string is considered to be usual zero-terminated
+/// string.
+void list_append_string(list_T *l, const char_u *str, int len)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ if (str == NULL) {
+ list_append_allocated_string(l, NULL);
+ } else {
+ list_append_allocated_string(l, (len >= 0
+ ? xmemdupz((char *) str, len)
+ : xstrdup((char *) str)));
+ }
+}
+
+/// Append given string to the list
+///
+/// Unlike list_append_string this function does not copy the string.
+///
+/// @param[out] l List to append to.
+/// @param[in] str String to append.
+void list_append_allocated_string(list_T *l, char *const str)
+ FUNC_ATTR_NONNULL_ARG(1)
{
listitem_T *li = listitem_alloc();
list_append(l, li);
li->li_tv.v_type = VAR_STRING;
li->li_tv.v_lock = 0;
-
- if (str == NULL) {
- li->li_tv.vval.v_string = NULL;
- } else {
- li->li_tv.vval.v_string = (len >= 0) ? vim_strnsave(str, len)
- : vim_strsave(str);
- }
+ li->li_tv.vval.v_string = (char_u *) str;
}
/*
@@ -6512,6 +6624,7 @@ static struct fst {
{"getwinposy", 0, 0, f_getwinposy},
{"getwinvar", 2, 3, f_getwinvar},
{"glob", 1, 3, f_glob},
+ {"glob2regpat", 1, 1, f_glob2regpat},
{"globpath", 2, 4, f_globpath},
{"has", 1, 1, f_has},
{"has_key", 2, 2, f_has_key},
@@ -6573,6 +6686,8 @@ static struct fst {
{"min", 1, 1, f_min},
{"mkdir", 1, 3, f_mkdir},
{"mode", 0, 1, f_mode},
+ {"msgpackdump", 1, 1, f_msgpackdump},
+ {"msgpackparse", 1, 1, f_msgpackparse},
{"nextnonblank", 1, 1, f_nextnonblank},
{"nr2char", 1, 2, f_nr2char},
{"or", 2, 2, f_or},
@@ -6857,7 +6972,7 @@ get_func_tv (
* Return FAIL when the function can't be called, OK otherwise.
* Also returns OK when an error was encountered while executing the function.
*/
-static int
+int
call_func (
char_u *funcname, /* name of the function */
int len, /* length of "name" */
@@ -7078,7 +7193,7 @@ static int non_zero_arg(typval_T *argvars)
* Get the float value of "argvars[0]" into "f".
* Returns FAIL when the argument is not a Number or Float.
*/
-static int get_float_arg(typval_T *argvars, float_T *f)
+static inline int get_float_arg(typval_T *argvars, float_T *f)
{
if (argvars[0].v_type == VAR_FLOAT) {
*f = argvars[0].vval.v_float;
@@ -7092,14 +7207,34 @@ static int get_float_arg(typval_T *argvars, float_T *f)
return FAIL;
}
+// Apply a floating point C function on a typval with one float_T.
+//
+// Some versions of glibc on i386 have an optimization that makes it harder to
+// call math functions indirectly from inside an inlined function, causing
+// compile-time errors. Avoid `inline` in that case. #3072
+#ifndef ARCH_32
+inline
+#endif
+static void float_op_wrapper(typval_T *argvars, typval_T *rettv,
+ float_T (*function)(float_T))
+{
+ float_T f;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK) {
+ rettv->vval.v_float = function(f);
+ } else {
+ rettv->vval.v_float = 0.0;
+ }
+}
+
/*
* "abs(expr)" function
*/
static void f_abs(typval_T *argvars, typval_T *rettv)
{
if (argvars[0].v_type == VAR_FLOAT) {
- rettv->v_type = VAR_FLOAT;
- rettv->vval.v_float = fabs(argvars[0].vval.v_float);
+ float_op_wrapper(argvars, rettv, &fabs);
} else {
varnumber_T n;
int error = FALSE;
@@ -7119,13 +7254,7 @@ static void f_abs(typval_T *argvars, typval_T *rettv)
*/
static void f_acos(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = acos(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &acos);
}
/*
@@ -7279,13 +7408,7 @@ static void f_argv(typval_T *argvars, typval_T *rettv)
*/
static void f_asin(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = asin(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &asin);
}
/*
@@ -7293,13 +7416,7 @@ static void f_asin(typval_T *argvars, typval_T *rettv)
*/
static void f_atan(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = atan(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &atan);
}
/*
@@ -7628,13 +7745,7 @@ static void f_call(typval_T *argvars, typval_T *rettv)
*/
static void f_ceil(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = ceil(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &ceil);
}
/*
@@ -7838,13 +7949,7 @@ static void f_copy(typval_T *argvars, typval_T *rettv)
*/
static void f_cos(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = cos(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &cos);
}
/*
@@ -7852,13 +7957,7 @@ static void f_cos(typval_T *argvars, typval_T *rettv)
*/
static void f_cosh(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = cosh(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &cosh);
}
/*
@@ -8257,13 +8356,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv)
*/
static void f_exp(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = exp(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &exp);
}
/*
@@ -8469,27 +8562,12 @@ static void f_feedkeys(typval_T *argvars, typval_T *rettv)
}
}
-/*
- * "filereadable()" function
- */
+/// "filereadable()" function
static void f_filereadable(typval_T *argvars, typval_T *rettv)
{
- int fd;
- char_u *p;
- int n;
-
-#ifndef O_NONBLOCK
-# define O_NONBLOCK 0
-#endif
- p = get_tv_string(&argvars[0]);
- if (*p && !os_isdir(p) && (fd = os_open((char *)p,
- O_RDONLY | O_NONBLOCK, 0)) >= 0) {
- n = TRUE;
- close(fd);
- } else
- n = FALSE;
-
- rettv->vval.v_number = n;
+ char_u *p = get_tv_string(&argvars[0]);
+ rettv->vval.v_number =
+ (*p && !os_isdir(p) && os_file_is_readable((char*)p));
}
/*
@@ -8742,13 +8820,7 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv)
*/
static void f_floor(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = floor(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &floor);
}
/*
@@ -9894,6 +9966,17 @@ static void f_globpath(typval_T *argvars, typval_T *rettv)
}
/*
+ * "glob2regpat()" function
+ */
+static void f_glob2regpat(typval_T *argvars, typval_T *rettv)
+{
+ char_u *pat = get_tv_string_chk(&argvars[0]);
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
+}
+
+/*
* "has()" function
*/
static void f_has(typval_T *argvars, typval_T *rettv)
@@ -9915,9 +9998,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
#endif
"arabic",
"autocmd",
-#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
- || defined(FEAT_GUI_W32) \
- || defined(FEAT_GUI_MOTIF))
+#ifdef FEAT_BROWSE
"browsefilter",
#endif
"byte_offset",
@@ -10681,29 +10762,27 @@ static void f_jobclose(typval_T *argvars, typval_T *rettv)
return;
}
- Job *job = job_find(argvars[0].vval.v_number);
-
- if (!is_user_job(job)) {
- // Invalid job id
+ TerminalJobData *data = find_job(argvars[0].vval.v_number);
+ if (!data) {
EMSG(_(e_invjob));
return;
}
+ Process *proc = (Process *)&data->proc;
+
if (argvars[1].v_type == VAR_STRING) {
char *stream = (char *)argvars[1].vval.v_string;
if (!strcmp(stream, "stdin")) {
- job_close_in(job);
- ((TerminalJobData *)job_data(job))->stdin_closed = true;
+ process_close_in(proc);
} else if (!strcmp(stream, "stdout")) {
- job_close_out(job);
+ process_close_out(proc);
} else if (!strcmp(stream, "stderr")) {
- job_close_err(job);
+ process_close_err(proc);
} else {
EMSG2(_("Invalid job stream \"%s\""), stream);
}
} else {
- ((TerminalJobData *)job_data(job))->stdin_closed = true;
- job_close_streams(job);
+ process_close_streams(proc);
}
}
@@ -10724,15 +10803,13 @@ static void f_jobsend(typval_T *argvars, typval_T *rettv)
return;
}
- Job *job = job_find(argvars[0].vval.v_number);
-
- if (!is_user_job(job)) {
- // Invalid job id
+ TerminalJobData *data = find_job(argvars[0].vval.v_number);
+ if (!data) {
EMSG(_(e_invjob));
return;
}
- if (((TerminalJobData *)job_data(job))->stdin_closed) {
+ if (((Process *)&data->proc)->in->closed) {
EMSG(_("Can't send data to the job: stdin is closed"));
return;
}
@@ -10746,7 +10823,7 @@ static void f_jobsend(typval_T *argvars, typval_T *rettv)
}
WBuffer *buf = wstream_new_buffer(input, input_len, 1, xfree);
- rettv->vval.v_number = job_write(job, buf);
+ rettv->vval.v_number = wstream_write(data->proc.uv.process.in, buf);
}
// "jobresize(job, width, height)" function
@@ -10766,19 +10843,20 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv)
return;
}
- Job *job = job_find(argvars[0].vval.v_number);
- if (!is_user_job(job)) {
- // Probably an invalid job id
+ TerminalJobData *data = find_job(argvars[0].vval.v_number);
+ if (!data) {
EMSG(_(e_invjob));
return;
}
- if (!job_resize(job, argvars[1].vval.v_number, argvars[2].vval.v_number)) {
+ if (data->proc.uv.process.type != kProcessTypePty) {
EMSG(_(e_jobnotpty));
return;
}
+ pty_process_resize(&data->proc.pty, argvars[1].vval.v_number,
+ argvars[2].vval.v_number);
rettv->vval.v_number = 1;
}
@@ -10867,37 +10945,33 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
}
}
- JobOptions opts = common_job_options(argv, on_stdout, on_stderr, on_exit,
- job_opts);
-
- if (!job_opts) {
- goto start;
- }
+ bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0;
+ TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
+ job_opts, pty);
+ Process *proc = (Process *)&data->proc;
- opts.pty = get_dict_number(job_opts, (uint8_t *)"pty");
- if (opts.pty) {
+ if (pty) {
uint16_t width = get_dict_number(job_opts, (uint8_t *)"width");
if (width > 0) {
- opts.width = width;
+ data->proc.pty.width = width;
}
uint16_t height = get_dict_number(job_opts, (uint8_t *)"height");
if (height > 0) {
- opts.height = height;
+ data->proc.pty.height = height;
}
char *term = (char *)get_dict_string(job_opts, (uint8_t *)"TERM", true);
if (term) {
- opts.term_name = term;
+ data->proc.pty.term_name = term;
}
}
-start:
if (!on_stdout) {
- opts.stdout_cb = NULL;
+ proc->out = NULL;
}
if (!on_stderr) {
- opts.stderr_cb = NULL;
+ proc->err = NULL;
}
- common_job_start(opts, rettv);
+ common_job_start(data, rettv);
}
// "jobstop()" function
@@ -10916,14 +10990,15 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv)
return;
}
- Job *job = job_find(argvars[0].vval.v_number);
- if (!is_user_job(job)) {
+ TerminalJobData *data = find_job(argvars[0].vval.v_number);
+ if (!data) {
EMSG(_(e_invjob));
return;
}
- job_stop(job);
+ process_stop((Process *)&data->proc);
+ data->stopped = true;
rettv->vval.v_number = 1;
}
@@ -10947,30 +11022,24 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv)
list_T *rv = list_alloc();
ui_busy_start();
- // disable breakchecks, which could result in job callbacks being executed
- // at unexpected places
- disable_breakcheck++;
- // disable job event deferring so the callbacks are processed while waiting.
- if (!disable_job_defer++) {
- // process any pending job events in the deferred queue, but only do this if
- // deferred is not disabled(at the top-level `jobwait()` call)
- event_process();
- }
+ Queue *waiting_jobs = queue_new_parent(loop_on_put, &loop);
// For each item in the input list append an integer to the output list. -3
// is used to represent an invalid job id, -2 is for a interrupted job and
// -1 for jobs that were skipped or timed out.
for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
- Job *job = NULL;
+ TerminalJobData *data = NULL;
if (arg->li_tv.v_type != VAR_NUMBER
- || !(job = job_find(arg->li_tv.vval.v_number))
- || !is_user_job(job)) {
+ || !(data = find_job(arg->li_tv.vval.v_number))) {
list_append_number(rv, -3);
} else {
- TerminalJobData *data = job_data(job);
// append the list item and set the status pointer so we'll collect the
// status code when the job exits
list_append_number(rv, -1);
data->status_ptr = &rv->lv_last->li_tv.vval.v_number;
+ // Process any pending events for the job because we'll temporarily
+ // replace the parent queue
+ queue_process_events(data->events);
+ queue_replace_parent(data->events, waiting_jobs);
}
}
@@ -10982,18 +11051,16 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv)
}
for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
- Job *job = NULL;
+ TerminalJobData *data = NULL;
if (remaining == 0) {
// timed out
break;
}
if (arg->li_tv.v_type != VAR_NUMBER
- || !(job = job_find(arg->li_tv.vval.v_number))
- || !is_user_job(job)) {
+ || !(data = find_job(arg->li_tv.vval.v_number))) {
continue;
}
- TerminalJobData *data = job_data(job);
- int status = job_wait(job, remaining);
+ int status = process_wait((Process *)&data->proc, remaining, waiting_jobs);
if (status < 0) {
// interrupted or timed out, skip remaining jobs.
if (status == -2) {
@@ -11013,25 +11080,31 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv)
}
}
- // poll to ensure any pending callbacks from the last job are invoked
- event_poll(0);
-
for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
- Job *job = NULL;
+ TerminalJobData *data = NULL;
if (arg->li_tv.v_type != VAR_NUMBER
- || !(job = job_find(arg->li_tv.vval.v_number))
- || !is_user_job(job)) {
+ || !(data = find_job(arg->li_tv.vval.v_number))) {
continue;
}
- TerminalJobData *data = job_data(job);
// remove the status pointer because the list may be freed before the
// job exits
data->status_ptr = NULL;
}
- disable_job_defer--;
- disable_breakcheck--;
- ui_busy_stop();
+ // restore the parent queue for any jobs still alive
+ for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
+ TerminalJobData *data = NULL;
+ if (arg->li_tv.v_type != VAR_NUMBER
+ || !(data = pmap_get(uint64_t)(jobs, arg->li_tv.vval.v_number))) {
+ continue;
+ }
+ // restore the parent queue for the job
+ queue_process_events(data->events);
+ queue_replace_parent(data->events, loop.events);
+ }
+
+ queue_free(waiting_jobs);
+ ui_busy_stop();
rv->lv_refcount++;
rettv->v_type = VAR_LIST;
rettv->vval.v_list = rv;
@@ -11306,13 +11379,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
*/
static void f_log(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = log(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &log);
}
/*
@@ -11320,13 +11387,7 @@ static void f_log(typval_T *argvars, typval_T *rettv)
*/
static void f_log10(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = log10(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &log10);
}
@@ -11718,33 +11779,6 @@ static void f_min(typval_T *argvars, typval_T *rettv)
max_min(argvars, rettv, FALSE);
}
-
-/*
- * Create the directory in which "dir" is located, and higher levels when
- * needed.
- */
-static int mkdir_recurse(char_u *dir, int prot)
-{
- char_u *p;
- char_u *updir;
- int r = FAIL;
-
- /* Get end of directory name in "dir".
- * We're done when it's "/" or "c:/". */
- p = path_tail_with_sep(dir);
- if (p <= get_past_head(dir))
- return OK;
-
- /* If the directory exists we're done. Otherwise: create it.*/
- updir = vim_strnsave(dir, (int)(p - dir));
- if (os_isdir(updir))
- r = OK;
- else if (mkdir_recurse(updir, prot) == OK)
- r = vim_mkdir_emsg(updir, prot);
- xfree(updir);
- return r;
-}
-
/*
* "mkdir()" function
*/
@@ -11769,8 +11803,19 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv)
if (argvars[1].v_type != VAR_UNKNOWN) {
if (argvars[2].v_type != VAR_UNKNOWN)
prot = get_tv_number_chk(&argvars[2], NULL);
- if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
- mkdir_recurse(dir, prot);
+ if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) {
+ char *failed_dir;
+ int ret = os_mkdir_recurse((char *) dir, prot, &failed_dir);
+ if (ret != 0) {
+ EMSG3(_(e_mkdir), failed_dir, os_strerror(ret));
+ xfree(failed_dir);
+ rettv->vval.v_number = FAIL;
+ return;
+ } else {
+ rettv->vval.v_number = OK;
+ return;
+ }
+ }
}
rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
}
@@ -11832,6 +11877,827 @@ static void f_mode(typval_T *argvars, typval_T *rettv)
rettv->v_type = VAR_STRING;
}
+/// Msgpack callback for writing to readfile()-style list
+static int msgpack_list_write(void *data, const char *buf, size_t len)
+{
+ if (len == 0) {
+ return 0;
+ }
+ list_T *const list = (list_T *) data;
+ const char *const end = buf + len;
+ const char *line_end = buf;
+ if (list->lv_last == NULL) {
+ list_append_string(list, NULL, 0);
+ }
+ listitem_T *li = list->lv_last;
+ do {
+ const char *line_start = line_end;
+ line_end = xmemscan(line_start, NL, end - line_start);
+ if (line_end == line_start) {
+ list_append_allocated_string(list, NULL);
+ } else {
+ const size_t line_length = line_end - line_start;
+ char *str;
+ if (li == NULL) {
+ str = xmemdupz(line_start, line_length);
+ } else {
+ const size_t li_len = (li->li_tv.vval.v_string == NULL
+ ? 0
+ : STRLEN(li->li_tv.vval.v_string));
+ li->li_tv.vval.v_string = xrealloc(li->li_tv.vval.v_string,
+ li_len + line_length + 1);
+ str = (char *) li->li_tv.vval.v_string + li_len;
+ memmove(str, line_start, line_length);
+ str[line_length] = 0;
+ }
+ for (size_t i = 0; i < line_length; i++) {
+ if (str[i] == NUL) {
+ str[i] = NL;
+ }
+ }
+ if (li == NULL) {
+ list_append_allocated_string(list, str);
+ } else {
+ li = NULL;
+ }
+ if (line_end == end - 1) {
+ list_append_allocated_string(list, NULL);
+ }
+ }
+ line_end++;
+ } while (line_end < end);
+ return 0;
+}
+
+/// Convert readfile()-style list to a char * buffer with length
+///
+/// @param[in] list Converted list.
+/// @param[out] ret_len Resulting buffer length.
+/// @param[out] ret_buf Allocated buffer with the result or NULL if ret_len is
+/// zero.
+///
+/// @return true in case of success, false in case of failure.
+static inline bool vim_list_to_buf(const list_T *const list,
+ size_t *const ret_len, char **const ret_buf)
+ FUNC_ATTR_NONNULL_ARG(2,3) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ size_t len = 0;
+ if (list != NULL) {
+ for (const listitem_T *li = list->lv_first;
+ li != NULL;
+ li = li->li_next) {
+ if (li->li_tv.v_type != VAR_STRING) {
+ return false;
+ }
+ len++;
+ if (li->li_tv.vval.v_string != 0) {
+ len += STRLEN(li->li_tv.vval.v_string);
+ }
+ }
+ if (len) {
+ len--;
+ }
+ }
+ *ret_len = len;
+ if (len == 0) {
+ *ret_buf = NULL;
+ return true;
+ }
+ ListReaderState lrstate = init_lrstate(list);
+ char *const buf = xmalloc(len);
+ size_t read_bytes;
+ if (read_from_list(&lrstate, buf, len, &read_bytes) != OK) {
+ assert(false);
+ }
+ assert(len == read_bytes);
+ *ret_buf = buf;
+ return true;
+}
+
+/// Convert one VimL value to msgpack
+///
+/// @param packer Messagepack packer.
+/// @param[out] mpstack Stack with values to convert. Only used for pushing
+/// values to it.
+/// @param[in] tv Converted value.
+///
+/// @return OK in case of success, FAIL otherwise.
+static int convert_one_value(msgpack_packer *const packer,
+ MPConvStack *const mpstack,
+ const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ switch (tv->v_type) {
+#define CHECK_SELF_REFERENCE(conv_type, vval_name, ptr) \
+ do { \
+ for (size_t i = 0; i < kv_size(*mpstack); i++) { \
+ if (kv_A(*mpstack, i).type == conv_type \
+ && kv_A(*mpstack, i).data.vval_name == ptr) { \
+ EMSG2(_(e_invarg2), "container references itself"); \
+ return FAIL; \
+ } \
+ } \
+ } while (0)
+ case VAR_STRING: {
+ if (tv->vval.v_string == NULL) {
+ msgpack_pack_bin(packer, 0);
+ } else {
+ const size_t len = STRLEN(tv->vval.v_string);
+ msgpack_pack_bin(packer, len);
+ msgpack_pack_bin_body(packer, tv->vval.v_string, len);
+ }
+ break;
+ }
+ case VAR_NUMBER: {
+ msgpack_pack_int64(packer, (int64_t) tv->vval.v_number);
+ break;
+ }
+ case VAR_FLOAT: {
+ msgpack_pack_double(packer, (double) tv->vval.v_float);
+ break;
+ }
+ case VAR_FUNC: {
+ EMSG2(_(e_invarg2), "attempt to dump function reference");
+ return FAIL;
+ }
+ case VAR_LIST: {
+ if (tv->vval.v_list == NULL) {
+ msgpack_pack_array(packer, 0);
+ break;
+ }
+ CHECK_SELF_REFERENCE(kMPConvList, l.list, tv->vval.v_list);
+ msgpack_pack_array(packer, tv->vval.v_list->lv_len);
+ kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) {
+ .type = kMPConvList,
+ .data = {
+ .l = {
+ .list = tv->vval.v_list,
+ .li = tv->vval.v_list->lv_first,
+ },
+ },
+ }));
+ break;
+ }
+ case VAR_DICT: {
+ if (tv->vval.v_dict == NULL) {
+ msgpack_pack_map(packer, 0);
+ break;
+ }
+ const dictitem_T *type_di;
+ const dictitem_T *val_di;
+ if (tv->vval.v_dict->dv_hashtab.ht_used == 2
+ && (type_di = dict_find((dict_T *) tv->vval.v_dict,
+ (char_u *) "_TYPE", -1)) != NULL
+ && type_di->di_tv.v_type == VAR_LIST
+ && (val_di = dict_find((dict_T *) tv->vval.v_dict,
+ (char_u *) "_VAL", -1)) != NULL) {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(msgpack_type_lists); i++) {
+ if (type_di->di_tv.vval.v_list == msgpack_type_lists[i]) {
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(msgpack_type_lists)) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ switch ((MessagePackType) i) {
+ case kMPNil: {
+ msgpack_pack_nil(packer);
+ break;
+ }
+ case kMPBoolean: {
+ if (val_di->di_tv.v_type != VAR_NUMBER) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ if (val_di->di_tv.vval.v_number) {
+ msgpack_pack_true(packer);
+ } else {
+ msgpack_pack_false(packer);
+ }
+ break;
+ }
+ case kMPInteger: {
+ const list_T *val_list;
+ varnumber_T sign;
+ varnumber_T highest_bits;
+ varnumber_T high_bits;
+ varnumber_T low_bits;
+ // List of 4 integers; first is signed (should be 1 or -1, but this
+ // is not checked), second is unsigned and have at most one (sign is
+ // -1) or two (sign is 1) non-zero bits (number of bits is not
+ // checked), other unsigned and have at most 31 non-zero bits
+ // (number of bits is not checked).
+ if (val_di->di_tv.v_type != VAR_LIST
+ || (val_list = val_di->di_tv.vval.v_list) == NULL
+ || val_list->lv_len != 4
+ || val_list->lv_first->li_tv.v_type != VAR_NUMBER
+ || (sign = val_list->lv_first->li_tv.vval.v_number) == 0
+ || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER
+ || (highest_bits =
+ val_list->lv_first->li_next->li_tv.vval.v_number) < 0
+ || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER
+ || (high_bits =
+ val_list->lv_last->li_prev->li_tv.vval.v_number) < 0
+ || val_list->lv_last->li_tv.v_type != VAR_NUMBER
+ || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ uint64_t number = ((uint64_t) (((uint64_t) highest_bits) << 62)
+ | (uint64_t) (((uint64_t) high_bits) << 31)
+ | (uint64_t) low_bits);
+ if (sign > 0) {
+ msgpack_pack_uint64(packer, number);
+ } else {
+ msgpack_pack_int64(packer, (int64_t) (-number));
+ }
+ break;
+ }
+ case kMPFloat: {
+ if (val_di->di_tv.v_type != VAR_FLOAT) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ msgpack_pack_double(packer, val_di->di_tv.vval.v_float);
+ break;
+ }
+ case kMPString:
+ case kMPBinary: {
+ const bool is_string = ((MessagePackType) i == kMPString);
+ if (val_di->di_tv.v_type != VAR_LIST) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ size_t len;
+ char *buf;
+ if (!vim_list_to_buf(val_di->di_tv.vval.v_list, &len, &buf)) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ if (is_string) {
+ msgpack_pack_str(packer, len);
+ } else {
+ msgpack_pack_bin(packer, len);
+ }
+ if (len == 0) {
+ break;
+ }
+ if (is_string) {
+ msgpack_pack_str_body(packer, buf, len);
+ } else {
+ msgpack_pack_bin_body(packer, buf, len);
+ }
+ xfree(buf);
+ break;
+ }
+ case kMPArray: {
+ if (val_di->di_tv.v_type != VAR_LIST) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ CHECK_SELF_REFERENCE(kMPConvList, l.list,
+ val_di->di_tv.vval.v_list);
+ msgpack_pack_array(packer, val_di->di_tv.vval.v_list->lv_len);
+ kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) {
+ .type = kMPConvList,
+ .data = {
+ .l = {
+ .list = val_di->di_tv.vval.v_list,
+ .li = val_di->di_tv.vval.v_list->lv_first,
+ },
+ },
+ }));
+ break;
+ }
+ case kMPMap: {
+ if (val_di->di_tv.v_type != VAR_LIST) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ if (val_di->di_tv.vval.v_list == NULL) {
+ msgpack_pack_map(packer, 0);
+ break;
+ }
+ const list_T *const val_list = val_di->di_tv.vval.v_list;
+ for (const listitem_T *li = val_list->lv_first; li != NULL;
+ li = li->li_next) {
+ if (li->li_tv.v_type != VAR_LIST
+ || li->li_tv.vval.v_list->lv_len != 2) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ }
+ CHECK_SELF_REFERENCE(kMPConvPairs, l.list, val_list);
+ msgpack_pack_map(packer, val_list->lv_len);
+ kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) {
+ .type = kMPConvPairs,
+ .data = {
+ .l = {
+ .list = val_list,
+ .li = val_list->lv_first,
+ },
+ },
+ }));
+ break;
+ }
+ case kMPExt: {
+ const list_T *val_list;
+ varnumber_T type;
+ if (val_di->di_tv.v_type != VAR_LIST
+ || (val_list = val_di->di_tv.vval.v_list) == NULL
+ || val_list->lv_len != 2
+ || (val_list->lv_first->li_tv.v_type != VAR_NUMBER)
+ || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX
+ || type < INT8_MIN
+ || (val_list->lv_last->li_tv.v_type != VAR_LIST)) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ size_t len;
+ char *buf;
+ if (!vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list,
+ &len, &buf)) {
+ goto vim_to_msgpack_regural_dict;
+ }
+ msgpack_pack_ext(packer, len, (int8_t) type);
+ msgpack_pack_ext_body(packer, buf, len);
+ xfree(buf);
+ break;
+ }
+ }
+ break;
+ }
+vim_to_msgpack_regural_dict:
+ CHECK_SELF_REFERENCE(kMPConvDict, d.dict, tv->vval.v_dict);
+ msgpack_pack_map(packer, tv->vval.v_dict->dv_hashtab.ht_used);
+ kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) {
+ .type = kMPConvDict,
+ .data = {
+ .d = {
+ .dict = tv->vval.v_dict,
+ .hi = tv->vval.v_dict->dv_hashtab.ht_array,
+ .todo = tv->vval.v_dict->dv_hashtab.ht_used,
+ },
+ },
+ }));
+ break;
+ }
+ }
+#undef CHECK_SELF_REFERENCE
+ return OK;
+}
+
+/// Convert typval_T to messagepack
+static int vim_to_msgpack(msgpack_packer *const packer,
+ const typval_T *const tv)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ MPConvStack mpstack;
+ kv_init(mpstack);
+ if (convert_one_value(packer, &mpstack, tv) == FAIL) {
+ goto vim_to_msgpack_error_ret;
+ }
+ while (kv_size(mpstack)) {
+ MPConvStackVal *cur_mpsv = &kv_A(mpstack, kv_size(mpstack) - 1);
+ const typval_T *cur_tv = NULL;
+ switch (cur_mpsv->type) {
+ case kMPConvDict: {
+ if (!cur_mpsv->data.d.todo) {
+ (void) kv_pop(mpstack);
+ continue;
+ }
+ while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) {
+ cur_mpsv->data.d.hi++;
+ }
+ const dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi);
+ cur_mpsv->data.d.todo--;
+ cur_mpsv->data.d.hi++;
+ const size_t key_len = STRLEN(&di->di_key[0]);
+ msgpack_pack_str(packer, key_len);
+ msgpack_pack_str_body(packer, &di->di_key[0], key_len);
+ cur_tv = &di->di_tv;
+ break;
+ }
+ case kMPConvList: {
+ if (cur_mpsv->data.l.li == NULL) {
+ (void) kv_pop(mpstack);
+ continue;
+ }
+ cur_tv = &cur_mpsv->data.l.li->li_tv;
+ cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next;
+ break;
+ }
+ case kMPConvPairs: {
+ if (cur_mpsv->data.l.li == NULL) {
+ (void) kv_pop(mpstack);
+ continue;
+ }
+ const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list;
+ if (convert_one_value(packer, &mpstack, &kv_pair->lv_first->li_tv)
+ == FAIL) {
+ goto vim_to_msgpack_error_ret;
+ }
+ cur_tv = &kv_pair->lv_last->li_tv;
+ cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next;
+ break;
+ }
+ }
+ if (convert_one_value(packer, &mpstack, cur_tv) == FAIL) {
+ goto vim_to_msgpack_error_ret;
+ }
+ }
+ kv_destroy(mpstack);
+ return OK;
+vim_to_msgpack_error_ret:
+ kv_destroy(mpstack);
+ return FAIL;
+}
+
+/// "msgpackdump()" function
+static void f_msgpackdump(typval_T *argvars, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (argvars[0].v_type != VAR_LIST) {
+ EMSG2(_(e_listarg), "msgpackdump()");
+ return;
+ }
+ list_T *ret_list = rettv_list_alloc(rettv);
+ const list_T *list = argvars[0].vval.v_list;
+ if (list == NULL) {
+ return;
+ }
+ msgpack_packer *lpacker = msgpack_packer_new(ret_list, &msgpack_list_write);
+ for (const listitem_T *li = list->lv_first; li != NULL; li = li->li_next) {
+ if (vim_to_msgpack(lpacker, &li->li_tv) == FAIL) {
+ break;
+ }
+ }
+ msgpack_packer_free(lpacker);
+}
+
+/// Read bytes from list
+///
+/// @param[in,out] state Structure describing position in list from which
+/// reading should start. Is updated to reflect position
+/// at which reading ended.
+/// @param[out] buf Buffer to write to.
+/// @param[in] nbuf Buffer length.
+/// @param[out] read_bytes Is set to amount of bytes read.
+///
+/// @return OK when reading was finished, FAIL in case of error (i.e. list item
+/// was not a string), NOTDONE if reading was successfull, but there are
+/// more bytes to read.
+static int read_from_list(ListReaderState *const state, char *const buf,
+ const size_t nbuf, size_t *const read_bytes)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ char *const buf_end = buf + nbuf;
+ char *p = buf;
+ while (p < buf_end) {
+ for (size_t i = state->offset; i < state->li_length && p < buf_end; i++) {
+ const char ch = state->li->li_tv.vval.v_string[state->offset++];
+ *p++ = (ch == NL ? NUL : ch);
+ }
+ if (p < buf_end) {
+ state->li = state->li->li_next;
+ if (state->li == NULL) {
+ *read_bytes = (size_t) (p - buf);
+ return OK;
+ }
+ *p++ = NL;
+ if (state->li->li_tv.v_type != VAR_STRING) {
+ *read_bytes = (size_t) (p - buf);
+ return FAIL;
+ }
+ state->offset = 0;
+ state->li_length = (state->li->li_tv.vval.v_string == NULL
+ ? 0
+ : STRLEN(state->li->li_tv.vval.v_string));
+ }
+ }
+ *read_bytes = nbuf;
+ return (state->offset < state->li_length || state->li->li_next != NULL
+ ? NOTDONE
+ : OK);
+}
+
+/// Initialize ListReaderState structure
+static inline ListReaderState init_lrstate(const list_T *const list)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return (ListReaderState) {
+ .li = list->lv_first,
+ .offset = 0,
+ .li_length = (list->lv_first->li_tv.vval.v_string == NULL
+ ? 0
+ : STRLEN(list->lv_first->li_tv.vval.v_string)),
+ };
+}
+
+/// Convert msgpack object to a VimL one
+static int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+#define INIT_SPECIAL_DICT(tv, type, val) \
+ do { \
+ dict_T *const dict = dict_alloc(); \
+ dictitem_T *const type_di = dictitem_alloc((char_u *) "_TYPE"); \
+ type_di->di_tv.v_type = VAR_LIST; \
+ type_di->di_tv.v_lock = 0; \
+ type_di->di_tv.vval.v_list = (list_T *) msgpack_type_lists[type]; \
+ type_di->di_tv.vval.v_list->lv_refcount++; \
+ dict_add(dict, type_di); \
+ dictitem_T *const val_di = dictitem_alloc((char_u *) "_VAL"); \
+ val_di->di_tv = val; \
+ dict_add(dict, val_di); \
+ tv->v_type = VAR_DICT; \
+ dict->dv_refcount++; \
+ tv->vval.v_dict = dict; \
+ } while (0)
+ switch (mobj.type) {
+ case MSGPACK_OBJECT_NIL: {
+ INIT_SPECIAL_DICT(rettv, kMPNil, ((typval_T) {
+ .v_type = VAR_NUMBER,
+ .v_lock = 0,
+ .vval = { .v_number = 0 },
+ }));
+ break;
+ }
+ case MSGPACK_OBJECT_BOOLEAN: {
+ INIT_SPECIAL_DICT(rettv, kMPBoolean,
+ ((typval_T) {
+ .v_type = VAR_NUMBER,
+ .v_lock = 0,
+ .vval = {
+ .v_number = (varnumber_T) mobj.via.boolean,
+ },
+ }));
+ break;
+ }
+ case MSGPACK_OBJECT_POSITIVE_INTEGER: {
+ if (mobj.via.u64 <= VARNUMBER_MAX) {
+ *rettv = (typval_T) {
+ .v_type = VAR_NUMBER,
+ .v_lock = 0,
+ .vval = { .v_number = (varnumber_T) mobj.via.u64 },
+ };
+ } else {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ INIT_SPECIAL_DICT(rettv, kMPInteger,
+ ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = 0,
+ .vval = { .v_list = list },
+ }));
+ uint64_t n = mobj.via.u64;
+ list_append_number(list, 1);
+ list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
+ list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
+ list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER: {
+ if (mobj.via.i64 >= VARNUMBER_MIN) {
+ *rettv = (typval_T) {
+ .v_type = VAR_NUMBER,
+ .v_lock = 0,
+ .vval = { .v_number = (varnumber_T) mobj.via.i64 },
+ };
+ } else {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ INIT_SPECIAL_DICT(rettv, kMPInteger,
+ ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = 0,
+ .vval = { .v_list = list },
+ }));
+ uint64_t n = -((uint64_t) mobj.via.i64);
+ list_append_number(list, -1);
+ list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
+ list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
+ list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_FLOAT: {
+ *rettv = (typval_T) {
+ .v_type = VAR_FLOAT,
+ .v_lock = 0,
+ .vval = { .v_float = mobj.via.f64 },
+ };
+ break;
+ }
+ case MSGPACK_OBJECT_STR: {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ INIT_SPECIAL_DICT(rettv, kMPString,
+ ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = 0,
+ .vval = { .v_list = list },
+ }));
+ if (msgpack_list_write((void *) list, mobj.via.str.ptr, mobj.via.str.size)
+ == -1) {
+ return FAIL;
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_BIN: {
+ if (memchr(mobj.via.bin.ptr, NUL, mobj.via.bin.size) == NULL) {
+ *rettv = (typval_T) {
+ .v_type = VAR_STRING,
+ .v_lock = 0,
+ .vval = { .v_string = xmemdupz(mobj.via.bin.ptr, mobj.via.bin.size) },
+ };
+ break;
+ }
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ INIT_SPECIAL_DICT(rettv, kMPBinary,
+ ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = 0,
+ .vval = { .v_list = list },
+ }));
+ if (msgpack_list_write((void *) list, mobj.via.bin.ptr, mobj.via.bin.size)
+ == -1) {
+ return FAIL;
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_ARRAY: {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ *rettv = (typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = 0,
+ .vval = { .v_list = list },
+ };
+ for (size_t i = 0; i < mobj.via.array.size; i++) {
+ listitem_T *const li = listitem_alloc();
+ li->li_tv.v_type = VAR_UNKNOWN;
+ list_append(list, li);
+ if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) {
+ return FAIL;
+ }
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_MAP: {
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
+ || mobj.via.map.ptr[i].key.via.str.size == 0
+ || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
+ mobj.via.map.ptr[i].key.via.str.size) != NULL) {
+ goto msgpack_to_vim_generic_map;
+ }
+ }
+ dict_T *const dict = dict_alloc();
+ dict->dv_refcount++;
+ *rettv = (typval_T) {
+ .v_type = VAR_DICT,
+ .v_lock = 0,
+ .vval = { .v_dict = dict },
+ };
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key)
+ + mobj.via.map.ptr[i].key.via.str.size);
+ memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
+ mobj.via.map.ptr[i].key.via.str.size);
+ di->di_tv.v_type = VAR_UNKNOWN;
+ if (dict_add(dict, di) == FAIL) {
+ // Duplicate key: fallback to generic map
+ clear_tv(rettv);
+ xfree(di);
+ goto msgpack_to_vim_generic_map;
+ }
+ if (msgpack_to_vim(mobj.via.map.ptr[i].val, &di->di_tv) == FAIL) {
+ return FAIL;
+ }
+ }
+ break;
+msgpack_to_vim_generic_map: {}
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ INIT_SPECIAL_DICT(rettv, kMPMap,
+ ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = 0,
+ .vval = { .v_list = list },
+ }));
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ list_T *const kv_pair = list_alloc();
+ list_append_list(list, kv_pair);
+ listitem_T *const key_li = listitem_alloc();
+ key_li->li_tv.v_type = VAR_UNKNOWN;
+ list_append(kv_pair, key_li);
+ listitem_T *const val_li = listitem_alloc();
+ val_li->li_tv.v_type = VAR_UNKNOWN;
+ list_append(kv_pair, val_li);
+ if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) {
+ return FAIL;
+ }
+ if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_li->li_tv) == FAIL) {
+ return FAIL;
+ }
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_EXT: {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ list_append_number(list, mobj.via.ext.type);
+ list_T *const ext_val_list = list_alloc();
+ list_append_list(list, ext_val_list);
+ INIT_SPECIAL_DICT(rettv, kMPExt,
+ ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = 0,
+ .vval = { .v_list = list },
+ }));
+ if (msgpack_list_write((void *) ext_val_list, mobj.via.ext.ptr,
+ mobj.via.ext.size) == -1) {
+ return FAIL;
+ }
+ break;
+ }
+ }
+#undef INIT_SPECIAL_DICT
+ return OK;
+}
+
+/// "msgpackparse" function
+static void f_msgpackparse(typval_T *argvars, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (argvars[0].v_type != VAR_LIST) {
+ EMSG2(_(e_listarg), "msgpackparse()");
+ }
+ list_T *ret_list = rettv_list_alloc(rettv);
+ const list_T *list = argvars[0].vval.v_list;
+ if (list == NULL || list->lv_first == NULL) {
+ return;
+ }
+ if (list->lv_first->li_tv.v_type != VAR_STRING) {
+ EMSG2(_(e_invarg2), "List item is not a string");
+ return;
+ }
+ ListReaderState lrstate = init_lrstate(list);
+ msgpack_unpacker *const unpacker = msgpack_unpacker_new(IOSIZE);
+ if (unpacker == NULL) {
+ EMSG(_(e_outofmem));
+ return;
+ }
+ msgpack_unpacked unpacked;
+ msgpack_unpacked_init(&unpacked);
+ do {
+ if (!msgpack_unpacker_reserve_buffer(unpacker, IOSIZE)) {
+ EMSG(_(e_outofmem));
+ goto f_msgpackparse_exit;
+ }
+ size_t read_bytes;
+ const int rlret = read_from_list(
+ &lrstate, msgpack_unpacker_buffer(unpacker), IOSIZE, &read_bytes);
+ if (rlret == FAIL) {
+ EMSG2(_(e_invarg2), "List item is not a string");
+ goto f_msgpackparse_exit;
+ }
+ msgpack_unpacker_buffer_consumed(unpacker, read_bytes);
+ if (read_bytes == 0) {
+ break;
+ }
+ while (unpacker->off < unpacker->used) {
+ const msgpack_unpack_return result = msgpack_unpacker_next(unpacker,
+ &unpacked);
+ if (result == MSGPACK_UNPACK_PARSE_ERROR) {
+ EMSG2(_(e_invarg2), "Failed to parse msgpack string");
+ goto f_msgpackparse_exit;
+ }
+ if (result == MSGPACK_UNPACK_NOMEM_ERROR) {
+ EMSG(_(e_outofmem));
+ goto f_msgpackparse_exit;
+ }
+ if (result == MSGPACK_UNPACK_SUCCESS) {
+ listitem_T *li = listitem_alloc();
+ li->li_tv.v_type = VAR_UNKNOWN;
+ list_append(ret_list, li);
+ if (msgpack_to_vim(unpacked.data, &li->li_tv) == FAIL) {
+ EMSG2(_(e_invarg2), "Failed to convert msgpack string");
+ goto f_msgpackparse_exit;
+ }
+ }
+ if (result == MSGPACK_UNPACK_CONTINUE) {
+ if (rlret == OK) {
+ EMSG2(_(e_invarg2), "Incomplete msgpack string");
+ }
+ break;
+ }
+ }
+ if (rlret == OK) {
+ break;
+ }
+ } while (true);
+
+f_msgpackparse_exit:
+ msgpack_unpacked_destroy(&unpacked);
+ msgpack_unpacker_free(unpacker);
+ return;
+}
/*
* "nextnonblank()" function
@@ -12420,7 +13286,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv)
#endif
p = get_tv_string(&argvars[0]);
-#ifdef FEAT_SHORTCUT
+#ifdef WIN32
{
char_u *v = NULL;
@@ -12756,13 +13622,7 @@ theend:
*/
static void f_round(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = round(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &round);
}
// "rpcnotify()" function
@@ -12940,7 +13800,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv)
// The last item of argv must be NULL
argv[i] = NULL;
- uint64_t channel_id = channel_from_job(argv);
+ uint64_t channel_id = channel_from_process(argv);
if (!channel_id) {
EMSG(_(e_api_spawn_failed));
@@ -13893,13 +14753,7 @@ static void f_simplify(typval_T *argvars, typval_T *rettv)
*/
static void f_sin(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = sin(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &sin);
}
/*
@@ -13907,13 +14761,7 @@ static void f_sin(typval_T *argvars, typval_T *rettv)
*/
static void f_sinh(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = sinh(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &sinh);
}
/// struct used in the array that's given to qsort()
@@ -14384,13 +15232,7 @@ static void f_split(typval_T *argvars, typval_T *rettv)
*/
static void f_sqrt(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = sqrt(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &sqrt);
}
/*
@@ -14763,6 +15605,8 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv)
modec = TOLOWER_ASC(mode[0]);
if (modec != 'c' && modec != 'g')
modec = 0; /* replace invalid with current */
+ } else if (ui_rgb_attached()) {
+ modec = 'g';
} else {
modec = 'c';
}
@@ -15214,19 +16058,15 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
}
}
- JobOptions opts = common_job_options(argv, on_stdout, on_stderr, on_exit,
- job_opts);
- opts.pty = true;
- opts.width = curwin->w_width;
- opts.height = curwin->w_height;
- opts.term_name = xstrdup("xterm-256color");
- Job *job = common_job_start(opts, rettv);
- if (!job) {
- shell_free_argv(argv);
+ TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
+ job_opts, true);
+ data->proc.pty.width = curwin->w_width;
+ data->proc.pty.height = curwin->w_height;
+ data->proc.pty.term_name = xstrdup("xterm-256color");
+ if (!common_job_start(data, rettv)) {
return;
}
- TerminalJobData *data = opts.data;
- TerminalOptions topts = TERMINAL_OPTIONS_INIT;
+ TerminalOptions topts;
topts.data = data;
topts.width = curwin->w_width;
topts.height = curwin->w_height;
@@ -15239,7 +16079,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
&& os_isdir(argvars[1].vval.v_string)) {
cwd = (char *)argvars[1].vval.v_string;
}
- int pid = job_pid(job);
+ int pid = data->proc.pty.process.pid;
// Get the desired name of the buffer.
char *name = job_opts ?
@@ -15278,13 +16118,7 @@ static void f_test(typval_T *argvars, typval_T *rettv)
*/
static void f_tan(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = tan(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &tan);
}
/*
@@ -15292,13 +16126,7 @@ static void f_tan(typval_T *argvars, typval_T *rettv)
*/
static void f_tanh(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- rettv->vval.v_float = tanh(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &tanh);
}
/*
@@ -15446,14 +16274,7 @@ error:
*/
static void f_trunc(typval_T *argvars, typval_T *rettv)
{
- float_T f;
-
- rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK)
- /* trunc() is not in C90, use floor() or ceil() instead. */
- rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
- else
- rettv->vval.v_float = 0.0;
+ float_op_wrapper(argvars, rettv, &trunc);
}
/*
@@ -20211,21 +21032,31 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags)
return ret;
}
-static inline JobOptions common_job_options(char **argv, ufunc_T *on_stdout,
- ufunc_T *on_stderr, ufunc_T *on_exit, dict_T *self)
+static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout,
+ ufunc_T *on_stderr, ufunc_T *on_exit, dict_T *self, bool pty)
{
TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));
+ data->stopped = false;
data->on_stdout = on_stdout;
data->on_stderr = on_stderr;
data->on_exit = on_exit;
data->self = self;
- JobOptions opts = JOB_OPTIONS_INIT;
- opts.argv = argv;
- opts.data = data;
- opts.stdout_cb = on_job_stdout;
- opts.stderr_cb = on_job_stderr;
- opts.exit_cb = on_job_exit;
- return opts;
+ data->events = queue_new_child(loop.events);
+ if (pty) {
+ data->proc.pty = pty_process_init(&loop, data);
+ } else {
+ data->proc.uv = uv_process_init(&loop, data);
+ }
+ Process *proc = (Process *)&data->proc;
+ proc->argv = argv;
+ proc->in = &data->in;
+ proc->out = &data->out;
+ if (!pty) {
+ proc->err = &data->err;
+ }
+ proc->cb = on_process_exit;
+ proc->events = data->events;
+ return data;
}
/// Return true/false on success/failure.
@@ -20251,27 +21082,37 @@ static inline bool common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout,
return false;
}
-static inline Job *common_job_start(JobOptions opts, typval_T *rettv)
+static inline bool common_job_start(TerminalJobData *data, typval_T *rettv)
{
- TerminalJobData *data = opts.data;
data->refcount++;
- Job *job = job_start(opts, &rettv->vval.v_number);
-
- if (rettv->vval.v_number <= 0) {
- if (rettv->vval.v_number == 0) {
- EMSG(_(e_jobtblfull));
- xfree(opts.term_name);
+ Process *proc = (Process *)&data->proc;
+ if (!process_spawn(proc)) {
+ EMSG(_(e_jobexe));
+ if (proc->type == kProcessTypePty) {
+ xfree(data->proc.pty.term_name);
free_term_job_data(data);
- } else {
- EMSG(_(e_jobexe));
}
- return NULL;
+ return false;
}
- data->job = job;
- return job;
+
+ data->id = current_job_id++;
+ wstream_init(proc->in, 0);
+ if (proc->out) {
+ rstream_init(proc->out, 0);
+ rstream_start(proc->out, on_job_stdout);
+ }
+ if (proc->err) {
+ rstream_init(proc->err, 0);
+ rstream_start(proc->err, on_job_stderr);
+ }
+ pmap_put(uint64_t)(jobs, data->id, data);
+ rettv->vval.v_number = data->id;
+ return true;
}
-static inline void free_term_job_data(TerminalJobData *data) {
+static inline void free_term_job_data_event(void **argv)
+{
+ TerminalJobData *data = argv[0];
if (data->on_stdout) {
user_func_unref(data->on_stdout);
}
@@ -20286,35 +21127,33 @@ static inline void free_term_job_data(TerminalJobData *data) {
data->self->internal_refcount--;
dict_unref(data->self);
}
+ queue_free(data->events);
xfree(data);
}
-static inline bool is_user_job(Job *job)
+static inline void free_term_job_data(TerminalJobData *data)
{
- if (!job) {
- return false;
- }
-
- JobOptions *opts = job_opts(job);
- return opts->exit_cb == on_job_exit;
+ // data->queue may still be used after this function returns(process_wait), so
+ // only free in the next event loop iteration
+ queue_put(loop.fast_events, free_term_job_data_event, 1, data);
}
// vimscript job callbacks must be executed on Nvim main loop
-static inline void push_job_event(Job *job, ufunc_T *callback,
- const char *type, char *data, size_t count, int status)
-{
- JobEvent *event_data = xmalloc(sizeof(JobEvent));
- event_data->received = NULL;
- if (data) {
- event_data->received = list_alloc();
- char *ptr = data;
+static inline void process_job_event(TerminalJobData *data, ufunc_T *callback,
+ const char *type, char *buf, size_t count, int status)
+{
+ JobEvent event_data;
+ event_data.received = NULL;
+ if (buf) {
+ event_data.received = list_alloc();
+ char *ptr = buf;
size_t remaining = count;
size_t off = 0;
while (off < remaining) {
// append the line
if (ptr[off] == NL) {
- list_append_string(event_data->received, (uint8_t *)ptr, off);
+ list_append_string(event_data.received, (uint8_t *)ptr, off);
size_t skip = off + 1;
ptr += skip;
remaining -= skip;
@@ -20327,59 +21166,58 @@ static inline void push_job_event(Job *job, ufunc_T *callback,
}
off++;
}
- list_append_string(event_data->received, (uint8_t *)ptr, off);
+ list_append_string(event_data.received, (uint8_t *)ptr, off);
} else {
- event_data->status = status;
+ event_data.status = status;
}
- event_data->job_id = job_id(job);
- event_data->data = job_data(job);
- event_data->callback = callback;
- event_data->type = type;
- event_push((Event) {
- .handler = on_job_event,
- .data = event_data
- }, !disable_job_defer);
+ event_data.data = data;
+ event_data.callback = callback;
+ event_data.type = type;
+ on_job_event(&event_data);
}
-static void on_job_stdout(RStream *rstream, RBuffer *buf, void *job, bool eof)
+static void on_job_stdout(Stream *stream, RBuffer *buf, size_t count,
+ void *job, bool eof)
{
- TerminalJobData *data = job_data(job);
- on_job_output(rstream, job, buf, eof, data->on_stdout, "stdout");
+ TerminalJobData *data = job;
+ on_job_output(stream, job, buf, count, eof, data->on_stdout, "stdout");
}
-static void on_job_stderr(RStream *rstream, RBuffer *buf, void *job, bool eof)
+static void on_job_stderr(Stream *stream, RBuffer *buf, size_t count,
+ void *job, bool eof)
{
- TerminalJobData *data = job_data(job);
- on_job_output(rstream, job, buf, eof, data->on_stderr, "stderr");
+ TerminalJobData *data = job;
+ on_job_output(stream, job, buf, count, eof, data->on_stderr, "stderr");
}
-static void on_job_output(RStream *rstream, Job *job, RBuffer *buf, bool eof,
- ufunc_T *callback, const char *type)
+static void on_job_output(Stream *stream, TerminalJobData *data, RBuffer *buf,
+ size_t count, bool eof, ufunc_T *callback, const char *type)
{
if (eof) {
return;
}
- TerminalJobData *data = job_data(job);
- RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
- // The order here matters, the terminal must receive the data first because
- // push_job_event will modify the read buffer(convert NULs into NLs)
- if (data->term) {
- terminal_receive(data->term, ptr, len);
- }
+ // stub variable, to keep reading consistent with the order of events, only
+ // consider the count parameter.
+ size_t r;
+ char *ptr = rbuffer_read_ptr(buf, &r);
- if (callback) {
- push_job_event(job, callback, type, ptr, len, 0);
- }
+ // The order here matters, the terminal must receive the data first because
+ // process_job_event will modify the read buffer(convert NULs into NLs)
+ if (data->term) {
+ terminal_receive(data->term, ptr, count);
+ }
- rbuffer_consumed(buf, len);
+ if (callback) {
+ process_job_event(data, callback, type, ptr, count, 0);
}
+
+ rbuffer_consumed(buf, count);
}
-static void on_job_exit(Job *job, int status, void *d)
+static void on_process_exit(Process *proc, int status, void *d)
{
TerminalJobData *data = d;
-
if (data->term && !data->exited) {
data->exited = true;
terminal_close(data->term,
@@ -20390,19 +21228,20 @@ static void on_job_exit(Job *job, int status, void *d)
*data->status_ptr = status;
}
- push_job_event(job, data->on_exit, "exit", NULL, 0, status);
+ process_job_event(data, data->on_exit, "exit", NULL, 0, status);
}
-static void term_write(char *buf, size_t size, void *data)
+static void term_write(char *buf, size_t size, void *d)
{
- Job *job = ((TerminalJobData *)data)->job;
+ TerminalJobData *data = d;
WBuffer *wbuf = wstream_new_buffer(xmemdup(buf, size), size, 1, xfree);
- job_write(job, wbuf);
+ wstream_write(&data->in, wbuf);
}
-static void term_resize(uint16_t width, uint16_t height, void *data)
+static void term_resize(uint16_t width, uint16_t height, void *d)
{
- job_resize(((TerminalJobData *)data)->job, width, height);
+ TerminalJobData *data = d;
+ pty_process_resize(&data->proc.pty, width, height);
}
static void term_close(void *d)
@@ -20410,7 +21249,7 @@ static void term_close(void *d)
TerminalJobData *data = d;
if (!data->exited) {
data->exited = true;
- job_stop(data->job);
+ process_stop((Process *)&data->proc);
}
terminal_destroy(data->term);
term_job_data_decref(d);
@@ -20423,10 +21262,8 @@ static void term_job_data_decref(TerminalJobData *data)
}
}
-static void on_job_event(Event event)
+static void on_job_event(JobEvent *ev)
{
- JobEvent *ev = event.data;
-
if (!ev->callback) {
goto end;
}
@@ -20437,7 +21274,7 @@ static void on_job_event(Event event)
if (argc > 0) {
argv[0].v_type = VAR_NUMBER;
argv[0].v_lock = 0;
- argv[0].vval.v_number = ev->job_id;
+ argv[0].vval.v_number = ev->data->id;
}
if (argc > 1) {
@@ -20468,9 +21305,18 @@ static void on_job_event(Event event)
end:
if (!ev->received) {
// exit event, safe to free job data now
+ pmap_del(uint64_t)(jobs, ev->data->id);
term_job_data_decref(ev->data);
}
- xfree(ev);
+}
+
+static TerminalJobData *find_job(uint64_t id)
+{
+ TerminalJobData *data = pmap_get(uint64_t)(jobs, id);
+ if (!data || data->stopped) {
+ return NULL;
+ }
+ return data;
}
static void script_host_eval(char *name, typval_T *argvars, typval_T *rettv)
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index 75e3b247f3..8f065eda33 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -65,9 +65,13 @@ enum {
VV_PROGPATH,
VV_COMMAND_OUTPUT,
VV_COMPLETED_ITEM,
+ VV_MSGPACK_TYPES,
VV_LEN, /* number of v: vars */
};
+/// Maximum number of function arguments
+#define MAX_FUNC_ARGS 20
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval.h.generated.h"
#endif
diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h
index 34a36004d6..0faf860588 100644
--- a/src/nvim/eval_defs.h
+++ b/src/nvim/eval_defs.h
@@ -1,11 +1,16 @@
#ifndef NVIM_EVAL_DEFS_H
#define NVIM_EVAL_DEFS_H
+#include <limits.h>
+
#include "nvim/hashtab.h"
typedef int varnumber_T;
typedef double float_T;
+#define VARNUMBER_MAX INT_MAX
+#define VARNUMBER_MIN INT_MIN
+
typedef struct listvar_S list_T;
typedef struct dictvar_S dict_T;
diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h
new file mode 100644
index 0000000000..5126d52241
--- /dev/null
+++ b/src/nvim/event/defs.h
@@ -0,0 +1,39 @@
+#ifndef NVIM_EVENT_DEFS_H
+#define NVIM_EVENT_DEFS_H
+
+#include <assert.h>
+#include <stdarg.h>
+
+#define EVENT_HANDLER_MAX_ARGC 4
+
+typedef void (*argv_callback)(void **argv);
+typedef struct message {
+ int priority;
+ argv_callback handler;
+ void *argv[EVENT_HANDLER_MAX_ARGC];
+} Event;
+
+#define VA_EVENT_INIT(event, p, h, a) \
+ do { \
+ assert(a <= EVENT_HANDLER_MAX_ARGC); \
+ (event)->priority = p; \
+ (event)->handler = h; \
+ if (a) { \
+ va_list args; \
+ va_start(args, a); \
+ for (int i = 0; i < a; i++) { \
+ (event)->argv[i] = va_arg(args, void *); \
+ } \
+ va_end(args); \
+ } \
+ } while (0)
+
+static inline Event event_create(int priority, argv_callback cb, int argc, ...)
+{
+ assert(argc <= EVENT_HANDLER_MAX_ARGC);
+ Event event;
+ VA_EVENT_INIT(&event, priority, cb, argc);
+ return event;
+}
+
+#endif // NVIM_EVENT_DEFS_H
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
new file mode 100644
index 0000000000..3d3288f858
--- /dev/null
+++ b/src/nvim/event/loop.c
@@ -0,0 +1,85 @@
+#include <stdarg.h>
+#include <stdint.h>
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/process.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/loop.c.generated.h"
+#endif
+
+typedef struct idle_event {
+ uv_idle_t idle;
+ Event event;
+} IdleEvent;
+
+
+void loop_init(Loop *loop, void *data)
+{
+ uv_loop_init(&loop->uv);
+ loop->uv.data = loop;
+ loop->children = kl_init(WatcherPtr);
+ loop->children_stop_requests = 0;
+ loop->events = queue_new_parent(loop_on_put, loop);
+ loop->fast_events = queue_new_child(loop->events);
+ uv_signal_init(&loop->uv, &loop->children_watcher);
+ uv_timer_init(&loop->uv, &loop->children_kill_timer);
+ uv_timer_init(&loop->uv, &loop->poll_timer);
+}
+
+void loop_poll_events(Loop *loop, int ms)
+{
+ static int recursive = 0;
+
+ if (recursive++) {
+ abort(); // Should not re-enter uv_run
+ }
+
+ uv_run_mode mode = UV_RUN_ONCE;
+
+ if (ms > 0) {
+ // Use a repeating timeout of ms milliseconds to make sure
+ // we do not block indefinitely for I/O.
+ uv_timer_start(&loop->poll_timer, timer_cb, (uint64_t)ms, (uint64_t)ms);
+ } else if (ms == 0) {
+ // For ms == 0, we need to do a non-blocking event poll by
+ // setting the run mode to UV_RUN_NOWAIT.
+ mode = UV_RUN_NOWAIT;
+ }
+
+ uv_run(&loop->uv, mode);
+
+ if (ms > 0) {
+ uv_timer_stop(&loop->poll_timer);
+ }
+
+ recursive--; // Can re-enter uv_run now
+ queue_process_events(loop->fast_events);
+}
+
+void loop_on_put(Queue *queue, void *data)
+{
+ Loop *loop = data;
+ // Sometimes libuv will run pending callbacks(timer for example) before
+ // blocking for a poll. If this happens and the callback pushes a event to one
+ // of the queues, the event would only be processed after the poll
+ // returns(user hits a key for example). To avoid this scenario, we call
+ // uv_stop when a event is enqueued.
+ uv_stop(&loop->uv);
+}
+
+void loop_close(Loop *loop)
+{
+ uv_close((uv_handle_t *)&loop->children_watcher, NULL);
+ uv_close((uv_handle_t *)&loop->children_kill_timer, NULL);
+ uv_close((uv_handle_t *)&loop->poll_timer, NULL);
+ do {
+ uv_run(&loop->uv, UV_RUN_DEFAULT);
+ } while (uv_loop_close(&loop->uv));
+}
+
+static void timer_cb(uv_timer_t *handle)
+{
+}
diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h
new file mode 100644
index 0000000000..9212a45aa4
--- /dev/null
+++ b/src/nvim/event/loop.h
@@ -0,0 +1,70 @@
+#ifndef NVIM_EVENT_LOOP_H
+#define NVIM_EVENT_LOOP_H
+
+#include <stdint.h>
+
+#include <uv.h>
+
+#include "nvim/lib/klist.h"
+#include "nvim/os/time.h"
+#include "nvim/event/queue.h"
+
+typedef void * WatcherPtr;
+
+#define _noop(x)
+KLIST_INIT(WatcherPtr, WatcherPtr, _noop)
+
+typedef struct loop {
+ uv_loop_t uv;
+ Queue *events, *fast_events;
+ klist_t(WatcherPtr) *children;
+ uv_signal_t children_watcher;
+ uv_timer_t children_kill_timer, poll_timer;
+ size_t children_stop_requests;
+} Loop;
+
+#define CREATE_EVENT(queue, handler, argc, ...) \
+ do { \
+ if (queue) { \
+ queue_put((queue), (handler), argc, __VA_ARGS__); \
+ } else { \
+ void *argv[argc] = {__VA_ARGS__}; \
+ (handler)(argv); \
+ } \
+ } while (0)
+
+// Poll for events until a condition or timeout
+#define LOOP_PROCESS_EVENTS_UNTIL(loop, queue, timeout, condition) \
+ do { \
+ int remaining = timeout; \
+ uint64_t before = (remaining > 0) ? os_hrtime() : 0; \
+ while (!(condition)) { \
+ LOOP_PROCESS_EVENTS(loop, queue, remaining); \
+ if (remaining == 0) { \
+ break; \
+ } else if (remaining > 0) { \
+ uint64_t now = os_hrtime(); \
+ remaining -= (int) ((now - before) / 1000000); \
+ before = now; \
+ if (remaining <= 0) { \
+ break; \
+ } \
+ } \
+ } \
+ } while (0)
+
+#define LOOP_PROCESS_EVENTS(loop, queue, timeout) \
+ do { \
+ if (queue && !queue_empty(queue)) { \
+ queue_process_events(queue); \
+ } else { \
+ loop_poll_events(loop, timeout); \
+ } \
+ } while (0)
+
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/loop.h.generated.h"
+#endif
+
+#endif // NVIM_EVENT_LOOP_H
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
new file mode 100644
index 0000000000..81d4e690c3
--- /dev/null
+++ b/src/nvim/event/process.c
@@ -0,0 +1,343 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#include <uv.h>
+
+#include "nvim/os/shell.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
+#include "nvim/event/process.h"
+#include "nvim/event/uv_process.h"
+#include "nvim/event/pty_process.h"
+#include "nvim/globals.h"
+#include "nvim/log.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/process.c.generated.h"
+#endif
+
+// {SIGNAL}_TIMEOUT is the time (in nanoseconds) that a process has to cleanly
+// exit before we send SIGNAL to it
+#define TERM_TIMEOUT 1000000000
+#define KILL_TIMEOUT (TERM_TIMEOUT * 2)
+
+#define CLOSE_PROC_STREAM(proc, stream) \
+ do { \
+ if (proc->stream && !proc->stream->closed) { \
+ stream_close(proc->stream, NULL); \
+ } \
+ } while (0)
+
+
+bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
+{
+ if (proc->in) {
+ uv_pipe_init(&proc->loop->uv, &proc->in->uv.pipe, 0);
+ }
+
+ if (proc->out) {
+ uv_pipe_init(&proc->loop->uv, &proc->out->uv.pipe, 0);
+ }
+
+ if (proc->err) {
+ uv_pipe_init(&proc->loop->uv, &proc->err->uv.pipe, 0);
+ }
+
+ bool success;
+ switch (proc->type) {
+ case kProcessTypeUv:
+ success = uv_process_spawn((UvProcess *)proc);
+ break;
+ case kProcessTypePty:
+ success = pty_process_spawn((PtyProcess *)proc);
+ break;
+ default:
+ abort();
+ }
+
+ if (!success) {
+ if (proc->in) {
+ uv_close((uv_handle_t *)&proc->in->uv.pipe, NULL);
+ }
+ if (proc->out) {
+ uv_close((uv_handle_t *)&proc->out->uv.pipe, NULL);
+ }
+ if (proc->err) {
+ uv_close((uv_handle_t *)&proc->err->uv.pipe, NULL);
+ }
+ process_close(proc);
+ shell_free_argv(proc->argv);
+ proc->status = -1;
+ return false;
+ }
+
+ void *data = proc->data;
+
+ if (proc->in) {
+ stream_init(NULL, proc->in, -1, (uv_stream_t *)&proc->in->uv.pipe, data);
+ proc->in->events = proc->events;
+ proc->in->internal_data = proc;
+ proc->in->internal_close_cb = on_process_stream_close;
+ proc->refcount++;
+ }
+
+ if (proc->out) {
+ stream_init(NULL, proc->out, -1, (uv_stream_t *)&proc->out->uv.pipe, data);
+ proc->out->events = proc->events;
+ proc->out->internal_data = proc;
+ proc->out->internal_close_cb = on_process_stream_close;
+ proc->refcount++;
+ }
+
+ if (proc->err) {
+ stream_init(NULL, proc->err, -1, (uv_stream_t *)&proc->err->uv.pipe, data);
+ proc->err->events = proc->events;
+ proc->err->internal_data = proc;
+ proc->err->internal_close_cb = on_process_stream_close;
+ proc->refcount++;
+ }
+
+ proc->internal_exit_cb = on_process_exit;
+ proc->internal_close_cb = decref;
+ proc->refcount++;
+ kl_push(WatcherPtr, proc->loop->children, proc);
+ return true;
+}
+
+void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
+{
+ kl_iter(WatcherPtr, loop->children, current) {
+ Process *proc = (*current)->data;
+ uv_kill(proc->pid, SIGTERM);
+ proc->term_sent = true;
+ process_stop(proc);
+ }
+
+ // Wait until all children exit
+ LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1, kl_empty(loop->children));
+ pty_process_teardown(loop);
+}
+
+// Wrappers around `stream_close` that protect against double-closing.
+void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL
+{
+ process_close_in(proc);
+ process_close_out(proc);
+ process_close_err(proc);
+}
+
+void process_close_in(Process *proc) FUNC_ATTR_NONNULL_ALL
+{
+ CLOSE_PROC_STREAM(proc, in);
+}
+
+void process_close_out(Process *proc) FUNC_ATTR_NONNULL_ALL
+{
+ CLOSE_PROC_STREAM(proc, out);
+}
+
+void process_close_err(Process *proc) FUNC_ATTR_NONNULL_ALL
+{
+ CLOSE_PROC_STREAM(proc, err);
+}
+
+/// Synchronously wait for a process to finish
+///
+/// @param process The Process instance
+/// @param ms Number of milliseconds to wait, 0 for not waiting, -1 for
+/// waiting until the process quits.
+/// @return returns the status code of the exited process. -1 if the process is
+/// still running and the `timeout` has expired. Note that this is
+/// indistinguishable from the process returning -1 by itself. Which
+/// is possible on some OS. Returns -2 if an user has interruped the
+/// wait.
+int process_wait(Process *proc, int ms, Queue *events) FUNC_ATTR_NONNULL_ARG(1)
+{
+ // The default status is -1, which represents a timeout
+ int status = -1;
+ bool interrupted = false;
+ if (!proc->refcount) {
+ LOOP_PROCESS_EVENTS(proc->loop, proc->events, 0);
+ return proc->status;
+ }
+
+ if (!events) {
+ events = proc->events;
+ }
+
+ // Increase refcount to stop the exit callback from being called(and possibly
+ // being freed) before we have a chance to get the status.
+ proc->refcount++;
+ LOOP_PROCESS_EVENTS_UNTIL(proc->loop, events, ms,
+ // Until...
+ got_int || // interrupted by the user
+ proc->refcount == 1); // job exited
+
+ // we'll assume that a user frantically hitting interrupt doesn't like
+ // the current job. Signal that it has to be killed.
+ if (got_int) {
+ interrupted = true;
+ got_int = false;
+ process_stop(proc);
+ if (ms == -1) {
+ // We can only return if all streams/handles are closed and the job
+ // exited.
+ LOOP_PROCESS_EVENTS_UNTIL(proc->loop, events, -1,
+ proc->refcount == 1);
+ } else {
+ LOOP_PROCESS_EVENTS(proc->loop, events, 0);
+ }
+ }
+
+ if (proc->refcount == 1) {
+ // Job exited, collect status and manually invoke close_cb to free the job
+ // resources
+ status = interrupted ? -2 : proc->status;
+ decref(proc);
+ if (events) {
+ // the decref call created an exit event, process it now
+ queue_process_events(events);
+ }
+ } else {
+ proc->refcount--;
+ }
+
+ return status;
+}
+
+/// Ask a process to terminate and eventually kill if it doesn't respond
+void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
+{
+ if (proc->stopped_time) {
+ return;
+ }
+
+ proc->stopped_time = os_hrtime();
+ switch (proc->type) {
+ case kProcessTypeUv:
+ // Close the process's stdin. If the process doesn't close its own
+ // stdout/stderr, they will be closed when it exits(possibly due to being
+ // terminated after a timeout)
+ process_close_in(proc);
+ break;
+ case kProcessTypePty:
+ // close all streams for pty processes to send SIGHUP to the process
+ process_close_streams(proc);
+ pty_process_close_master((PtyProcess *)proc);
+ break;
+ default:
+ abort();
+ }
+
+ Loop *loop = proc->loop;
+ if (!loop->children_stop_requests++) {
+ // When there's at least one stop request pending, start a timer that
+ // will periodically check if a signal should be send to a to the job
+ DLOG("Starting job kill timer");
+ uv_timer_start(&loop->children_kill_timer, children_kill_cb, 100, 100);
+ }
+}
+
+/// Iterates the process list sending SIGTERM to stopped processes and SIGKILL
+/// to those that didn't die from SIGTERM after a while(exit_timeout is 0).
+static void children_kill_cb(uv_timer_t *handle)
+{
+ Loop *loop = handle->loop->data;
+ uint64_t now = os_hrtime();
+
+ kl_iter(WatcherPtr, loop->children, current) {
+ Process *proc = (*current)->data;
+ if (!proc->stopped_time) {
+ continue;
+ }
+ uint64_t elapsed = now - proc->stopped_time;
+
+ if (!proc->term_sent && elapsed >= TERM_TIMEOUT) {
+ ILOG("Sending SIGTERM to pid %d", proc->pid);
+ uv_kill(proc->pid, SIGTERM);
+ proc->term_sent = true;
+ } else if (elapsed >= KILL_TIMEOUT) {
+ ILOG("Sending SIGKILL to pid %d", proc->pid);
+ uv_kill(proc->pid, SIGKILL);
+ }
+ }
+}
+
+static void process_close_event(void **argv)
+{
+ Process *proc = argv[0];
+ shell_free_argv(proc->argv);
+ if (proc->type == kProcessTypePty) {
+ xfree(((PtyProcess *)proc)->term_name);
+ }
+ if (proc->cb) {
+ proc->cb(proc, proc->status, proc->data);
+ }
+}
+
+static void decref(Process *proc)
+{
+ if (--proc->refcount != 0) {
+ return;
+ }
+
+ Loop *loop = proc->loop;
+ kliter_t(WatcherPtr) **node = NULL;
+ kl_iter(WatcherPtr, loop->children, current) {
+ if ((*current)->data == proc) {
+ node = current;
+ break;
+ }
+ }
+ assert(node);
+ kl_shift_at(WatcherPtr, loop->children, node);
+ CREATE_EVENT(proc->events, process_close_event, 1, proc);
+}
+
+static void process_close(Process *proc)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ assert(!proc->closed);
+ proc->closed = true;
+ switch (proc->type) {
+ case kProcessTypeUv:
+ uv_process_close((UvProcess *)proc);
+ break;
+ case kProcessTypePty:
+ pty_process_close((PtyProcess *)proc);
+ break;
+ default:
+ abort();
+ }
+}
+
+static void process_close_handles(void **argv)
+{
+ Process *proc = argv[0];
+ process_close_streams(proc);
+ process_close(proc);
+}
+
+static void on_process_exit(Process *proc)
+{
+ Loop *loop = proc->loop;
+ if (proc->stopped_time && loop->children_stop_requests
+ && !--loop->children_stop_requests) {
+ // Stop the timer if no more stop requests are pending
+ DLOG("Stopping process kill timer");
+ uv_timer_stop(&loop->children_kill_timer);
+ }
+ // Process handles are closed in the next event loop tick. This is done to
+ // give libuv more time to read data from the OS after the process exits(If
+ // process_close_streams is called with data still in the OS buffer, we lose
+ // it)
+ CREATE_EVENT(proc->events, process_close_handles, 1, proc);
+}
+
+static void on_process_stream_close(Stream *stream, void *data)
+{
+ Process *proc = data;
+ decref(proc);
+}
+
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
new file mode 100644
index 0000000000..45edc46b95
--- /dev/null
+++ b/src/nvim/event/process.h
@@ -0,0 +1,58 @@
+#ifndef NVIM_EVENT_PROCESS_H
+#define NVIM_EVENT_PROCESS_H
+
+#include "nvim/event/loop.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
+
+typedef enum {
+ kProcessTypeUv,
+ kProcessTypePty
+} ProcessType;
+
+typedef struct process Process;
+typedef void (*process_exit_cb)(Process *proc, int status, void *data);
+typedef void (*internal_process_cb)(Process *proc);
+
+struct process {
+ ProcessType type;
+ Loop *loop;
+ void *data;
+ int pid, status, refcount;
+ // set to the hrtime of when process_stop was called for the process.
+ uint64_t stopped_time;
+ char **argv;
+ Stream *in, *out, *err;
+ process_exit_cb cb;
+ internal_process_cb internal_exit_cb, internal_close_cb;
+ bool closed, term_sent;
+ Queue *events;
+};
+
+static inline Process process_init(Loop *loop, ProcessType type, void *data)
+{
+ return (Process) {
+ .type = type,
+ .data = data,
+ .loop = loop,
+ .events = NULL,
+ .pid = 0,
+ .status = 0,
+ .refcount = 0,
+ .stopped_time = 0,
+ .argv = NULL,
+ .in = NULL,
+ .out = NULL,
+ .err = NULL,
+ .cb = NULL,
+ .closed = false,
+ .term_sent = false,
+ .internal_close_cb = NULL,
+ .internal_exit_cb = NULL
+ };
+}
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/process.h.generated.h"
+#endif
+#endif // NVIM_EVENT_PROCESS_H
diff --git a/src/nvim/os/pty_process.c b/src/nvim/event/pty_process.c
index ff0bcfb6de..8eef72f12f 100644
--- a/src/nvim/os/pty_process.c
+++ b/src/nvim/event/pty_process.c
@@ -20,92 +20,40 @@
#include <uv.h>
-#include "nvim/func_attr.h"
-#include "nvim/os/job.h"
-#include "nvim/os/job_defs.h"
-#include "nvim/os/job_private.h"
-#include "nvim/os/pty_process.h"
-#include "nvim/memory.h"
+#include "nvim/lib/klist.h"
+
+#include "nvim/event/loop.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
+#include "nvim/event/process.h"
+#include "nvim/event/pty_process.h"
+#include "nvim/log.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/pty_process.c.generated.h"
+# include "event/pty_process.c.generated.h"
#endif
-typedef struct {
- struct winsize winsize;
- uv_pipe_t proc_stdin, proc_stdout, proc_stderr;
- int tty_fd;
-} PtyProcess;
-
-void pty_process_init(Job *job) FUNC_ATTR_NONNULL_ALL
-{
- PtyProcess *ptyproc = xmalloc(sizeof(PtyProcess));
- ptyproc->tty_fd = -1;
-
- if (job->opts.writable) {
- uv_pipe_init(uv_default_loop(), &ptyproc->proc_stdin, 0);
- ptyproc->proc_stdin.data = NULL;
- }
-
- if (job->opts.stdout_cb) {
- uv_pipe_init(uv_default_loop(), &ptyproc->proc_stdout, 0);
- ptyproc->proc_stdout.data = NULL;
- }
-
- if (job->opts.stderr_cb) {
- uv_pipe_init(uv_default_loop(), &ptyproc->proc_stderr, 0);
- ptyproc->proc_stderr.data = NULL;
- }
-
- job->proc_stdin = (uv_stream_t *)&ptyproc->proc_stdin;
- job->proc_stdout = (uv_stream_t *)&ptyproc->proc_stdout;
- job->proc_stderr = (uv_stream_t *)&ptyproc->proc_stderr;
- job->process = ptyproc;
-}
-
-void pty_process_destroy(Job *job) FUNC_ATTR_NONNULL_ALL
-{
- xfree(job->opts.term_name);
- xfree(job->process);
- job->process = NULL;
-}
-
-static bool set_pipe_duplicating_descriptor(int fd, uv_pipe_t *pipe)
+bool pty_process_spawn(PtyProcess *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
- int fd_dup = dup(fd);
- if (fd_dup < 0) {
- ELOG("Failed to dup descriptor %d: %s", fd, strerror(errno));
- return false;
+ static struct termios termios;
+ if (!termios.c_cflag) {
+ init_termios(&termios);
}
- int uv_result = uv_pipe_open(pipe, fd_dup);
- if (uv_result) {
- ELOG("Failed to set pipe to descriptor %d: %s",
- fd_dup, uv_strerror(uv_result));
- close(fd_dup);
- return false;
- }
- return true;
-}
-static const unsigned int KILL_RETRIES = 5;
-static const unsigned int KILL_TIMEOUT = 2; // seconds
-
-bool pty_process_spawn(Job *job) FUNC_ATTR_NONNULL_ALL
-{
- int master;
- PtyProcess *ptyproc = job->process;
- ptyproc->winsize = (struct winsize){job->opts.height, job->opts.width, 0, 0};
- struct termios termios;
- init_termios(&termios);
+ Process *proc = (Process *)ptyproc;
+ assert(!proc->err);
+ uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD);
+ ptyproc->winsize = (struct winsize){ptyproc->height, ptyproc->width, 0, 0};
uv_disable_stdio_inheritance();
-
+ int master;
int pid = forkpty(&master, NULL, &termios, &ptyproc->winsize);
if (pid < 0) {
+ ELOG("forkpty failed: %s", strerror(errno));
return false;
} else if (pid == 0) {
- init_child(job);
+ init_child(ptyproc);
abort();
}
@@ -120,67 +68,56 @@ bool pty_process_spawn(Job *job) FUNC_ATTR_NONNULL_ALL
goto error;
}
- if (job->opts.writable
- && !set_pipe_duplicating_descriptor(master, &ptyproc->proc_stdin)) {
+ if (proc->in && !set_duplicating_descriptor(master, &proc->in->uv.pipe)) {
goto error;
}
-
- if (job->opts.stdout_cb
- && !set_pipe_duplicating_descriptor(master, &ptyproc->proc_stdout)) {
- goto error;
- }
-
- if (job->opts.stderr_cb
- && !set_pipe_duplicating_descriptor(master, &ptyproc->proc_stderr)) {
+ if (proc->out && !set_duplicating_descriptor(master, &proc->out->uv.pipe)) {
goto error;
}
ptyproc->tty_fd = master;
- job->pid = pid;
+ proc->pid = pid;
return true;
error:
close(master);
-
- // terminate spawned process
- kill(pid, SIGTERM);
- int status, child;
- unsigned int try = 0;
- while (try++ < KILL_RETRIES && !(child = waitpid(pid, &status, WNOHANG))) {
- sleep(KILL_TIMEOUT);
- }
- if (child != pid) {
- kill(pid, SIGKILL);
- }
-
+ kill(pid, SIGKILL);
+ waitpid(pid, NULL, 0);
return false;
}
-void pty_process_close(Job *job) FUNC_ATTR_NONNULL_ALL
+void pty_process_resize(PtyProcess *ptyproc, uint16_t width,
+ uint16_t height)
+ FUNC_ATTR_NONNULL_ALL
+{
+ ptyproc->winsize = (struct winsize){height, width, 0, 0};
+ ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize);
+}
+
+void pty_process_close(PtyProcess *ptyproc)
+ FUNC_ATTR_NONNULL_ALL
{
- pty_process_close_master(job);
- job_close_streams(job);
- job_decref(job);
+ pty_process_close_master(ptyproc);
+ Process *proc = (Process *)ptyproc;
+ if (proc->internal_close_cb) {
+ proc->internal_close_cb(proc);
+ }
}
-void pty_process_close_master(Job *job) FUNC_ATTR_NONNULL_ALL
+void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
{
- PtyProcess *ptyproc = job->process;
if (ptyproc->tty_fd >= 0) {
close(ptyproc->tty_fd);
ptyproc->tty_fd = -1;
}
}
-void pty_process_resize(Job *job, uint16_t width, uint16_t height)
- FUNC_ATTR_NONNULL_ALL
+void pty_process_teardown(Loop *loop)
{
- PtyProcess *ptyproc = job->process;
- ptyproc->winsize = (struct winsize){height, width, 0, 0};
- ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize);
+ uv_signal_stop(&loop->children_watcher);
}
-static void init_child(Job *job) FUNC_ATTR_NONNULL_ALL
+static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
{
unsetenv("COLUMNS");
unsetenv("LINES");
@@ -195,14 +132,13 @@ static void init_child(Job *job) FUNC_ATTR_NONNULL_ALL
signal(SIGTERM, SIG_DFL);
signal(SIGALRM, SIG_DFL);
- setenv("TERM", job->opts.term_name ? job->opts.term_name : "ansi", 1);
- execvp(job->opts.argv[0], job->opts.argv);
+ setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
+ execvp(ptyproc->process.argv[0], ptyproc->process.argv);
fprintf(stderr, "execvp failed: %s\n", strerror(errno));
}
static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL
{
- memset(termios, 0, sizeof(struct termios));
// Taken from pangoterm
termios->c_iflag = ICRNL|IXON;
termios->c_oflag = OPOST|ONLCR;
@@ -255,3 +191,50 @@ static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL
termios->c_cc[VMIN] = 1;
termios->c_cc[VTIME] = 0;
}
+
+static bool set_duplicating_descriptor(int fd, uv_pipe_t *pipe)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int fd_dup = dup(fd);
+ if (fd_dup < 0) {
+ ELOG("Failed to dup descriptor %d: %s", fd, strerror(errno));
+ return false;
+ }
+ int uv_result = uv_pipe_open(pipe, fd_dup);
+ if (uv_result) {
+ ELOG("Failed to set pipe to descriptor %d: %s",
+ fd_dup, uv_strerror(uv_result));
+ close(fd_dup);
+ return false;
+ }
+ return true;
+}
+
+static void chld_handler(uv_signal_t *handle, int signum)
+{
+ int stat = 0;
+ int pid;
+
+ do {
+ pid = waitpid(-1, &stat, WNOHANG);
+ } while (pid < 0 && errno == EINTR);
+
+ if (pid <= 0) {
+ return;
+ }
+
+ Loop *loop = handle->loop->data;
+
+ kl_iter(WatcherPtr, loop->children, current) {
+ Process *proc = (*current)->data;
+ if (proc->pid == pid) {
+ if (WIFEXITED(stat)) {
+ proc->status = WEXITSTATUS(stat);
+ } else if (WIFSIGNALED(stat)) {
+ proc->status = WTERMSIG(stat);
+ }
+ proc->internal_exit_cb(proc);
+ break;
+ }
+ }
+}
diff --git a/src/nvim/event/pty_process.h b/src/nvim/event/pty_process.h
new file mode 100644
index 0000000000..446d7fd3c8
--- /dev/null
+++ b/src/nvim/event/pty_process.h
@@ -0,0 +1,30 @@
+#ifndef NVIM_EVENT_PTY_PROCESS_H
+#define NVIM_EVENT_PTY_PROCESS_H
+
+#include <sys/ioctl.h>
+
+#include "nvim/event/process.h"
+
+typedef struct pty_process {
+ Process process;
+ char *term_name;
+ uint16_t width, height;
+ struct winsize winsize;
+ int tty_fd;
+} PtyProcess;
+
+static inline PtyProcess pty_process_init(Loop *loop, void *data)
+{
+ PtyProcess rv;
+ rv.process = process_init(loop, kProcessTypePty, data);
+ rv.term_name = NULL;
+ rv.width = 80;
+ rv.height = 24;
+ rv.tty_fd = -1;
+ return rv;
+}
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/pty_process.h.generated.h"
+#endif
+#endif // NVIM_EVENT_PTY_PROCESS_H
diff --git a/src/nvim/event/queue.c b/src/nvim/event/queue.c
new file mode 100644
index 0000000000..19eca14144
--- /dev/null
+++ b/src/nvim/event/queue.c
@@ -0,0 +1,208 @@
+// Queue for selective async event processing. Instances of this queue support a
+// parent/child relationship with the following properties:
+//
+// - pushing a node to a child queue will push a corresponding link node to the
+// parent queue
+// - removing a link node from a parent queue will remove the next node
+// in the linked child queue
+// - removing a node from a child queue will remove the corresponding link node
+// in the parent queue
+//
+// These properties allow neovim to organize and process events from different
+// sources with a certain degree of control. Here's how the queue is used:
+//
+// +----------------+
+// | Main loop |
+// +----------------+
+// ^
+// |
+// +----------------+
+// +-------------->| Event loop |<------------+
+// | +--+-------------+ |
+// | ^ ^ |
+// | | | |
+// +-----------+ +-----------+ +---------+ +---------+
+// | Channel 1 | | Channel 2 | | Job 1 | | Job 2 |
+// +-----------+ +-----------+ +---------+ +---------+
+//
+//
+// In the above diagram, the lower boxes represents event emitters, each with
+// it's own private queue that have the event loop queue as the parent.
+//
+// When idle, the main loop spins the event loop which queues events from many
+// sources(channels, jobs, user...). Each event emitter pushes events to its own
+// private queue which is propagated to the event loop queue. When the main loop
+// consumes an event, the corresponding event is removed from the emitter's
+// queue.
+//
+// The main reason for this queue hierarchy is to allow focusing on a single
+// event emitter while blocking the main loop. For example, if the `jobwait`
+// vimscript function is called on job1, the main loop will temporarily stop
+// polling the event loop queue and poll job1 queue instead. Same with channels,
+// when calling `rpcrequest`, we want to temporarily stop processing events from
+// other sources and focus on a specific channel.
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+
+#include <uv.h>
+
+#include "nvim/event/queue.h"
+#include "nvim/memory.h"
+#include "nvim/os/time.h"
+
+typedef struct queue_item QueueItem;
+struct queue_item {
+ union {
+ Queue *queue;
+ struct {
+ Event event;
+ QueueItem *parent;
+ } item;
+ } data;
+ bool link; // this is just a link to a node in a child queue
+ QUEUE node;
+};
+
+struct queue {
+ Queue *parent;
+ QUEUE headtail;
+ put_callback put_cb;
+ void *data;
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/queue.c.generated.h"
+#endif
+
+static Event NILEVENT = {.handler = NULL, .argv = {NULL}};
+
+Queue *queue_new_parent(put_callback put_cb, void *data)
+{
+ return queue_new(NULL, put_cb, data);
+}
+
+Queue *queue_new_child(Queue *parent)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(!parent->parent);
+ return queue_new(parent, NULL, NULL);
+}
+
+static Queue *queue_new(Queue *parent, put_callback put_cb, void *data)
+{
+ Queue *rv = xmalloc(sizeof(Queue));
+ QUEUE_INIT(&rv->headtail);
+ rv->parent = parent;
+ rv->put_cb = put_cb;
+ rv->data = data;
+ return rv;
+}
+
+void queue_free(Queue *queue)
+{
+ assert(queue);
+ if (queue->parent) {
+ while (!QUEUE_EMPTY(&queue->headtail)) {
+ QUEUE *q = QUEUE_HEAD(&queue->headtail);
+ QueueItem *item = queue_node_data(q);
+ assert(!item->link);
+ QUEUE_REMOVE(&item->data.item.parent->node);
+ xfree(item->data.item.parent);
+ QUEUE_REMOVE(q);
+ xfree(item);
+ }
+ }
+
+ xfree(queue);
+}
+
+Event queue_get(Queue *queue)
+{
+ return queue_empty(queue) ? NILEVENT : queue_remove(queue);
+}
+
+void queue_put_event(Queue *queue, Event event)
+{
+ assert(queue);
+ assert(queue->parent); // don't push directly to the parent queue
+ queue_push(queue, event);
+ if (queue->parent->put_cb) {
+ queue->parent->put_cb(queue->parent, queue->parent->data);
+ }
+}
+
+void queue_process_events(Queue *queue)
+{
+ assert(queue);
+ while (!queue_empty(queue)) {
+ Event event = queue_get(queue);
+ if (event.handler) {
+ event.handler(event.argv);
+ }
+ }
+}
+
+bool queue_empty(Queue *queue)
+{
+ assert(queue);
+ return QUEUE_EMPTY(&queue->headtail);
+}
+
+void queue_replace_parent(Queue *queue, Queue *new_parent)
+{
+ assert(queue_empty(queue));
+ queue->parent = new_parent;
+}
+
+static Event queue_remove(Queue *queue)
+{
+ assert(!queue_empty(queue));
+ QUEUE *h = QUEUE_HEAD(&queue->headtail);
+ QUEUE_REMOVE(h);
+ QueueItem *item = queue_node_data(h);
+ Event rv;
+
+ if (item->link) {
+ assert(!queue->parent);
+ // remove the next node in the linked queue
+ Queue *linked = item->data.queue;
+ assert(!queue_empty(linked));
+ QueueItem *child =
+ queue_node_data(QUEUE_HEAD(&linked->headtail));
+ QUEUE_REMOVE(&child->node);
+ rv = child->data.item.event;
+ xfree(child);
+ } else {
+ assert(queue->parent);
+ assert(!queue_empty(queue->parent));
+ // remove the corresponding link node in the parent queue
+ QUEUE_REMOVE(&item->data.item.parent->node);
+ xfree(item->data.item.parent);
+ rv = item->data.item.event;
+ }
+
+ xfree(item);
+ return rv;
+}
+
+static void queue_push(Queue *queue, Event event)
+{
+ QueueItem *item = xmalloc(sizeof(QueueItem));
+ item->link = false;
+ item->data.item.event = event;
+ QUEUE_INSERT_TAIL(&queue->headtail, &item->node);
+ // push link node to the parent queue
+ item->data.item.parent = xmalloc(sizeof(QueueItem));
+ item->data.item.parent->link = true;
+ item->data.item.parent->data.queue = queue;
+ QUEUE_INSERT_TAIL(&queue->parent->headtail, &item->data.item.parent->node);
+}
+
+static QueueItem *queue_node_data(QUEUE *q)
+{
+ return QUEUE_DATA(q, QueueItem, node);
+}
diff --git a/src/nvim/event/queue.h b/src/nvim/event/queue.h
new file mode 100644
index 0000000000..85fc59f8b2
--- /dev/null
+++ b/src/nvim/event/queue.h
@@ -0,0 +1,19 @@
+#ifndef NVIM_EVENT_QUEUE_H
+#define NVIM_EVENT_QUEUE_H
+
+#include <uv.h>
+
+#include "nvim/event/defs.h"
+#include "nvim/lib/queue.h"
+
+typedef struct queue Queue;
+typedef void (*put_callback)(Queue *queue, void *data);
+
+#define queue_put(q, h, ...) \
+ queue_put_event(q, event_create(1, h, __VA_ARGS__));
+
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/queue.h.generated.h"
+#endif
+#endif // NVIM_EVENT_QUEUE_H
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
new file mode 100644
index 0000000000..9f3fbc25ff
--- /dev/null
+++ b/src/nvim/event/rstream.c
@@ -0,0 +1,201 @@
+#include <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <uv.h>
+
+#include "nvim/event/rstream.h"
+#include "nvim/ascii.h"
+#include "nvim/vim.h"
+#include "nvim/memory.h"
+#include "nvim/log.h"
+#include "nvim/misc1.h"
+#include "nvim/event/loop.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/rstream.c.generated.h"
+#endif
+
+void rstream_init_fd(Loop *loop, Stream *stream, int fd, size_t bufsize,
+ void *data)
+ FUNC_ATTR_NONNULL_ARG(1)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ stream_init(loop, stream, fd, NULL, data);
+ rstream_init(stream, bufsize);
+}
+
+void rstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t bufsize,
+ void *data)
+ FUNC_ATTR_NONNULL_ARG(1)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ stream_init(NULL, stream, -1, uvstream, data);
+ rstream_init(stream, bufsize);
+}
+
+void rstream_init(Stream *stream, size_t bufsize)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ stream->buffer = rbuffer_new(bufsize);
+ stream->buffer->data = stream;
+ stream->buffer->full_cb = on_rbuffer_full;
+ stream->buffer->nonfull_cb = on_rbuffer_nonfull;
+}
+
+
+/// Starts watching for events from a `Stream` instance.
+///
+/// @param stream The `Stream` instance
+void rstream_start(Stream *stream, stream_read_cb cb)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ stream->read_cb = cb;
+ if (stream->uvstream) {
+ uv_read_start(stream->uvstream, alloc_cb, read_cb);
+ } else {
+ uv_idle_start(&stream->uv.idle, fread_idle_cb);
+ }
+}
+
+/// Stops watching for events from a `Stream` instance.
+///
+/// @param stream The `Stream` instance
+void rstream_stop(Stream *stream)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (stream->uvstream) {
+ uv_read_stop(stream->uvstream);
+ } else {
+ uv_idle_stop(&stream->uv.idle);
+ }
+}
+
+static void on_rbuffer_full(RBuffer *buf, void *data)
+{
+ rstream_stop(data);
+}
+
+static void on_rbuffer_nonfull(RBuffer *buf, void *data)
+{
+ Stream *stream = data;
+ assert(stream->read_cb);
+ rstream_start(stream, stream->read_cb);
+}
+
+// Callbacks used by libuv
+
+// Called by libuv to allocate memory for reading.
+static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
+{
+ Stream *stream = handle->data;
+ buf->base = rbuffer_write_ptr(stream->buffer, &buf->len);
+}
+
+// Callback invoked by libuv after it copies the data into the buffer provided
+// by `alloc_cb`. This is also called on EOF or when `alloc_cb` returns a
+// 0-length buffer.
+static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
+{
+ Stream *stream = uvstream->data;
+
+ if (cnt <= 0) {
+ if (cnt != UV_ENOBUFS
+ // cnt == 0 means libuv asked for a buffer and decided it wasn't needed:
+ // http://docs.libuv.org/en/latest/stream.html#c.uv_read_start.
+ //
+ // We don't need to do anything with the RBuffer because the next call
+ // 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);
+ // Read error or EOF, either way stop the stream and invoke the callback
+ // with eof == true
+ uv_read_stop(uvstream);
+ invoke_read_cb(stream, 0, true);
+ }
+ return;
+ }
+
+ // at this point we're sure that cnt is positive, no error occurred
+ size_t nread = (size_t)cnt;
+ // Data was already written, so all we need is to update 'wpos' to reflect
+ // the space actually used in the buffer.
+ rbuffer_produced(stream->buffer, nread);
+ invoke_read_cb(stream, nread, false);
+}
+
+// Called by the by the 'idle' handle to emulate a reading event
+static void fread_idle_cb(uv_idle_t *handle)
+{
+ uv_fs_t req;
+ Stream *stream = handle->data;
+
+ stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &stream->uvbuf.len);
+
+ // the offset argument to uv_fs_read is int64_t, could someone really try
+ // to read more than 9 quintillion (9e18) bytes?
+ // upcast is meant to avoid tautological condition warning on 32 bits
+ uintmax_t fpos_intmax = stream->fpos;
+ if (fpos_intmax > INT64_MAX) {
+ ELOG("stream offset overflow");
+ preserve_exit();
+ }
+
+ // Synchronous read
+ uv_fs_read(
+ handle->loop,
+ &req,
+ stream->fd,
+ &stream->uvbuf,
+ 1,
+ (int64_t) stream->fpos,
+ NULL);
+
+ uv_fs_req_cleanup(&req);
+
+ if (req.result <= 0) {
+ uv_idle_stop(&stream->uv.idle);
+ invoke_read_cb(stream, 0, true);
+ return;
+ }
+
+ // no errors (req.result (ssize_t) is positive), it's safe to cast.
+ size_t nread = (size_t) req.result;
+ rbuffer_produced(stream->buffer, nread);
+ stream->fpos += nread;
+ invoke_read_cb(stream, nread, false);
+}
+
+static void read_event(void **argv)
+{
+ Stream *stream = argv[0];
+ if (stream->read_cb) {
+ size_t count = (uintptr_t)argv[1];
+ bool eof = (uintptr_t)argv[2];
+ stream->read_cb(stream, stream->buffer, count, stream->data, eof);
+ }
+ stream->pending_reqs--;
+ if (stream->closed && !stream->pending_reqs) {
+ stream_close_handle(stream);
+ }
+}
+
+static void invoke_read_cb(Stream *stream, size_t count, bool eof)
+{
+ if (stream->closed) {
+ return;
+ }
+
+ // Don't let the stream be closed before the event is processed.
+ stream->pending_reqs++;
+
+ CREATE_EVENT(stream->events,
+ read_event,
+ 3,
+ stream,
+ (void *)(uintptr_t *)count,
+ (void *)(uintptr_t)eof);
+}
diff --git a/src/nvim/event/rstream.h b/src/nvim/event/rstream.h
new file mode 100644
index 0000000000..f30ad79ee5
--- /dev/null
+++ b/src/nvim/event/rstream.h
@@ -0,0 +1,16 @@
+#ifndef NVIM_EVENT_RSTREAM_H
+#define NVIM_EVENT_RSTREAM_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/stream.h"
+
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/rstream.h.generated.h"
+#endif
+#endif // NVIM_EVENT_RSTREAM_H
diff --git a/src/nvim/event/signal.c b/src/nvim/event/signal.c
new file mode 100644
index 0000000000..11ce15a882
--- /dev/null
+++ b/src/nvim/event/signal.c
@@ -0,0 +1,59 @@
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/signal.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/signal.c.generated.h"
+#endif
+
+
+void signal_watcher_init(Loop *loop, SignalWatcher *watcher, void *data)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
+{
+ uv_signal_init(&loop->uv, &watcher->uv);
+ watcher->uv.data = watcher;
+ watcher->data = data;
+ watcher->cb = NULL;
+ watcher->events = loop->fast_events;
+}
+
+void signal_watcher_start(SignalWatcher *watcher, signal_cb cb, int signum)
+ FUNC_ATTR_NONNULL_ALL
+{
+ watcher->cb = cb;
+ uv_signal_start(&watcher->uv, signal_watcher_cb, signum);
+}
+
+void signal_watcher_stop(SignalWatcher *watcher)
+ FUNC_ATTR_NONNULL_ALL
+{
+ uv_signal_stop(&watcher->uv);
+}
+
+void signal_watcher_close(SignalWatcher *watcher, signal_close_cb cb)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ watcher->close_cb = cb;
+ uv_close((uv_handle_t *)&watcher->uv, close_cb);
+}
+
+static void signal_event(void **argv)
+{
+ SignalWatcher *watcher = argv[0];
+ watcher->cb(watcher, watcher->uv.signum, watcher->data);
+}
+
+static void signal_watcher_cb(uv_signal_t *handle, int signum)
+{
+ SignalWatcher *watcher = handle->data;
+ CREATE_EVENT(watcher->events, signal_event, 1, watcher);
+}
+
+static void close_cb(uv_handle_t *handle)
+{
+ SignalWatcher *watcher = handle->data;
+ if (watcher->close_cb) {
+ watcher->close_cb(watcher, watcher->data);
+ }
+}
diff --git a/src/nvim/event/signal.h b/src/nvim/event/signal.h
new file mode 100644
index 0000000000..e32608acc0
--- /dev/null
+++ b/src/nvim/event/signal.h
@@ -0,0 +1,23 @@
+#ifndef NVIM_EVENT_SIGNAL_H
+#define NVIM_EVENT_SIGNAL_H
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+
+typedef struct signal_watcher SignalWatcher;
+typedef void (*signal_cb)(SignalWatcher *watcher, int signum, void *data);
+typedef void (*signal_close_cb)(SignalWatcher *watcher, void *data);
+
+struct signal_watcher {
+ uv_signal_t uv;
+ void *data;
+ signal_cb cb;
+ signal_close_cb close_cb;
+ Queue *events;
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/signal.h.generated.h"
+#endif
+#endif // NVIM_EVENT_SIGNAL_H
diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c
new file mode 100644
index 0000000000..347e464d25
--- /dev/null
+++ b/src/nvim/event/socket.c
@@ -0,0 +1,167 @@
+#include <assert.h>
+#include <stdint.h>
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/socket.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
+#include "nvim/os/os.h"
+#include "nvim/ascii.h"
+#include "nvim/vim.h"
+#include "nvim/strings.h"
+#include "nvim/path.h"
+#include "nvim/memory.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/socket.c.generated.h"
+#endif
+
+#define NVIM_DEFAULT_TCP_PORT 7450
+
+void socket_watcher_init(Loop *loop, SocketWatcher *watcher,
+ const char *endpoint, void *data)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3)
+{
+ // Trim to `ADDRESS_MAX_SIZE`
+ if (xstrlcpy(watcher->addr, endpoint, sizeof(watcher->addr))
+ >= sizeof(watcher->addr)) {
+ // TODO(aktau): since this is not what the user wanted, perhaps we
+ // should return an error here
+ WLOG("Address was too long, truncated to %s", watcher->addr);
+ }
+
+ bool tcp = true;
+ char ip[16], *ip_end = xstrchrnul(watcher->addr, ':');
+
+ // (ip_end - addr) is always > 0, so convert to size_t
+ size_t addr_len = (size_t)(ip_end - watcher->addr);
+
+ if (addr_len > sizeof(ip) - 1) {
+ // Maximum length of an IPv4 address buffer is 15 (eg: 255.255.255.255)
+ addr_len = sizeof(ip) - 1;
+ }
+
+ // Extract the address part
+ xstrlcpy(ip, watcher->addr, addr_len + 1);
+ int port = NVIM_DEFAULT_TCP_PORT;
+
+ if (*ip_end == ':') {
+ // Extract the port
+ long lport = strtol(ip_end + 1, NULL, 10); // NOLINT
+ if (lport <= 0 || lport > 0xffff) {
+ // Invalid port, treat as named pipe or unix socket
+ tcp = false;
+ } else {
+ port = (int) lport;
+ }
+ }
+
+ if (tcp) {
+ // Try to parse ip address
+ if (uv_ip4_addr(ip, port, &watcher->uv.tcp.addr)) {
+ // Invalid address, treat as named pipe or unix socket
+ tcp = false;
+ }
+ }
+
+ if (tcp) {
+ uv_tcp_init(&loop->uv, &watcher->uv.tcp.handle);
+ watcher->stream = (uv_stream_t *)&watcher->uv.tcp.handle;
+ } else {
+ uv_pipe_init(&loop->uv, &watcher->uv.pipe.handle, 0);
+ watcher->stream = (uv_stream_t *)&watcher->uv.pipe.handle;
+ }
+
+ watcher->stream->data = watcher;
+ watcher->cb = NULL;
+ watcher->close_cb = NULL;
+ watcher->events = NULL;
+}
+
+int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
+ FUNC_ATTR_NONNULL_ALL
+{
+ watcher->cb = cb;
+ int result;
+
+ if (watcher->stream->type == UV_TCP) {
+ result = uv_tcp_bind(&watcher->uv.tcp.handle,
+ (const struct sockaddr *)&watcher->uv.tcp.addr, 0);
+ } else {
+ result = uv_pipe_bind(&watcher->uv.pipe.handle, watcher->addr);
+ }
+
+ if (result == 0) {
+ result = uv_listen(watcher->stream, backlog, connection_cb);
+ }
+
+ assert(result <= 0); // libuv should have returned -errno or zero.
+ if (result < 0) {
+ if (result == -EACCES) {
+ // Libuv converts ENOENT to EACCES for Windows compatibility, but if
+ // the parent directory does not exist, ENOENT would be more accurate.
+ *path_tail((char_u *)watcher->addr) = NUL;
+ if (!os_file_exists((char_u *)watcher->addr)) {
+ result = -ENOENT;
+ }
+ }
+ return result;
+ }
+
+ return 0;
+}
+
+int socket_watcher_accept(SocketWatcher *watcher, Stream *stream, void *data)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
+{
+ uv_stream_t *client;
+
+ if (watcher->stream->type == UV_TCP) {
+ client = (uv_stream_t *)&stream->uv.tcp;
+ uv_tcp_init(watcher->uv.tcp.handle.loop, (uv_tcp_t *)client);
+ } else {
+ client = (uv_stream_t *)&stream->uv.pipe;
+ uv_pipe_init(watcher->uv.pipe.handle.loop, (uv_pipe_t *)client, 0);
+ }
+
+ int result = uv_accept(watcher->stream, client);
+
+ if (result) {
+ uv_close((uv_handle_t *)client, NULL);
+ return result;
+ }
+
+ stream_init(NULL, stream, -1, client, data);
+ return 0;
+}
+
+void socket_watcher_close(SocketWatcher *watcher, socket_close_cb cb)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ watcher->close_cb = cb;
+ uv_close((uv_handle_t *)watcher->stream, close_cb);
+}
+
+static void connection_event(void **argv)
+{
+ SocketWatcher *watcher = argv[0];
+ int status = (int)(uintptr_t)(argv[1]);
+ watcher->cb(watcher, status, watcher->data);
+}
+
+static void connection_cb(uv_stream_t *handle, int status)
+{
+ SocketWatcher *watcher = handle->data;
+ CREATE_EVENT(watcher->events, connection_event, 2, watcher,
+ (void *)(uintptr_t)status);
+}
+
+static void close_cb(uv_handle_t *handle)
+{
+ SocketWatcher *watcher = handle->data;
+ if (watcher->close_cb) {
+ watcher->close_cb(watcher, watcher->data);
+ }
+}
diff --git a/src/nvim/event/socket.h b/src/nvim/event/socket.h
new file mode 100644
index 0000000000..ad59fdbe3a
--- /dev/null
+++ b/src/nvim/event/socket.h
@@ -0,0 +1,39 @@
+#ifndef NVIM_EVENT_SOCKET_H
+#define NVIM_EVENT_SOCKET_H
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
+
+#define ADDRESS_MAX_SIZE 256
+
+typedef struct socket_watcher SocketWatcher;
+typedef void (*socket_cb)(SocketWatcher *watcher, int result, void *data);
+typedef void (*socket_close_cb)(SocketWatcher *watcher, void *data);
+
+struct socket_watcher {
+ // Pipe/socket path, or TCP address string
+ char addr[ADDRESS_MAX_SIZE];
+ // TCP server or unix socket (named pipe on Windows)
+ union {
+ struct {
+ uv_tcp_t handle;
+ struct sockaddr_in addr;
+ } tcp;
+ struct {
+ uv_pipe_t handle;
+ } pipe;
+ } uv;
+ uv_stream_t *stream;
+ void *data;
+ socket_cb cb;
+ socket_close_cb close_cb;
+ Queue *events;
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/socket.h.generated.h"
+#endif
+#endif // NVIM_EVENT_SOCKET_H
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
new file mode 100644
index 0000000000..6caad6fdcc
--- /dev/null
+++ b/src/nvim/event/stream.c
@@ -0,0 +1,111 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#include <uv.h>
+
+#include "nvim/rbuffer.h"
+#include "nvim/event/stream.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/stream.c.generated.h"
+#endif
+
+/// Sets the stream associated with `fd` to "blocking" mode.
+///
+/// @return `0` on success, or `-errno` on failure.
+int stream_set_blocking(int fd, bool blocking)
+{
+ // Private loop to avoid conflict with existing watcher(s):
+ // uv__io_stop: Assertion `loop->watchers[w->fd] == w' failed.
+ uv_loop_t loop;
+ uv_pipe_t stream;
+ uv_loop_init(&loop);
+ uv_pipe_init(&loop, &stream, 0);
+ uv_pipe_open(&stream, fd);
+ int retval = uv_stream_set_blocking((uv_stream_t *)&stream, blocking);
+ uv_close((uv_handle_t *)&stream, NULL);
+ uv_run(&loop, UV_RUN_NOWAIT); // not necessary, but couldn't hurt.
+ uv_loop_close(&loop);
+ return retval;
+}
+
+void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream,
+ void *data)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ stream->uvstream = uvstream;
+
+ if (fd >= 0) {
+ uv_handle_type type = uv_guess_handle(fd);
+ stream->fd = fd;
+
+ if (type == UV_FILE) {
+ // Non-blocking file reads are simulated with an idle handle that reads in
+ // chunks of the ring buffer size, giving time for other events to be
+ // processed between reads.
+ uv_idle_init(&loop->uv, &stream->uv.idle);
+ stream->uv.idle.data = stream;
+ } else {
+ assert(type == UV_NAMED_PIPE || type == UV_TTY);
+ uv_pipe_init(&loop->uv, &stream->uv.pipe, 0);
+ uv_pipe_open(&stream->uv.pipe, fd);
+ stream->uvstream = (uv_stream_t *)&stream->uv.pipe;
+ }
+ }
+
+ if (stream->uvstream) {
+ stream->uvstream->data = stream;
+ loop = stream->uvstream->loop->data;
+ }
+
+ stream->data = data;
+ stream->internal_data = NULL;
+ stream->fpos = 0;
+ stream->curmem = 0;
+ stream->maxmem = 0;
+ stream->pending_reqs = 0;
+ stream->read_cb = NULL;
+ stream->write_cb = NULL;
+ stream->close_cb = NULL;
+ stream->internal_close_cb = NULL;
+ stream->closed = false;
+ stream->buffer = NULL;
+ stream->events = NULL;
+}
+
+void stream_close(Stream *stream, stream_close_cb on_stream_close)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ assert(!stream->closed);
+ stream->closed = true;
+ stream->close_cb = on_stream_close;
+
+ if (!stream->pending_reqs) {
+ stream_close_handle(stream);
+ }
+}
+
+void stream_close_handle(Stream *stream)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (stream->uvstream) {
+ uv_close((uv_handle_t *)stream->uvstream, close_cb);
+ } else {
+ uv_close((uv_handle_t *)&stream->uv.idle, close_cb);
+ }
+}
+
+static void close_cb(uv_handle_t *handle)
+{
+ Stream *stream = handle->data;
+ if (stream->buffer) {
+ rbuffer_free(stream->buffer);
+ }
+ if (stream->close_cb) {
+ stream->close_cb(stream, stream->data);
+ }
+ if (stream->internal_close_cb) {
+ stream->internal_close_cb(stream, stream->internal_data);
+ }
+}
diff --git a/src/nvim/event/stream.h b/src/nvim/event/stream.h
new file mode 100644
index 0000000000..c6baac0db7
--- /dev/null
+++ b/src/nvim/event/stream.h
@@ -0,0 +1,60 @@
+#ifndef NVIM_EVENT_STREAM_H
+#define NVIM_EVENT_STREAM_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/rbuffer.h"
+
+typedef struct stream Stream;
+/// Type of function called when the Stream buffer is filled with data
+///
+/// @param stream The Stream instance
+/// @param rbuffer The associated RBuffer instance
+/// @param count Number of bytes to read. This must be respected if keeping
+/// the order of events is a requirement. This is because events
+/// may be queued and only processed later when more data is copied
+/// into to the buffer, so one read may starve another.
+/// @param data User-defined data
+/// @param eof If the stream reached EOF.
+typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count,
+ void *data, bool eof);
+
+/// Type of function called when the Stream has information about a write
+/// request.
+///
+/// @param wstream The Stream instance
+/// @param data User-defined data
+/// @param status 0 on success, anything else indicates failure
+typedef void (*stream_write_cb)(Stream *stream, void *data, int status);
+typedef void (*stream_close_cb)(Stream *stream, void *data);
+
+struct stream {
+ union {
+ uv_pipe_t pipe;
+ uv_tcp_t tcp;
+ uv_idle_t idle;
+ } uv;
+ uv_stream_t *uvstream;
+ uv_buf_t uvbuf;
+ RBuffer *buffer;
+ uv_file fd;
+ stream_read_cb read_cb;
+ stream_write_cb write_cb;
+ stream_close_cb close_cb, internal_close_cb;
+ size_t fpos;
+ size_t curmem;
+ size_t maxmem;
+ size_t pending_reqs;
+ void *data, *internal_data;
+ bool closed;
+ Queue *events;
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/stream.h.generated.h"
+#endif
+#endif // NVIM_EVENT_STREAM_H
diff --git a/src/nvim/event/time.c b/src/nvim/event/time.c
new file mode 100644
index 0000000000..7bf333bcea
--- /dev/null
+++ b/src/nvim/event/time.c
@@ -0,0 +1,62 @@
+#include <stdint.h>
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/time.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/time.c.generated.h"
+#endif
+
+
+void time_watcher_init(Loop *loop, TimeWatcher *watcher, void *data)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
+{
+ uv_timer_init(&loop->uv, &watcher->uv);
+ watcher->uv.data = watcher;
+ watcher->data = data;
+ watcher->events = loop->fast_events;
+}
+
+void time_watcher_start(TimeWatcher *watcher, time_cb cb, uint64_t timeout,
+ uint64_t repeat)
+ FUNC_ATTR_NONNULL_ALL
+{
+ watcher->cb = cb;
+ uv_timer_start(&watcher->uv, time_watcher_cb, timeout, repeat);
+}
+
+void time_watcher_stop(TimeWatcher *watcher)
+ FUNC_ATTR_NONNULL_ALL
+{
+ uv_timer_stop(&watcher->uv);
+}
+
+void time_watcher_close(TimeWatcher *watcher, time_cb cb)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ watcher->close_cb = cb;
+ uv_close((uv_handle_t *)&watcher->uv, close_cb);
+}
+
+static void time_event(void **argv)
+{
+ TimeWatcher *watcher = argv[0];
+ watcher->cb(watcher, watcher->data);
+}
+
+static void time_watcher_cb(uv_timer_t *handle)
+ FUNC_ATTR_NONNULL_ALL
+{
+ TimeWatcher *watcher = handle->data;
+ CREATE_EVENT(watcher->events, time_event, 1, watcher);
+}
+
+static void close_cb(uv_handle_t *handle)
+{
+ TimeWatcher *watcher = handle->data;
+ if (watcher->close_cb) {
+ watcher->close_cb(watcher, watcher->data);
+ }
+}
diff --git a/src/nvim/event/time.h b/src/nvim/event/time.h
new file mode 100644
index 0000000000..7882b2b627
--- /dev/null
+++ b/src/nvim/event/time.h
@@ -0,0 +1,21 @@
+#ifndef NVIM_EVENT_TIME_H
+#define NVIM_EVENT_TIME_H
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+
+typedef struct time_watcher TimeWatcher;
+typedef void (*time_cb)(TimeWatcher *watcher, void *data);
+
+struct time_watcher {
+ uv_timer_t uv;
+ void *data;
+ time_cb cb, close_cb;
+ Queue *events;
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/time.h.generated.h"
+#endif
+#endif // NVIM_EVENT_TIME_H
diff --git a/src/nvim/event/uv_process.c b/src/nvim/event/uv_process.c
new file mode 100644
index 0000000000..21c2fd1790
--- /dev/null
+++ b/src/nvim/event/uv_process.c
@@ -0,0 +1,77 @@
+#include <assert.h>
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
+#include "nvim/event/process.h"
+#include "nvim/event/uv_process.h"
+#include "nvim/log.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/uv_process.c.generated.h"
+#endif
+
+bool uv_process_spawn(UvProcess *uvproc)
+ FUNC_ATTR_NONNULL_ALL
+{
+ Process *proc = (Process *)uvproc;
+ uvproc->uvopts.file = proc->argv[0];
+ uvproc->uvopts.args = proc->argv;
+ uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE;
+ uvproc->uvopts.exit_cb = exit_cb;
+ uvproc->uvopts.cwd = NULL;
+ uvproc->uvopts.env = NULL;
+ uvproc->uvopts.stdio = uvproc->uvstdio;
+ uvproc->uvopts.stdio_count = 3;
+ uvproc->uvstdio[0].flags = UV_IGNORE;
+ uvproc->uvstdio[1].flags = UV_IGNORE;
+ uvproc->uvstdio[2].flags = UV_IGNORE;
+ uvproc->uv.data = proc;
+
+ if (proc->in) {
+ uvproc->uvstdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ uvproc->uvstdio[0].data.stream = (uv_stream_t *)&proc->in->uv.pipe;
+ }
+
+ if (proc->out) {
+ uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ uvproc->uvstdio[1].data.stream = (uv_stream_t *)&proc->out->uv.pipe;
+ }
+
+ if (proc->err) {
+ uvproc->uvstdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ uvproc->uvstdio[2].data.stream = (uv_stream_t *)&proc->err->uv.pipe;
+ }
+
+ int status;
+ if ((status = uv_spawn(&proc->loop->uv, &uvproc->uv, &uvproc->uvopts))) {
+ ELOG("uv_spawn failed: %s", uv_strerror(status));
+ return false;
+ }
+
+ proc->pid = uvproc->uv.pid;
+ return true;
+}
+
+void uv_process_close(UvProcess *uvproc)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ uv_close((uv_handle_t *)&uvproc->uv, close_cb);
+}
+
+static void close_cb(uv_handle_t *handle)
+{
+ Process *proc = handle->data;
+ if (proc->internal_close_cb) {
+ proc->internal_close_cb(proc);
+ }
+}
+
+static void exit_cb(uv_process_t *handle, int64_t status, int term_signal)
+{
+ Process *proc = handle->data;
+ proc->status = (int)status;
+ proc->internal_exit_cb(proc);
+}
diff --git a/src/nvim/event/uv_process.h b/src/nvim/event/uv_process.h
new file mode 100644
index 0000000000..5ee73044b5
--- /dev/null
+++ b/src/nvim/event/uv_process.h
@@ -0,0 +1,25 @@
+#ifndef NVIM_EVENT_UV_PROCESS_H
+#define NVIM_EVENT_UV_PROCESS_H
+
+#include <uv.h>
+
+#include "nvim/event/process.h"
+
+typedef struct uv_process {
+ Process process;
+ uv_process_t uv;
+ uv_process_options_t uvopts;
+ uv_stdio_container_t uvstdio[3];
+} UvProcess;
+
+static inline UvProcess uv_process_init(Loop *loop, void *data)
+{
+ UvProcess rv;
+ rv.process = process_init(loop, kProcessTypeUv, data);
+ return rv;
+}
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/uv_process.h.generated.h"
+#endif
+#endif // NVIM_EVENT_UV_PROCESS_H
diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c
new file mode 100644
index 0000000000..8028e35e6b
--- /dev/null
+++ b/src/nvim/event/wstream.c
@@ -0,0 +1,164 @@
+#include <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/wstream.h"
+#include "nvim/vim.h"
+#include "nvim/memory.h"
+
+#define DEFAULT_MAXMEM 1024 * 1024 * 10
+
+typedef struct {
+ Stream *stream;
+ WBuffer *buffer;
+ uv_write_t uv_req;
+} WRequest;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/wstream.c.generated.h"
+#endif
+
+void wstream_init_fd(Loop *loop, Stream *stream, int fd, size_t maxmem,
+ void *data)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
+{
+ stream_init(loop, stream, fd, NULL, data);
+ wstream_init(stream, maxmem);
+}
+
+void wstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t maxmem,
+ void *data)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
+{
+ stream_init(NULL, stream, -1, uvstream, data);
+ wstream_init(stream, maxmem);
+}
+
+void wstream_init(Stream *stream, size_t maxmem)
+{
+ stream->maxmem = maxmem ? maxmem : DEFAULT_MAXMEM;
+}
+
+/// Sets a callback that will be called on completion of a write request,
+/// indicating failure/success.
+///
+/// This affects all requests currently in-flight as well. Overwrites any
+/// possible earlier callback.
+///
+/// @note This callback will not fire if the write request couldn't even be
+/// queued properly (i.e.: when `wstream_write() returns an error`).
+///
+/// @param stream The `Stream` instance
+/// @param cb The callback
+void wstream_set_write_cb(Stream *stream, stream_write_cb cb)
+ FUNC_ATTR_NONNULL_ALL
+{
+ stream->write_cb = cb;
+}
+
+/// Queues data for writing to the backing file descriptor of a `Stream`
+/// instance. This will fail if the write would cause the Stream use more
+/// memory than specified by `maxmem`.
+///
+/// @param stream The `Stream` instance
+/// @param buffer The buffer which contains data to be written
+/// @return false if the write failed
+bool wstream_write(Stream *stream, WBuffer *buffer)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(stream->maxmem);
+ // This should not be called after a stream was freed
+ assert(!stream->closed);
+
+ if (stream->curmem > stream->maxmem) {
+ goto err;
+ }
+
+ stream->curmem += buffer->size;
+
+ WRequest *data = xmalloc(sizeof(WRequest));
+ data->stream = stream;
+ data->buffer = buffer;
+ data->uv_req.data = data;
+
+ uv_buf_t uvbuf;
+ uvbuf.base = buffer->data;
+ uvbuf.len = buffer->size;
+
+ if (uv_write(&data->uv_req, stream->uvstream, &uvbuf, 1, write_cb)) {
+ xfree(data);
+ goto err;
+ }
+
+ stream->pending_reqs++;
+ return true;
+
+err:
+ wstream_release_wbuffer(buffer);
+ return false;
+}
+
+/// Creates a WBuffer object for holding output data. Instances of this
+/// object can be reused across Stream instances, and the memory is freed
+/// automatically when no longer needed(it tracks the number of references
+/// internally)
+///
+/// @param data Data stored by the WBuffer
+/// @param size The size of the data array
+/// @param refcount The number of references for the WBuffer. This will be used
+/// by Stream instances to decide when a WBuffer should be freed.
+/// @param cb Pointer to function that will be responsible for freeing
+/// the buffer data(passing 'free' will work as expected).
+/// @return The allocated WBuffer instance
+WBuffer *wstream_new_buffer(char *data,
+ size_t size,
+ size_t refcount,
+ wbuffer_data_finalizer cb)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ WBuffer *rv = xmalloc(sizeof(WBuffer));
+ rv->size = size;
+ rv->refcount = refcount;
+ rv->cb = cb;
+ rv->data = data;
+
+ return rv;
+}
+
+static void write_cb(uv_write_t *req, int status)
+{
+ WRequest *data = req->data;
+
+ data->stream->curmem -= data->buffer->size;
+
+ wstream_release_wbuffer(data->buffer);
+
+ if (data->stream->write_cb) {
+ data->stream->write_cb(data->stream, data->stream->data, status);
+ }
+
+ data->stream->pending_reqs--;
+
+ if (data->stream->closed && data->stream->pending_reqs == 0) {
+ // Last pending write, free the stream;
+ stream_close_handle(data->stream);
+ }
+
+ xfree(data);
+}
+
+void wstream_release_wbuffer(WBuffer *buffer)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (!--buffer->refcount) {
+ if (buffer->cb) {
+ buffer->cb(buffer->data);
+ }
+
+ xfree(buffer);
+ }
+}
diff --git a/src/nvim/event/wstream.h b/src/nvim/event/wstream.h
new file mode 100644
index 0000000000..9008de0d97
--- /dev/null
+++ b/src/nvim/event/wstream.h
@@ -0,0 +1,24 @@
+#ifndef NVIM_EVENT_WSTREAM_H
+#define NVIM_EVENT_WSTREAM_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <uv.h>
+
+#include "nvim/event/loop.h"
+#include "nvim/event/stream.h"
+
+typedef struct wbuffer WBuffer;
+typedef void (*wbuffer_data_finalizer)(void *data);
+
+struct wbuffer {
+ size_t size, refcount;
+ char *data;
+ wbuffer_data_finalizer cb;
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "event/wstream.h.generated.h"
+#endif
+#endif // NVIM_EVENT_WSTREAM_H
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index b4adef9235..cacef01b19 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3472,18 +3472,8 @@ void do_sub(exarg_T *eap)
}
if (!eap->skip) {
- /* In POSIX vi ":s/pat/%/" uses the previous subst. string. */
- if (STRCMP(sub, "%") == 0
- && vim_strchr(p_cpo, CPO_SUBPERCENT) != NULL) {
- if (old_sub == NULL) { /* there is no previous command */
- EMSG(_(e_nopresub));
- return;
- }
- sub = old_sub;
- } else {
- xfree(old_sub);
- old_sub = vim_strsave(sub);
- }
+ xfree(old_sub);
+ old_sub = vim_strsave(sub);
}
} else if (!eap->skip) { /* use previous pattern and substitution */
if (old_sub == NULL) { /* there is no previous command */
@@ -6135,7 +6125,7 @@ char_u * sign_typenr2name(int typenr)
/*
* Undefine/free all signs.
*/
-void free_signs()
+void free_signs(void)
{
while (first_sign != NULL)
sign_undefine(first_sign, NULL);
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 011b3ce611..5221554306 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -2678,12 +2678,6 @@ return {
func='ex_ni',
},
{
- command='tearoff',
- flags=bit.bor(NEEDARG, EXTRA, TRLBAR, NOTRLCOM, CMDWIN),
- addr_type=ADDR_LINES,
- func='ex_tearoff',
- },
- {
command='terminal',
flags=bit.bor(BANG, FILES, CMDWIN),
addr_type=ADDR_LINES,
@@ -3171,12 +3165,6 @@ return {
func='ex_previous',
},
{
- command='Print',
- flags=bit.bor(RANGE, WHOLEFOLD, COUNT, EXFLAGS, TRLBAR, CMDWIN),
- addr_type=ADDR_LINES,
- func='ex_print',
- },
- {
command='~',
enum='CMD_tilde',
flags=bit.bor(RANGE, WHOLEFOLD, EXTRA, CMDWIN, MODIFY),
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index d610aa6d19..efa18aa681 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2624,7 +2624,7 @@ char_u *get_scriptname(scid_T id)
}
# if defined(EXITFREE)
-void free_scriptnames()
+void free_scriptnames(void)
{
# define FREE_SCRIPTNAME(item) xfree((item)->sn_name)
GA_DEEP_CLEAR(&script_items, scriptitem_T, FREE_SCRIPTNAME);
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 35b62cdd47..3c57537397 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -73,8 +73,8 @@
#include "nvim/os/time.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/mouse.h"
-#include "nvim/os/rstream.h"
-#include "nvim/os/wstream.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
static int quitmore = 0;
static int ex_pressedreturn = FALSE;
@@ -144,7 +144,6 @@ struct dbg_stuff {
#endif
# define ex_gui ex_nogui
-# define ex_tearoff ex_ni
# define ex_popup ex_ni
# define ex_simalt ex_ni
# define gui_mch_find_dialog ex_ni
@@ -2402,9 +2401,8 @@ static char_u *find_command(exarg_T *eap, int *full)
break;
}
- /* Look for a user defined command as a last resort. Let ":Print" be
- * overruled by a user defined command. */
- if ((eap->cmdidx == CMD_SIZE || eap->cmdidx == CMD_Print)
+ // Look for a user defined command as a last resort.
+ if ((eap->cmdidx == CMD_SIZE)
&& *eap->cmd >= 'A' && *eap->cmd <= 'Z') {
/* User defined commands may contain digits. */
while (ASCII_ISALNUM(*p))
@@ -3276,7 +3274,7 @@ set_one_cmd_context (
case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
case CMD_tmenu: case CMD_tunmenu:
- case CMD_popup: case CMD_tearoff: case CMD_emenu:
+ case CMD_popup: case CMD_emenu:
return set_context_in_menu_cmd(xp, cmd, arg, forceit);
case CMD_colorscheme:
@@ -6835,12 +6833,6 @@ void ex_cd(exarg_T *eap)
{
if (allbuf_locked())
return;
- if (vim_strchr(p_cpo, CPO_CHDIR) != NULL && curbufIsChanged()
- && !eap->forceit) {
- EMSG(_(
- "E747: Cannot change directory, buffer is modified (add ! to override)"));
- return;
- }
/* ":cd -": Change to previous directory */
if (STRCMP(new_dir, "-") == 0) {
@@ -7555,8 +7547,9 @@ static void ex_mkrc(exarg_T *eap)
int vim_mkdir_emsg(char_u *name, int prot)
{
- if (os_mkdir((char *)name, prot) != 0) {
- EMSG2(_("E739: Cannot create directory: %s"), name);
+ int ret;
+ if ((ret = os_mkdir((char *)name, prot)) != 0) {
+ EMSG3(_(e_mkdir), name, os_strerror(ret));
return FAIL;
}
return OK;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 3af035a6e3..03116d454f 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -62,8 +62,9 @@
#include "nvim/tag.h"
#include "nvim/window.h"
#include "nvim/ui.h"
+#include "nvim/os/input.h"
#include "nvim/os/os.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
/*
* Variables shared between getcmdline(), redrawcmdline() and others.
@@ -298,14 +299,14 @@ getcmdline (
/* Get a character. Ignore K_IGNORE, it should not do anything, such
* as stop completion. */
- event_enable_deferred();
+ input_enable_events();
do {
c = safe_vgetc();
} while (c == K_IGNORE);
- event_disable_deferred();
+ input_disable_events();
if (c == K_EVENT) {
- event_process();
+ queue_process_events(loop.events);
continue;
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 4dfa155e61..c9e11d8fb5 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -415,14 +415,10 @@ readfile (
msg_scroll = TRUE; /* don't overwrite previous file message */
/*
- * If the name ends in a path separator, we can't open it. Check here,
- * because reading the file may actually work, but then creating the swap
- * file may destroy it! Reported on MS-DOS and Win 95.
* If the name is too long we might crash further on, quit here.
*/
if (fname != NULL && *fname != NUL) {
- p = fname + STRLEN(fname);
- if (after_pathsep((char *)fname, (char *)p) || STRLEN(fname) >= MAXPATHL) {
+ if (STRLEN(fname) >= MAXPATHL) {
filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
msg_end();
msg_scroll = msg_save;
@@ -5121,116 +5117,9 @@ void forward_slash(char_u *fname)
/*
* Code for automatic commands.
*/
-
-
-static struct event_name {
- char *name; /* event name */
- event_T event; /* event number */
-} event_names[] =
-{
- {"BufAdd", EVENT_BUFADD},
- {"BufCreate", EVENT_BUFADD},
- {"BufDelete", EVENT_BUFDELETE},
- {"BufEnter", EVENT_BUFENTER},
- {"BufFilePost", EVENT_BUFFILEPOST},
- {"BufFilePre", EVENT_BUFFILEPRE},
- {"BufHidden", EVENT_BUFHIDDEN},
- {"BufLeave", EVENT_BUFLEAVE},
- {"BufNew", EVENT_BUFNEW},
- {"BufNewFile", EVENT_BUFNEWFILE},
- {"BufRead", EVENT_BUFREADPOST},
- {"BufReadCmd", EVENT_BUFREADCMD},
- {"BufReadPost", EVENT_BUFREADPOST},
- {"BufReadPre", EVENT_BUFREADPRE},
- {"BufUnload", EVENT_BUFUNLOAD},
- {"BufWinEnter", EVENT_BUFWINENTER},
- {"BufWinLeave", EVENT_BUFWINLEAVE},
- {"BufWipeout", EVENT_BUFWIPEOUT},
- {"BufWrite", EVENT_BUFWRITEPRE},
- {"BufWritePost", EVENT_BUFWRITEPOST},
- {"BufWritePre", EVENT_BUFWRITEPRE},
- {"BufWriteCmd", EVENT_BUFWRITECMD},
- {"CmdwinEnter", EVENT_CMDWINENTER},
- {"CmdwinLeave", EVENT_CMDWINLEAVE},
- {"CmdUndefined", EVENT_CMDUNDEFINED},
- {"ColorScheme", EVENT_COLORSCHEME},
- {"CompleteDone", EVENT_COMPLETEDONE},
- {"CursorHold", EVENT_CURSORHOLD},
- {"CursorHoldI", EVENT_CURSORHOLDI},
- {"CursorMoved", EVENT_CURSORMOVED},
- {"CursorMovedI", EVENT_CURSORMOVEDI},
- {"EncodingChanged", EVENT_ENCODINGCHANGED},
- {"FileEncoding", EVENT_ENCODINGCHANGED},
- {"FileAppendPost", EVENT_FILEAPPENDPOST},
- {"FileAppendPre", EVENT_FILEAPPENDPRE},
- {"FileAppendCmd", EVENT_FILEAPPENDCMD},
- {"FileChangedShell",EVENT_FILECHANGEDSHELL},
- {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
- {"FileChangedRO", EVENT_FILECHANGEDRO},
- {"FileReadPost", EVENT_FILEREADPOST},
- {"FileReadPre", EVENT_FILEREADPRE},
- {"FileReadCmd", EVENT_FILEREADCMD},
- {"FileType", EVENT_FILETYPE},
- {"FileWritePost", EVENT_FILEWRITEPOST},
- {"FileWritePre", EVENT_FILEWRITEPRE},
- {"FileWriteCmd", EVENT_FILEWRITECMD},
- {"FilterReadPost", EVENT_FILTERREADPOST},
- {"FilterReadPre", EVENT_FILTERREADPRE},
- {"FilterWritePost", EVENT_FILTERWRITEPOST},
- {"FilterWritePre", EVENT_FILTERWRITEPRE},
- {"FocusGained", EVENT_FOCUSGAINED},
- {"FocusLost", EVENT_FOCUSLOST},
- {"FuncUndefined", EVENT_FUNCUNDEFINED},
- {"GUIEnter", EVENT_GUIENTER},
- {"GUIFailed", EVENT_GUIFAILED},
- {"InsertChange", EVENT_INSERTCHANGE},
- {"InsertEnter", EVENT_INSERTENTER},
- {"InsertLeave", EVENT_INSERTLEAVE},
- {"InsertCharPre", EVENT_INSERTCHARPRE},
- {"MenuPopup", EVENT_MENUPOPUP},
- {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
- {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
- {"QuitPre", EVENT_QUITPRE},
- {"RemoteReply", EVENT_REMOTEREPLY},
- {"SessionLoadPost", EVENT_SESSIONLOADPOST},
- {"ShellCmdPost", EVENT_SHELLCMDPOST},
- {"ShellFilterPost", EVENT_SHELLFILTERPOST},
- {"SourcePre", EVENT_SOURCEPRE},
- {"SourceCmd", EVENT_SOURCECMD},
- {"SpellFileMissing",EVENT_SPELLFILEMISSING},
- {"StdinReadPost", EVENT_STDINREADPOST},
- {"StdinReadPre", EVENT_STDINREADPRE},
- {"SwapExists", EVENT_SWAPEXISTS},
- {"Syntax", EVENT_SYNTAX},
- {"TabClosed", EVENT_TABCLOSED},
- {"TabEnter", EVENT_TABENTER},
- {"TabLeave", EVENT_TABLEAVE},
- {"TabNew", EVENT_TABNEW},
- {"TabNewEntered", EVENT_TABNEWENTERED},
- {"TermChanged", EVENT_TERMCHANGED},
- {"TermOpen", EVENT_TERMOPEN},
- {"TermResponse", EVENT_TERMRESPONSE},
- {"TextChanged", EVENT_TEXTCHANGED},
- {"TextChangedI", EVENT_TEXTCHANGEDI},
- {"User", EVENT_USER},
- {"VimEnter", EVENT_VIMENTER},
- {"VimLeave", EVENT_VIMLEAVE},
- {"VimLeavePre", EVENT_VIMLEAVEPRE},
- {"WinEnter", EVENT_WINENTER},
- {"WinLeave", EVENT_WINLEAVE},
- {"VimResized", EVENT_VIMRESIZED},
- {NULL, (event_T)0}
-};
-
-static AutoPat *first_autopat[NUM_EVENTS] =
-{
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "auevents_name_map.generated.h"
+#endif
static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
@@ -5526,7 +5415,7 @@ static event_T event_name2nr(char_u *start, char_u **end)
for (p = start; *p && !ascii_iswhite(*p) && *p != ','; ++p)
;
for (i = 0; event_names[i].name != NULL; ++i) {
- len = (int)STRLEN(event_names[i].name);
+ len = (int) event_names[i].len;
if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
break;
}
diff --git a/src/nvim/fileio.h b/src/nvim/fileio.h
index 3b37d359d7..d93f3f3eb3 100644
--- a/src/nvim/fileio.h
+++ b/src/nvim/fileio.h
@@ -13,100 +13,6 @@
#define READ_KEEP_UNDO 0x20 /* keep undo info*/
/*
- * Events for autocommands.
- */
-typedef enum auto_event {
- EVENT_BUFADD = 0, /* after adding a buffer to the buffer list */
- EVENT_BUFNEW, /* after creating any buffer */
- EVENT_BUFDELETE, /* deleting a buffer from the buffer list */
- EVENT_BUFWIPEOUT, /* just before really deleting a buffer */
- EVENT_BUFENTER, /* after entering a buffer */
- EVENT_BUFFILEPOST, /* after renaming a buffer */
- EVENT_BUFFILEPRE, /* before renaming a buffer */
- EVENT_BUFLEAVE, /* before leaving a buffer */
- EVENT_BUFNEWFILE, /* when creating a buffer for a new file */
- EVENT_BUFREADPOST, /* after reading a buffer */
- EVENT_BUFREADPRE, /* before reading a buffer */
- EVENT_BUFREADCMD, /* read buffer using command */
- EVENT_BUFUNLOAD, /* just before unloading a buffer */
- EVENT_BUFHIDDEN, /* just after buffer becomes hidden */
- EVENT_BUFWINENTER, /* after showing a buffer in a window */
- EVENT_BUFWINLEAVE, /* just after buffer removed from window */
- EVENT_BUFWRITEPOST, /* after writing a buffer */
- EVENT_BUFWRITEPRE, /* before writing a buffer */
- EVENT_BUFWRITECMD, /* write buffer using command */
- EVENT_CMDWINENTER, /* after entering the cmdline window */
- EVENT_CMDWINLEAVE, /* before leaving the cmdline window */
- EVENT_COLORSCHEME, /* after loading a colorscheme */
- EVENT_COMPLETEDONE, /* after finishing insert complete */
- EVENT_FILEAPPENDPOST, /* after appending to a file */
- EVENT_FILEAPPENDPRE, /* before appending to a file */
- EVENT_FILEAPPENDCMD, /* append to a file using command */
- EVENT_FILECHANGEDSHELL, /* after shell command that changed file */
- EVENT_FILECHANGEDSHELLPOST, /* after (not) reloading changed file */
- EVENT_FILECHANGEDRO, /* before first change to read-only file */
- EVENT_FILEREADPOST, /* after reading a file */
- EVENT_FILEREADPRE, /* before reading a file */
- EVENT_FILEREADCMD, /* read from a file using command */
- EVENT_FILETYPE, /* new file type detected (user defined) */
- EVENT_FILEWRITEPOST, /* after writing a file */
- EVENT_FILEWRITEPRE, /* before writing a file */
- EVENT_FILEWRITECMD, /* write to a file using command */
- EVENT_FILTERREADPOST, /* after reading from a filter */
- EVENT_FILTERREADPRE, /* before reading from a filter */
- EVENT_FILTERWRITEPOST, /* after writing to a filter */
- EVENT_FILTERWRITEPRE, /* before writing to a filter */
- EVENT_FOCUSGAINED, /* got the focus */
- EVENT_FOCUSLOST, /* lost the focus to another app */
- EVENT_GUIENTER, /* after starting the GUI */
- EVENT_GUIFAILED, /* after starting the GUI failed */
- EVENT_INSERTCHANGE, /* when changing Insert/Replace mode */
- EVENT_INSERTENTER, /* when entering Insert mode */
- EVENT_INSERTLEAVE, /* when leaving Insert mode */
- EVENT_MENUPOPUP, /* just before popup menu is displayed */
- EVENT_QUICKFIXCMDPOST, /* after :make, :grep etc. */
- EVENT_QUICKFIXCMDPRE, /* before :make, :grep etc. */
- EVENT_QUITPRE, /* before :quit */
- EVENT_SESSIONLOADPOST, /* after loading a session file */
- EVENT_STDINREADPOST, /* after reading from stdin */
- EVENT_STDINREADPRE, /* before reading from stdin */
- EVENT_SYNTAX, /* syntax selected */
- EVENT_TERMCHANGED, /* after changing 'term' */
- EVENT_TERMRESPONSE, /* after setting "v:termresponse" */
- EVENT_USER, /* user defined autocommand */
- EVENT_VIMENTER, /* after starting Vim */
- EVENT_VIMLEAVE, /* before exiting Vim */
- EVENT_VIMLEAVEPRE, /* before exiting Vim and writing .viminfo */
- EVENT_VIMRESIZED, /* after Vim window was resized */
- EVENT_WINENTER, /* after entering a window */
- EVENT_WINLEAVE, /* before leaving a window */
- EVENT_ENCODINGCHANGED, /* after changing the 'encoding' option */
- EVENT_INSERTCHARPRE, /* before inserting a char */
- EVENT_CURSORHOLD, /* cursor in same position for a while */
- EVENT_CURSORHOLDI, /* idem, in Insert mode */
- EVENT_FUNCUNDEFINED, /* if calling a function which doesn't exist */
- EVENT_REMOTEREPLY, /* upon string reception from a remote vim */
- EVENT_SWAPEXISTS, /* found existing swap file */
- EVENT_SOURCEPRE, /* before sourcing a Vim script */
- EVENT_SOURCECMD, /* sourcing a Vim script using command */
- EVENT_SPELLFILEMISSING, /* spell file missing */
- EVENT_CURSORMOVED, /* cursor was moved */
- EVENT_CURSORMOVEDI, /* cursor was moved in Insert mode */
- EVENT_TABCLOSED, /* a tab has closed */
- EVENT_TABLEAVE, /* before leaving a tab page */
- EVENT_TABENTER, /* after entering a tab page */
- EVENT_TABNEW, /* when creating a new tab */
- EVENT_TABNEWENTERED, /* after entering a new tab */
- EVENT_SHELLCMDPOST, /* after ":!cmd" */
- EVENT_SHELLFILTERPOST, /* after ":1,2!cmd", ":w !cmd", ":r !cmd". */
- EVENT_TERMOPEN, // after opening a terminal buffer
- EVENT_TEXTCHANGED, /* text was modified */
- EVENT_TEXTCHANGEDI, /* text was modified in Insert mode*/
- EVENT_CMDUNDEFINED, ///< command undefined
- NUM_EVENTS /* MUST be the last one */
-} event_T;
-
-/*
* Struct to save values in before executing autocommands for a buffer that is
* not the current buffer.
*/
@@ -120,6 +26,8 @@ typedef struct {
} aco_save_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
+// Events for autocommands
+# include "auevents_enum.generated.h"
# include "fileio.h.generated.h"
#endif
#endif // NVIM_FILEIO_H
diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h
index 519f61c763..c31d21ec6d 100644
--- a/src/nvim/func_attr.h
+++ b/src/nvim/func_attr.h
@@ -179,7 +179,7 @@
#endif
#ifdef DEFINE_FUNC_ATTRIBUTES
- #define FUNC_ATTR_DEFERRED
+ #define FUNC_ATTR_ASYNC
#define FUNC_ATTR_MALLOC REAL_FATTR_MALLOC
#define FUNC_ATTR_ALLOC_SIZE(x) REAL_FATTR_ALLOC_SIZE(x)
#define FUNC_ATTR_ALLOC_SIZE_PROD(x,y) REAL_FATTR_ALLOC_SIZE_PROD(x,y)
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 864aa6a622..6a6e4f2214 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -49,7 +49,7 @@
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
@@ -1758,7 +1758,7 @@ static int vgetorpeek(int advance)
if (c1 == K_SPECIAL)
nolmaplen = 2;
else {
- LANGMAP_ADJUST(c1, (State & INSERT) == 0);
+ LANGMAP_ADJUST(c1, (State & (CMDLINE | INSERT)) == 0);
nolmaplen = 0;
}
/* First try buffer-local mappings. */
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 1d93900a94..68cb923e42 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -28,6 +28,7 @@
#include "nvim/menu.h"
#include "nvim/syntax_defs.h"
#include "nvim/types.h"
+#include "nvim/event/loop.h"
/*
* definition of global variables
@@ -58,7 +59,7 @@
/* Values for "starting" */
#define NO_SCREEN 2 /* no screen updating yet */
#define NO_BUFFERS 1 /* not all buffers loaded yet */
-/* 0 not starting anymore */
+/* 0 not starting anymore */
/*
* Number of Rows and Columns in the screen.
@@ -67,12 +68,16 @@
* They may have different values when the screen wasn't (re)allocated yet
* after setting Rows or Columns (e.g., when starting up).
*/
+
+#define DFLT_COLS 80 /* default value for 'columns' */
+#define DFLT_ROWS 24 /* default value for 'lines' */
+
EXTERN long Rows /* nr of rows in the screen */
#ifdef DO_INIT
- = 24L
+ = DFLT_ROWS
#endif
;
-EXTERN long Columns INIT(= 80); /* nr of columns in the screen */
+EXTERN long Columns INIT(= DFLT_COLS); /* nr of columns in the screen */
/*
* The characters and attributes cached for the screen.
@@ -893,14 +898,6 @@ EXTERN FILE *scriptout INIT(= NULL); /* stream to write script to */
/* volatile because it is used in signal handler catch_sigint(). */
EXTERN volatile int got_int INIT(= FALSE); /* set to TRUE when interrupt
signal occurred */
-EXTERN int disable_breakcheck INIT(= 0); // > 0 if breakchecks should be
- // ignored. FIXME(tarruda): Hacky
- // way to run functions that would
- // result in *_breakcheck calls
- // while events that would normally
- // be deferred are being processed
- // immediately. Ref:
- // neovim/neovim#2371
EXTERN int bangredo INIT(= FALSE); /* set to TRUE with ! command */
EXTERN int searchcmdlen; /* length of previous search cmd */
EXTERN int reg_do_extmatch INIT(= 0); /* Used when compiling regexp:
@@ -1112,6 +1109,7 @@ EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full"));
EXTERN char_u e_jobexe[] INIT(= N_("E902: \"%s\" is not an executable"));
EXTERN char_u e_jobnotpty[] INIT(= N_("E904: Job is not connected to a pty"));
EXTERN char_u e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
+EXTERN char_u e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s"));
EXTERN char_u e_markinval[] INIT(= N_("E19: Mark has invalid line number"));
EXTERN char_u e_marknotset[] INIT(= N_("E20: Mark not set"));
EXTERN char_u e_modifiable[] INIT(= N_(
@@ -1216,6 +1214,7 @@ EXTERN char *ignoredp;
// If a msgpack-rpc channel should be started over stdin/stdout
EXTERN bool embedded_mode INIT(= false);
+EXTERN Loop loop;
/// Used to track the status of external functions.
/// Currently only used for iconv().
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 99926ecf16..d6c5cf4fd5 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -31,6 +31,7 @@
#include "nvim/window.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
+#include "nvim/event/stream.h"
#include <sys/types.h>
#include <sys/stat.h>
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index 022d27fda1..38b96b1b8c 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -83,11 +83,6 @@
#define KS_SELECT 245
#define K_SELECT_STRING (char_u *)"\200\365X"
-/*
- * Used for tearing off a menu.
- */
-#define KS_TEAROFF 244
-
/* Used a termcap entry that produces a normal character. */
#define KS_KEY 242
@@ -396,7 +391,6 @@ enum key_extra {
#define K_HOR_SCROLLBAR TERMCAP2KEY(KS_HOR_SCROLLBAR, KE_FILLER)
#define K_SELECT TERMCAP2KEY(KS_SELECT, KE_FILLER)
-#define K_TEAROFF TERMCAP2KEY(KS_TEAROFF, KE_FILLER)
#define K_TABLINE TERMCAP2KEY(KS_TABLINE, KE_FILLER)
#define K_TABMENU TERMCAP2KEY(KS_TABMENU, KE_FILLER)
diff --git a/src/nvim/lib/klist.h b/src/nvim/lib/klist.h
index 10d6846133..1280a927e8 100644
--- a/src/nvim/lib/klist.h
+++ b/src/nvim/lib/klist.h
@@ -136,6 +136,6 @@
// `break` statement is executed before the next iteration.
#define kl_iter(name, kl, p) kl_iter_at(name, kl, p, NULL)
#define kl_iter_at(name, kl, p, h) \
- for (kl1_##name *p = h ? h : kl->head; p != kl->tail; p = p->next)
+ for (kl1_##name **p = h ? h : &kl->head; *p != kl->tail; p = &(*p)->next)
#endif
diff --git a/src/nvim/lib/queue.h b/src/nvim/lib/queue.h
new file mode 100644
index 0000000000..fe02b454ea
--- /dev/null
+++ b/src/nvim/lib/queue.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef QUEUE_H_
+#define QUEUE_H_
+
+typedef void *QUEUE[2];
+
+/* Private macros. */
+#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
+#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
+#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
+#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
+
+/* Public macros. */
+#define QUEUE_DATA(ptr, type, field) \
+ ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
+
+#define QUEUE_FOREACH(q, h) \
+ for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
+
+#define QUEUE_EMPTY(q) \
+ ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
+
+#define QUEUE_HEAD(q) \
+ (QUEUE_NEXT(q))
+
+#define QUEUE_INIT(q) \
+ do { \
+ QUEUE_NEXT(q) = (q); \
+ QUEUE_PREV(q) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_ADD(h, n) \
+ do { \
+ QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
+ QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV(h) = QUEUE_PREV(n); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ } \
+ while (0)
+
+#define QUEUE_SPLIT(h, q, n) \
+ do { \
+ QUEUE_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(n) = (n); \
+ QUEUE_NEXT(n) = (q); \
+ QUEUE_PREV(h) = QUEUE_PREV(q); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ QUEUE_PREV(q) = (n); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_HEAD(h, q) \
+ do { \
+ QUEUE_NEXT(q) = QUEUE_NEXT(h); \
+ QUEUE_PREV(q) = (h); \
+ QUEUE_NEXT_PREV(q) = (q); \
+ QUEUE_NEXT(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_TAIL(h, q) \
+ do { \
+ QUEUE_NEXT(q) = (h); \
+ QUEUE_PREV(q) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(q) = (q); \
+ QUEUE_PREV(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_REMOVE(q) \
+ do { \
+ QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
+ QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
+ } \
+ while (0)
+
+#endif /* QUEUE_H_ */
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 50c16c51d6..e11db16c61 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -61,9 +61,13 @@
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
#include "nvim/os/signal.h"
+#include "nvim/event/process.h"
+#include "nvim/msgpack_rpc/defs.h"
#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/msgpack_rpc/server.h"
+#include "nvim/msgpack_rpc/channel.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/handle.h"
@@ -133,6 +137,41 @@ static const char *err_extra_cmd =
N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments");
+void event_init(void)
+{
+ loop_init(&loop, NULL);
+ // early msgpack-rpc initialization
+ msgpack_rpc_init_method_table();
+ msgpack_rpc_helpers_init();
+ // Initialize input events
+ input_init();
+ // Timer to wake the event loop if a timeout argument is passed to
+ // `event_poll`
+ // Signals
+ signal_init();
+ // finish mspgack-rpc initialization
+ channel_init();
+ server_init();
+ terminal_init();
+}
+
+void event_teardown(void)
+{
+ if (!loop.events) {
+ return;
+ }
+
+ queue_process_events(loop.events);
+ input_stop();
+ channel_teardown();
+ process_teardown(&loop);
+ server_teardown();
+ signal_teardown();
+ terminal_teardown();
+
+ loop_close(&loop);
+}
+
/// Performs early initialization.
///
/// Needed for unit tests. Must be called after `time_init()`.
@@ -482,6 +521,11 @@ int main(int argc, char **argv)
if (restart_edit != 0)
stuffcharReadbuff(K_NOP);
+ // WORKAROUND(mhi): #3023
+ if (cb_flags & CB_UNNAMEDMASK) {
+ (void)eval_has_provider("clipboard");
+ }
+
TIME_MSG("before starting main loop");
/*
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 5d83020619..ed7bda4cce 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -116,5 +116,5 @@ MAP_IMPL(cstr_t, uint64_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
-#define MSGPACK_HANDLER_INITIALIZER {.fn = NULL, .defer = false}
+#define MSGPACK_HANDLER_INITIALIZER {.fn = NULL, .async = false}
MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index f11dc636a3..d90e91be5d 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -587,8 +587,7 @@ void ml_close(buf_T *buf, int del_file)
void ml_close_all(int del_file)
{
FOR_ALL_BUFFERS(buf) {
- ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0
- || vim_strchr(p_cpo, CPO_PRESERVE) == NULL));
+ ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0));
}
spell_delete_wordlist(); /* delete the internal wordlist */
vim_deltempdir(); /* delete created temp directory */
@@ -3935,8 +3934,9 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp)
size += lnum - 1;
/* Don't count the last line break if 'bin' and 'noeol'. */
- if (buf->b_p_bin && !buf->b_p_eol)
+ if (buf->b_p_bin && !buf->b_p_eol && buf->b_ml.ml_line_count == lnum) {
size -= ffdos + 1;
+ }
}
return size;
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 0db0ddffb8..d965de6019 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -417,9 +417,8 @@ add_menu_path (
/* free any old menu */
free_menu_string(menu, i);
- /* For "amenu", may insert an extra character.
- * Don't do this if adding a tearbar (addtearoff == FALSE).
- * Don't do this for "<Nop>". */
+ // For "amenu", may insert an extra character.
+ // Don't do this for "<Nop>".
c = 0;
d = 0;
if (amenu && call_data != NULL && *call_data != NUL
@@ -461,12 +460,6 @@ add_menu_path (
menu->silent[i] = menuarg->silent[0];
}
}
-#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) \
- && (defined(FEAT_BEVAL) || defined(FEAT_GUI_GTK))
- /* Need to update the menu tip. */
- if (modes & MENU_TIP_MODE)
- gui_mch_menu_set_tip(menu);
-#endif
}
return OK;
@@ -571,16 +564,6 @@ remove_menu (
return FAIL;
}
if ((menu->modes & modes) != 0x0) {
-#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
- /*
- * If we are removing all entries for this menu,MENU_ALL_MODES,
- * Then kill any tearoff before we start
- */
- if (*p == NUL && modes == MENU_ALL_MODES) {
- if (IsWindow(menu->tearoff_handle))
- DestroyWindow(menu->tearoff_handle);
- }
-#endif
if (remove_menu(&menu->children, p, modes, silent) == FAIL)
return FAIL;
} else if (*name != NUL) {
@@ -619,29 +602,14 @@ remove_menu (
/* Recalculate modes for menu based on the new updated children */
menu->modes &= ~modes;
-#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
- if ((s_tearoffs) && (menu->children != NULL)) /* there's a tear bar.. */
- child = menu->children->next; /* don't count tearoff bar */
- else
-#endif
child = menu->children;
for (; child != NULL; child = child->next)
menu->modes |= child->modes;
if (modes & MENU_TIP_MODE) {
free_menu_string(menu, MENU_INDEX_TIP);
-#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) \
- && (defined(FEAT_BEVAL) || defined(FEAT_GUI_GTK))
- /* Need to update the menu tip. */
- if (gui.in_use)
- gui_mch_menu_set_tip(menu);
-#endif
}
if ((menu->modes & MENU_ALL_MODES) == 0) {
/* The menu item is no longer valid in ANY mode, so delete it */
-#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
- if (s_tearoffs && menu->children != NULL) /* there's a tear bar.. */
- free_menu(&menu->children);
-#endif
*menup = menu;
free_menu(menup);
}
@@ -862,7 +830,7 @@ char_u *set_context_in_menu_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forc
after_dot = p + 1;
}
- /* ":tearoff" and ":popup" only use menus, not entries */
+ // ":popup" only uses menues, not entries
expand_menus = !((*cmd == 't' && cmd[1] == 'e') || *cmd == 'p');
expand_emenu = (*cmd == 'e');
if (expand_menus && ascii_iswhite(*p))
@@ -938,7 +906,6 @@ char_u *get_menu_name(expand_T *xp, int idx)
/* Skip PopUp[nvoci]. */
while (menu != NULL && (menu_is_hidden(menu->dname)
|| menu_is_separator(menu->dname)
- || menu_is_tearoff(menu->dname)
|| menu->children == NULL))
menu = menu->next;
@@ -986,7 +953,6 @@ char_u *get_menu_names(expand_T *xp, int idx)
while (menu != NULL
&& ( menu_is_hidden(menu->dname)
|| (expand_emenu && menu_is_separator(menu->dname))
- || menu_is_tearoff(menu->dname)
|| menu->dname[STRLEN(menu->dname) - 1] == '.'
))
menu = menu->next;
@@ -1245,16 +1211,6 @@ static int menu_is_hidden(char_u *name)
}
/*
- * Return TRUE if the menu is the tearoff menu.
- */
-static int menu_is_tearoff(char_u *name)
-{
- return FALSE;
-}
-
-
-
-/*
* Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
* execute it.
*/
@@ -1301,11 +1257,15 @@ void ex_emenu(exarg_T *eap)
/* Found the menu, so execute.
* Use the Insert mode entry when returning to Insert mode. */
- if (restart_edit
- && !current_SID
- ) {
+ if (((State & INSERT) || restart_edit) && !current_SID) {
mode = (char_u *)"Insert";
idx = MENU_INDEX_INSERT;
+ } else if (get_real_state() & VISUAL) {
+ /* Detect real visual mode -- if we are really in visual mode we
+ * don't need to do any guesswork to figure out what the selection
+ * is. Just execute the visual binding for the menu. */
+ mode = (char_u *)"Visual";
+ idx = MENU_INDEX_VISUAL;
} else if (eap->addr_count) {
pos_T tpos;
@@ -1364,61 +1324,6 @@ void ex_emenu(exarg_T *eap)
EMSG2(_("E335: Menu not defined for %s mode"), mode);
}
-#if defined(FEAT_GUI_MSWIN) \
- || defined(FEAT_GUI_GTK) \
- || defined(FEAT_BEVAL_TIP)
-/*
- * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy.
- */
-vimmenu_T *gui_find_menu(char_u *path_name)
-{
- vimmenu_T *menu = NULL;
- char_u *name;
- char_u *saved_name;
- char_u *p;
-
- menu = root_menu;
-
- saved_name = vim_strsave(path_name);
-
- name = saved_name;
- while (*name) {
- /* find the end of one dot-separated name and put a NUL at the dot */
- p = menu_name_skip(name);
-
- while (menu != NULL) {
- if (menu_name_equal(name, menu)) {
- if (menu->children == NULL) {
- /* found a menu item instead of a sub-menu */
- if (*p == NUL)
- EMSG(_("E336: Menu path must lead to a sub-menu"));
- else
- EMSG(_(e_notsubmenu));
- menu = NULL;
- goto theend;
- }
- if (*p == NUL) /* found a full match */
- goto theend;
- break;
- }
- menu = menu->next;
- }
- if (menu == NULL) /* didn't find it */
- break;
-
- /* Found a match, search the sub-menu. */
- menu = menu->children;
- name = p;
- }
-
- if (menu == NULL)
- EMSG(_("E337: Menu not found - check menu names"));
-theend:
- xfree(saved_name);
- return menu;
-}
-#endif
-
/*
* Translation of menu names. Just a simple lookup table.
*/
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 5b4c90cc8f..8263ff4896 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -2234,15 +2234,11 @@ void mch_errmsg(char *str)
{
int len;
-#if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI)
+#ifdef UNIX
/* On Unix use stderr if it's a tty.
* When not going to start the GUI also use stderr.
* On Mac, when started from Finder, stderr is the console. */
- if (
-# ifdef UNIX
- isatty(2)
-# endif
- ) {
+ if (os_isatty(2)) {
fprintf(stderr, "%s", str);
return;
}
@@ -2284,16 +2280,12 @@ void mch_errmsg(char *str)
*/
void mch_msg(char *str)
{
-#if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI)
+#ifdef UNIX
/* On Unix use stdout if we have a tty. This allows "vim -h | more" and
* uses mch_errmsg() when started from the desktop.
* When not going to start the GUI also use stdout.
* On Mac, when started from Finder, stderr is the console. */
- if (
-# ifdef UNIX
- isatty(2)
-# endif
- ) {
+ if (os_isatty(2)) {
printf("%s", str);
return;
}
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 0737caec5d..4f23b3da63 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -61,6 +61,7 @@
#include "nvim/os/shell.h"
#include "nvim/os/input.h"
#include "nvim/os/time.h"
+#include "nvim/event/stream.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "misc1.c.generated.h"
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 2a81b4f160..0e3b8200c9 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -9,13 +9,11 @@
#include "nvim/api/vim.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/remote_ui.h"
-#include "nvim/os/event.h"
-#include "nvim/os/rstream.h"
-#include "nvim/os/rstream_defs.h"
-#include "nvim/os/wstream.h"
-#include "nvim/os/wstream_defs.h"
-#include "nvim/os/job.h"
-#include "nvim/os/job_defs.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/uv_process.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
+#include "nvim/event/socket.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
@@ -34,6 +32,12 @@
#define log_server_msg(...)
#endif
+typedef enum {
+ kChannelTypeSocket,
+ kChannelTypeProc,
+ kChannelTypeStdio
+} ChannelType;
+
typedef struct {
uint64_t request_id;
bool returned, errored;
@@ -45,19 +49,26 @@ typedef struct {
size_t refcount;
size_t pending_requests;
PMap(cstr_t) *subscribed_events;
- bool is_job, closed;
+ bool closed;
+ ChannelType type;
msgpack_unpacker *unpacker;
union {
- Job *job;
+ Stream stream;
+ struct {
+ UvProcess uvproc;
+ Stream in;
+ Stream out;
+ Stream err;
+ } process;
struct {
- RStream *read;
- WStream *write;
- uv_stream_t *uv;
- } streams;
+ Stream in;
+ Stream out;
+ } std;
} data;
uint64_t next_request_id;
kvec_t(ChannelCallFrame *) call_stack;
kvec_t(WBuffer *) delayed_notifications;
+ Queue *events;
} Channel;
typedef struct {
@@ -104,57 +115,51 @@ void channel_teardown(void)
});
}
-/// Creates an API channel by starting a job and connecting to its
+/// Creates an API channel by starting a process and connecting to its
/// stdin/stdout. stderr is forwarded to the editor error stream.
///
/// @param argv The argument vector for the process. [consumed]
/// @return The channel id (> 0), on success.
/// 0, on error.
-uint64_t channel_from_job(char **argv)
-{
- Channel *channel = register_channel();
- channel->is_job = true;
- incref(channel); // job channels are only closed by the exit_cb
-
- int status;
- JobOptions opts = JOB_OPTIONS_INIT;
- opts.argv = argv;
- opts.data = channel;
- opts.stdout_cb = job_out;
- opts.stderr_cb = job_err;
- opts.exit_cb = job_exit;
- channel->data.job = job_start(opts, &status);
-
- if (status <= 0) {
- if (status == 0) { // Two decrefs needed if status == 0.
- decref(channel); // Only one needed if status < 0,
- } // because exit_cb will do the second one.
+uint64_t channel_from_process(char **argv)
+{
+ Channel *channel = register_channel(kChannelTypeProc);
+ channel->data.process.uvproc = uv_process_init(&loop, channel);
+ Process *proc = &channel->data.process.uvproc.process;
+ proc->argv = argv;
+ proc->in = &channel->data.process.in;
+ proc->out = &channel->data.process.out;
+ proc->err = &channel->data.process.err;
+ proc->cb = process_exit;
+ if (!process_spawn(proc)) {
+ loop_poll_events(&loop, 0);
decref(channel);
return 0;
}
+ incref(channel); // process channels are only closed by the exit_cb
+ wstream_init(proc->in, 0);
+ rstream_init(proc->out, 0);
+ rstream_start(proc->out, parse_msgpack);
+ rstream_init(proc->err, 0);
+ rstream_start(proc->err, forward_stderr);
+
return channel->id;
}
-/// Creates an API channel from a libuv stream representing a tcp or
-/// pipe/socket client connection
+/// Creates an API channel from a tcp/pipe socket connection
///
-/// @param stream The established connection
-void channel_from_stream(uv_stream_t *stream)
+/// @param watcher The SocketWatcher ready to accept the connection
+void channel_from_connection(SocketWatcher *watcher)
{
- Channel *channel = register_channel();
- stream->data = NULL;
- channel->is_job = false;
- // read stream
- channel->data.streams.read = rstream_new(parse_msgpack,
- rbuffer_new(CHANNEL_BUFFER_SIZE),
- channel);
- rstream_set_stream(channel->data.streams.read, stream);
- rstream_start(channel->data.streams.read);
- // write stream
- channel->data.streams.write = wstream_new(0);
- wstream_set_stream(channel->data.streams.write, stream);
- channel->data.streams.uv = stream;
+ Channel *channel = register_channel(kChannelTypeSocket);
+ socket_watcher_accept(watcher, &channel->data.stream, channel);
+ incref(channel); // close channel only after the stream is closed
+ channel->data.stream.internal_close_cb = close_cb;
+ channel->data.stream.internal_data = channel;
+ wstream_init(&channel->data.stream, 0);
+ rstream_init(&channel->data.stream, CHANNEL_BUFFER_SIZE);
+ rstream_start(&channel->data.stream, parse_msgpack);
}
/// Sends event/arguments to channel
@@ -220,7 +225,7 @@ Object channel_send_call(uint64_t id,
ChannelCallFrame frame = {request_id, false, false, NIL};
kv_push(ChannelCallFrame *, channel->call_stack, &frame);
channel->pending_requests++;
- event_poll_until(-1, frame.returned);
+ LOOP_PROCESS_EVENTS_UNTIL(&loop, channel->events, -1, frame.returned);
(void)kv_pop(channel->call_stack);
channel->pending_requests--;
@@ -313,44 +318,34 @@ bool channel_close(uint64_t id)
/// Neovim
static void channel_from_stdio(void)
{
- Channel *channel = register_channel();
+ Channel *channel = register_channel(kChannelTypeStdio);
incref(channel); // stdio channels are only closed on exit
- channel->is_job = false;
// read stream
- channel->data.streams.read = rstream_new(parse_msgpack,
- rbuffer_new(CHANNEL_BUFFER_SIZE),
- channel);
- rstream_set_file(channel->data.streams.read, 0);
- rstream_start(channel->data.streams.read);
+ rstream_init_fd(&loop, &channel->data.std.in, 0, CHANNEL_BUFFER_SIZE,
+ channel);
+ rstream_start(&channel->data.std.in, parse_msgpack);
// write stream
- channel->data.streams.write = wstream_new(0);
- wstream_set_file(channel->data.streams.write, 1);
- channel->data.streams.uv = NULL;
+ wstream_init_fd(&loop, &channel->data.std.out, 1, 0, NULL);
}
-static void job_out(RStream *rstream, RBuffer *buf, void *data, bool eof)
-{
- Job *job = data;
- parse_msgpack(rstream, buf, job_data(job), eof);
-}
-
-static void job_err(RStream *rstream, RBuffer *rbuf, void *data, bool eof)
+static void forward_stderr(Stream *stream, RBuffer *rbuf, size_t count,
+ void *data, bool eof)
{
while (rbuffer_size(rbuf)) {
char buf[256];
size_t read = rbuffer_read(rbuf, buf, sizeof(buf) - 1);
buf[read] = NUL;
- ELOG("Channel %" PRIu64 " stderr: %s",
- ((Channel *)job_data(data))->id, buf);
+ ELOG("Channel %" PRIu64 " stderr: %s", ((Channel *)data)->id, buf);
}
}
-static void job_exit(Job *job, int status, void *data)
+static void process_exit(Process *proc, int status, void *data)
{
decref(data);
}
-static void parse_msgpack(RStream *rstream, RBuffer *rbuf, void *data, bool eof)
+static void parse_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data,
+ bool eof)
{
Channel *channel = data;
incref(channel);
@@ -362,9 +357,9 @@ static void parse_msgpack(RStream *rstream, RBuffer *rbuf, void *data, bool eof)
}
size_t count = rbuffer_size(rbuf);
- DLOG("Feeding the msgpack parser with %u bytes of data from RStream(%p)",
+ DLOG("Feeding the msgpack parser with %u bytes of data from Stream(%p)",
count,
- rstream);
+ stream);
// Feed the unpacker with data
msgpack_unpacker_reserve_buffer(channel->unpacker, count);
@@ -458,31 +453,31 @@ static void handle_request(Channel *channel, msgpack_object *request)
method->via.bin.size);
} else {
handler.fn = msgpack_rpc_handle_missing_method;
- handler.defer = false;
+ handler.async = true;
}
Array args = ARRAY_DICT_INIT;
if (!msgpack_rpc_to_array(msgpack_rpc_args(request), &args)) {
handler.fn = msgpack_rpc_handle_invalid_arguments;
- handler.defer = false;
+ handler.async = true;
}
- bool defer = (!kv_size(channel->call_stack) && handler.defer);
RequestEvent *event_data = xmalloc(sizeof(RequestEvent));
event_data->channel = channel;
event_data->handler = handler;
event_data->args = args;
event_data->request_id = request_id;
incref(channel);
- event_push((Event) {
- .handler = on_request_event,
- .data = event_data
- }, defer);
+ if (handler.async) {
+ on_request_event((void **)&event_data);
+ } else {
+ queue_put(channel->events, on_request_event, 1, event_data);
+ }
}
-static void on_request_event(Event event)
+static void on_request_event(void **argv)
{
- RequestEvent *e = event.data;
+ RequestEvent *e = argv[0];
Channel *channel = e->channel;
MsgpackRpcRequestHandler handler = e->handler;
Array args = e->args;
@@ -516,10 +511,18 @@ static bool channel_write(Channel *channel, WBuffer *buffer)
return false;
}
- if (channel->is_job) {
- success = job_write(channel->data.job, buffer);
- } else {
- success = wstream_write(channel->data.streams.write, buffer);
+ switch (channel->type) {
+ case kChannelTypeSocket:
+ success = wstream_write(&channel->data.stream, buffer);
+ break;
+ case kChannelTypeProc:
+ success = wstream_write(&channel->data.process.in, buffer);
+ break;
+ case kChannelTypeStdio:
+ success = wstream_write(&channel->data.std.out, buffer);
+ break;
+ default:
+ abort();
}
if (!success) {
@@ -628,7 +631,7 @@ static void unsubscribe(Channel *channel, char *event)
xfree(event_string);
}
-/// Close the channel streams/job and free the channel resources.
+/// Close the channel streams/process and free the channel resources.
static void close_channel(Channel *channel)
{
if (channel->closed) {
@@ -637,27 +640,30 @@ static void close_channel(Channel *channel)
channel->closed = true;
- if (channel->is_job) {
- if (channel->data.job) {
- job_stop(channel->data.job);
- }
- } else {
- rstream_free(channel->data.streams.read);
- wstream_free(channel->data.streams.write);
- uv_handle_t *handle = (uv_handle_t *)channel->data.streams.uv;
- if (handle) {
- uv_close(handle, close_cb);
- } else {
- event_push((Event) { .handler = on_stdio_close, .data = channel }, false);
- }
+ switch (channel->type) {
+ case kChannelTypeSocket:
+ stream_close(&channel->data.stream, NULL);
+ break;
+ case kChannelTypeProc:
+ if (!channel->data.process.uvproc.process.closed) {
+ process_stop(&channel->data.process.uvproc.process);
+ }
+ break;
+ case kChannelTypeStdio:
+ stream_close(&channel->data.std.in, NULL);
+ stream_close(&channel->data.std.out, NULL);
+ queue_put(loop.fast_events, exit_event, 1, channel);
+ return;
+ default:
+ abort();
}
decref(channel);
}
-static void on_stdio_close(Event e)
+static void exit_event(void **argv)
{
- decref(e.data);
+ decref(argv[0]);
if (!exiting) {
mch_exit(0);
@@ -679,18 +685,20 @@ static void free_channel(Channel *channel)
pmap_free(cstr_t)(channel->subscribed_events);
kv_destroy(channel->call_stack);
kv_destroy(channel->delayed_notifications);
+ queue_free(channel->events);
xfree(channel);
}
-static void close_cb(uv_handle_t *handle)
+static void close_cb(Stream *stream, void *data)
{
- xfree(handle->data);
- xfree(handle);
+ decref(data);
}
-static Channel *register_channel(void)
+static Channel *register_channel(ChannelType type)
{
Channel *rv = xmalloc(sizeof(Channel));
+ rv->events = queue_new_child(loop.events);
+ rv->type = type;
rv->refcount = 1;
rv->closed = false;
rv->unpacker = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
diff --git a/src/nvim/msgpack_rpc/channel.h b/src/nvim/msgpack_rpc/channel.h
index df742fe368..104547a7b8 100644
--- a/src/nvim/msgpack_rpc/channel.h
+++ b/src/nvim/msgpack_rpc/channel.h
@@ -5,6 +5,7 @@
#include <uv.h>
#include "nvim/api/private/defs.h"
+#include "nvim/event/socket.h"
#include "nvim/vim.h"
#define METHOD_MAXLEN 512
diff --git a/src/nvim/msgpack_rpc/defs.h b/src/nvim/msgpack_rpc/defs.h
index 0492a65290..d97cf28ca1 100644
--- a/src/nvim/msgpack_rpc/defs.h
+++ b/src/nvim/msgpack_rpc/defs.h
@@ -11,9 +11,8 @@ typedef struct {
uint64_t request_id,
Array args,
Error *error);
- bool defer; // Should the call be deferred to the main loop? This should
- // be true if the function mutates editor data structures such
- // as buffers, windows, tabs, or if it executes vimscript code.
+ bool async; // function is always safe to run immediately instead of being
+ // put in a request queue for handling when nvim waits for input.
} MsgpackRpcRequestHandler;
/// Initializes the msgpack-rpc method table
diff --git a/src/nvim/msgpack_rpc/helpers.h b/src/nvim/msgpack_rpc/helpers.h
index bf161d54e0..7d9f114140 100644
--- a/src/nvim/msgpack_rpc/helpers.h
+++ b/src/nvim/msgpack_rpc/helpers.h
@@ -6,7 +6,7 @@
#include <msgpack.h>
-#include "nvim/os/wstream.h"
+#include "nvim/event/wstream.h"
#include "nvim/api/private/defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/msgpack_rpc/remote_ui.c
index 07d78dd9d7..3334b0e6af 100644
--- a/src/nvim/msgpack_rpc/remote_ui.c
+++ b/src/nvim/msgpack_rpc/remote_ui.c
@@ -28,7 +28,7 @@ void remote_ui_init(void)
connected_uis = pmap_new(uint64_t)();
// Add handler for "attach_ui"
String method = cstr_as_string("ui_attach");
- MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .defer = false};
+ MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .async = true};
msgpack_rpc_add_method_handler(method, handler);
method = cstr_as_string("ui_detach");
handler.fn = remote_ui_detach;
@@ -86,8 +86,7 @@ static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id,
ui->busy_stop = remote_ui_busy_stop;
ui->mouse_on = remote_ui_mouse_on;
ui->mouse_off = remote_ui_mouse_off;
- ui->insert_mode = remote_ui_insert_mode;
- ui->normal_mode = remote_ui_normal_mode;
+ ui->mode_change = remote_ui_mode_change;
ui->set_scroll_region = remote_ui_set_scroll_region;
ui->scroll = remote_ui_scroll;
ui->highlight_set = remote_ui_highlight_set;
@@ -214,16 +213,18 @@ static void remote_ui_mouse_off(UI *ui)
push_call(ui, "mouse_off", args);
}
-static void remote_ui_insert_mode(UI *ui)
+static void remote_ui_mode_change(UI *ui, int mode)
{
Array args = ARRAY_DICT_INIT;
- push_call(ui, "insert_mode", args);
-}
-
-static void remote_ui_normal_mode(UI *ui)
-{
- Array args = ARRAY_DICT_INIT;
- push_call(ui, "normal_mode", args);
+ if (mode == INSERT) {
+ ADD(args, STRING_OBJ(cstr_to_string("insert")));
+ } else if (mode == REPLACE) {
+ ADD(args, STRING_OBJ(cstr_to_string("replace")));
+ } else {
+ assert(mode == NORMAL);
+ ADD(args, STRING_OBJ(cstr_to_string("normal")));
+ }
+ push_call(ui, "mode_change", args);
}
static void remote_ui_set_scroll_region(UI *ui, int top, int bot, int left,
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 388b5a04cf..8dffea35ca 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -3,11 +3,10 @@
#include <string.h>
#include <stdint.h>
-#include <uv.h>
-
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/server.h"
#include "nvim/os/os.h"
+#include "nvim/event/socket.h"
#include "nvim/ascii.h"
#include "nvim/eval.h"
#include "nvim/garray.h"
@@ -19,35 +18,9 @@
#include "nvim/strings.h"
#define MAX_CONNECTIONS 32
-#define ADDRESS_MAX_SIZE 256
-#define NVIM_DEFAULT_TCP_PORT 7450
#define LISTEN_ADDRESS_ENV_VAR "NVIM_LISTEN_ADDRESS"
-typedef enum {
- kServerTypeTcp,
- kServerTypePipe
-} ServerType;
-
-typedef struct {
- // Pipe/socket path, or TCP address string
- char addr[ADDRESS_MAX_SIZE];
-
- // Type of the union below
- ServerType type;
-
- // TCP server or unix socket (named pipe on Windows)
- union {
- struct {
- uv_tcp_t handle;
- struct sockaddr_in addr;
- } tcp;
- struct {
- uv_pipe_t handle;
- } pipe;
- } socket;
-} Server;
-
-static garray_T servers = GA_EMPTY_INIT_VALUE;
+static garray_T watchers = GA_EMPTY_INIT_VALUE;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "msgpack_rpc/server.c.generated.h"
@@ -56,7 +29,7 @@ static garray_T servers = GA_EMPTY_INIT_VALUE;
/// Initializes the module
bool server_init(void)
{
- ga_init(&servers, sizeof(Server *), 1);
+ ga_init(&watchers, sizeof(SocketWatcher *), 1);
bool must_free = false;
const char *listen_address = os_getenv(LISTEN_ADDRESS_ENV_VAR);
@@ -72,18 +45,10 @@ bool server_init(void)
return ok;
}
-/// Retrieve the file handle from a server.
-static uv_handle_t *server_handle(Server *server)
-{
- return server->type == kServerTypeTcp
- ? (uv_handle_t *)&server->socket.tcp.handle
- : (uv_handle_t *) &server->socket.pipe.handle;
-}
-
/// Teardown a single server
-static void server_close_cb(Server **server)
+static void close_socket_watcher(SocketWatcher **watcher)
{
- uv_close(server_handle(*server), free_server);
+ socket_watcher_close(*watcher, free_server);
}
/// Set v:servername to the first server in the server list, or unset it if no
@@ -91,7 +56,7 @@ static void server_close_cb(Server **server)
static void set_vservername(garray_T *srvs)
{
char *default_server = (srvs->ga_len > 0)
- ? ((Server **)srvs->ga_data)[0]->addr
+ ? ((SocketWatcher **)srvs->ga_data)[0]->addr
: NULL;
set_vim_var_string(VV_SEND_SERVER, (char_u *)default_server, -1);
}
@@ -99,7 +64,7 @@ static void set_vservername(garray_T *srvs)
/// Teardown the server module
void server_teardown(void)
{
- GA_DEEP_CLEAR(&servers, Server *, server_close_cb);
+ GA_DEEP_CLEAR(&watchers, SocketWatcher *, close_socket_watcher);
}
/// Starts listening for API calls on the TCP address or pipe path `endpoint`.
@@ -116,120 +81,38 @@ void server_teardown(void)
int server_start(const char *endpoint)
FUNC_ATTR_NONNULL_ALL
{
- char addr[ADDRESS_MAX_SIZE];
-
- // Trim to `ADDRESS_MAX_SIZE`
- if (xstrlcpy(addr, endpoint, sizeof(addr)) >= sizeof(addr)) {
- // TODO(aktau): since this is not what the user wanted, perhaps we
- // should return an error here
- WLOG("Address was too long, truncated to %s", addr);
- }
-
- // Check if the server already exists
- for (int i = 0; i < servers.ga_len; i++) {
- if (strcmp(addr, ((Server **)servers.ga_data)[i]->addr) == 0) {
- ELOG("Already listening on %s", addr);
+ SocketWatcher *watcher = xmalloc(sizeof(SocketWatcher));
+ socket_watcher_init(&loop, watcher, endpoint, NULL);
+
+ // Check if a watcher for the endpoint already exists
+ for (int i = 0; i < watchers.ga_len; i++) {
+ if (!strcmp(watcher->addr, ((SocketWatcher **)watchers.ga_data)[i]->addr)) {
+ ELOG("Already listening on %s", watcher->addr);
+ socket_watcher_close(watcher, free_server);
return 1;
}
}
- ServerType server_type = kServerTypeTcp;
- Server *server = xmalloc(sizeof(Server));
- char ip[16], *ip_end = strrchr(addr, ':');
-
- if (!ip_end) {
- ip_end = strchr(addr, NUL);
- }
-
- // (ip_end - addr) is always > 0, so convert to size_t
- size_t addr_len = (size_t)(ip_end - addr);
-
- if (addr_len > sizeof(ip) - 1) {
- // Maximum length of an IPv4 address buffer is 15 (eg: 255.255.255.255)
- addr_len = sizeof(ip) - 1;
- }
-
- // Extract the address part
- xstrlcpy(ip, addr, addr_len + 1);
-
- int port = NVIM_DEFAULT_TCP_PORT;
-
- if (*ip_end == ':') {
- // Extract the port
- long lport = strtol(ip_end + 1, NULL, 10); // NOLINT
- if (lport <= 0 || lport > 0xffff) {
- // Invalid port, treat as named pipe or unix socket
- server_type = kServerTypePipe;
- } else {
- port = (int) lport;
- }
- }
-
- if (server_type == kServerTypeTcp) {
- // Try to parse ip address
- if (uv_ip4_addr(ip, port, &server->socket.tcp.addr)) {
- // Invalid address, treat as named pipe or unix socket
- server_type = kServerTypePipe;
- }
- }
-
- int result;
- uv_stream_t *stream = NULL;
-
- xstrlcpy(server->addr, addr, sizeof(server->addr));
-
- if (server_type == kServerTypeTcp) {
- // Listen on tcp address/port
- uv_tcp_init(uv_default_loop(), &server->socket.tcp.handle);
- result = uv_tcp_bind(&server->socket.tcp.handle,
- (const struct sockaddr *)&server->socket.tcp.addr,
- 0);
- stream = (uv_stream_t *)&server->socket.tcp.handle;
- } else {
- // Listen on named pipe or unix socket
- uv_pipe_init(uv_default_loop(), &server->socket.pipe.handle, 0);
- result = uv_pipe_bind(&server->socket.pipe.handle, server->addr);
- stream = (uv_stream_t *)&server->socket.pipe.handle;
- }
-
- stream->data = server;
-
- if (result == 0) {
- result = uv_listen((uv_stream_t *)&server->socket.tcp.handle,
- MAX_CONNECTIONS,
- connection_cb);
- }
-
- assert(result <= 0); // libuv should have returned -errno or zero.
+ int result = socket_watcher_start(watcher, MAX_CONNECTIONS, connection_cb);
if (result < 0) {
- if (result == -EACCES) {
- // Libuv converts ENOENT to EACCES for Windows compatibility, but if
- // the parent directory does not exist, ENOENT would be more accurate.
- *path_tail((char_u *) addr) = NUL;
- if (!os_file_exists((char_u *) addr)) {
- result = -ENOENT;
- }
- }
- uv_close((uv_handle_t *)stream, free_server);
ELOG("Failed to start server: %s", uv_strerror(result));
+ socket_watcher_close(watcher, free_server);
return result;
}
// Update $NVIM_LISTEN_ADDRESS, if not set.
const char *listen_address = os_getenv(LISTEN_ADDRESS_ENV_VAR);
if (listen_address == NULL) {
- os_setenv(LISTEN_ADDRESS_ENV_VAR, addr, 1);
+ os_setenv(LISTEN_ADDRESS_ENV_VAR, watcher->addr, 1);
}
- server->type = server_type;
-
- // Add the server to the list.
- ga_grow(&servers, 1);
- ((Server **)servers.ga_data)[servers.ga_len++] = server;
+ // Add the watcher to the list.
+ ga_grow(&watchers, 1);
+ ((SocketWatcher **)watchers.ga_data)[watchers.ga_len++] = watcher;
// Update v:servername, if not set.
if (STRLEN(get_vim_var_str(VV_SEND_SERVER)) == 0) {
- set_vservername(&servers);
+ set_vservername(&watchers);
}
return 0;
@@ -240,21 +123,21 @@ int server_start(const char *endpoint)
/// @param endpoint Address of the server.
void server_stop(char *endpoint)
{
- Server *server;
+ SocketWatcher *watcher;
char addr[ADDRESS_MAX_SIZE];
// Trim to `ADDRESS_MAX_SIZE`
xstrlcpy(addr, endpoint, sizeof(addr));
int i = 0; // Index of the server whose address equals addr.
- for (; i < servers.ga_len; i++) {
- server = ((Server **)servers.ga_data)[i];
- if (strcmp(addr, server->addr) == 0) {
+ for (; i < watchers.ga_len; i++) {
+ watcher = ((SocketWatcher **)watchers.ga_data)[i];
+ if (strcmp(addr, watcher->addr) == 0) {
break;
}
}
- if (i >= servers.ga_len) {
+ if (i >= watchers.ga_len) {
ELOG("Not listening on %s", addr);
return;
}
@@ -265,18 +148,18 @@ void server_stop(char *endpoint)
os_unsetenv(LISTEN_ADDRESS_ENV_VAR);
}
- uv_close(server_handle(server), free_server);
+ socket_watcher_close(watcher, free_server);
// Remove this server from the list by swapping it with the last item.
- if (i != servers.ga_len - 1) {
- ((Server **)servers.ga_data)[i] =
- ((Server **)servers.ga_data)[servers.ga_len - 1];
+ if (i != watchers.ga_len - 1) {
+ ((SocketWatcher **)watchers.ga_data)[i] =
+ ((SocketWatcher **)watchers.ga_data)[watchers.ga_len - 1];
}
- servers.ga_len--;
+ watchers.ga_len--;
// If v:servername is the stopped address, re-initialize it.
if (STRCMP(addr, get_vim_var_str(VV_SEND_SERVER)) == 0) {
- set_vservername(&servers);
+ set_vservername(&watchers);
}
}
@@ -285,52 +168,28 @@ void server_stop(char *endpoint)
char **server_address_list(size_t *size)
FUNC_ATTR_NONNULL_ALL
{
- if ((*size = (size_t) servers.ga_len) == 0) {
+ if ((*size = (size_t)watchers.ga_len) == 0) {
return NULL;
}
- char **addrs = xcalloc((size_t) servers.ga_len, sizeof(const char *));
- for (int i = 0; i < servers.ga_len; i++) {
- addrs[i] = xstrdup(((Server **)servers.ga_data)[i]->addr);
+ char **addrs = xcalloc((size_t)watchers.ga_len, sizeof(const char *));
+ for (int i = 0; i < watchers.ga_len; i++) {
+ addrs[i] = xstrdup(((SocketWatcher **)watchers.ga_data)[i]->addr);
}
return addrs;
}
-static void connection_cb(uv_stream_t *server, int status)
+static void connection_cb(SocketWatcher *watcher, int result, void *data)
{
- int result;
- uv_stream_t *client;
- Server *srv = server->data;
-
- if (status < 0) {
- abort();
- }
-
- if (srv->type == kServerTypeTcp) {
- client = xmalloc(sizeof(uv_tcp_t));
- uv_tcp_init(uv_default_loop(), (uv_tcp_t *)client);
- } else {
- client = xmalloc(sizeof(uv_pipe_t));
- uv_pipe_init(uv_default_loop(), (uv_pipe_t *)client, 0);
- }
-
- result = uv_accept(server, client);
-
if (result) {
ELOG("Failed to accept connection: %s", uv_strerror(result));
- uv_close((uv_handle_t *)client, free_client);
return;
}
- channel_from_stream(client);
-}
-
-static void free_client(uv_handle_t *handle)
-{
- xfree(handle);
+ channel_from_connection(watcher);
}
-static void free_server(uv_handle_t *handle)
+static void free_server(SocketWatcher *watcher, void *data)
{
- xfree(handle->data);
+ xfree(watcher);
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 92734e404a..5b35af9209 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -61,8 +61,9 @@
#include "nvim/mouse.h"
#include "nvim/undo.h"
#include "nvim/window.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
#include "nvim/os/time.h"
+#include "nvim/os/input.h"
/*
* The Visual area is remembered for reselection.
@@ -487,12 +488,12 @@ normal_cmd (
/*
* Get the command character from the user.
*/
- event_enable_deferred();
+ input_enable_events();
c = safe_vgetc();
- event_disable_deferred();
+ input_disable_events();
if (c == K_EVENT) {
- event_process();
+ queue_process_events(loop.events);
return;
}
@@ -2016,6 +2017,9 @@ do_mouse (
if (regname == '.')
insert_reg(regname, true);
else {
+ if (regname == 0 && eval_has_provider("clipboard")) {
+ regname = '*';
+ }
if ((State & REPLACE_FLAG) && !yank_register_mline(regname))
insert_reg(regname, true);
else {
@@ -2105,11 +2109,6 @@ do_mouse (
* NOTE: Ignore right button down and drag mouse events.
* Windows only shows the popup menu on the button up event.
*/
-#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
- || defined(FEAT_GUI_MAC)
- if (!is_click)
- return false;
-#endif
return false;
}
if (which_button == MOUSE_LEFT
@@ -2284,6 +2283,9 @@ do_mouse (
* Middle mouse click: Put text before cursor.
*/
if (which_button == MOUSE_MIDDLE) {
+ if (regname == 0 && eval_has_provider("clipboard")) {
+ regname = '*';
+ }
if (yank_register_mline(regname)) {
if (mouse_past_bottom)
dir = FORWARD;
@@ -5740,22 +5742,10 @@ static void nv_optrans(cmdarg_T *cap)
static char_u *str = (char_u *)"xXDCsSY&";
if (!checkclearopq(cap->oap)) {
- /* In Vi "2D" doesn't delete the next line. Can't translate it
- * either, because "2." should also not use the count. */
- if (cap->cmdchar == 'D' && vim_strchr(p_cpo, CPO_HASH) != NULL) {
- cap->oap->start = curwin->w_cursor;
- cap->oap->op_type = OP_DELETE;
- set_op_var(OP_DELETE);
- cap->count1 = 1;
- nv_dollar(cap);
- finish_op = true;
- ResetRedobuff();
- AppendCharToRedobuff('D');
- } else {
- if (cap->count0)
- stuffnumReadbuff(cap->count0);
- stuffReadbuff(ar[(int)(vim_strchr(str, cap->cmdchar) - str)]);
+ if (cap->count0) {
+ stuffnumReadbuff(cap->count0);
}
+ stuffReadbuff(ar[(int)(vim_strchr(str, cap->cmdchar) - str)]);
}
cap->opcount = 0;
}
@@ -6553,9 +6543,6 @@ static void n_opencmd(cmdarg_T *cap)
0, 0)) {
if (curwin->w_p_cole > 0 && oldline != curwin->w_cursor.lnum)
update_single_line(curwin, oldline);
- /* When '#' is in 'cpoptions' ignore the count. */
- if (vim_strchr(p_cpo, CPO_HASH) != NULL)
- cap->count1 = 1;
invoke_edit(cap, false, cap->cmdchar, true);
}
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 063ad154f1..766b5720d9 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -765,7 +765,10 @@ yankreg_T *get_yank_register(int regname, int mode)
if (mode == YREG_PASTE && get_clipboard(regname, &reg, false)) {
// reg is set to clipboard contents.
return reg;
- } else if (mode != YREG_YANK && (regname == 0 || regname == '"') && y_previous != NULL) {
+ } else if (mode != YREG_YANK
+ && (regname == 0 || regname == '"' || regname == '*' || regname == '+')
+ && y_previous != NULL) {
+ // in case clipboard not available, paste from previous used register
return y_previous;
}
@@ -5275,11 +5278,11 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet)
}
yankreg_T *target;
if (cb_flags & CB_UNNAMEDPLUS) {
- *name = '+';
- target = &y_regs[STAR_REGISTER];
+ *name = cb_flags & CB_UNNAMED ? '"': '+';
+ target = &y_regs[PLUS_REGISTER];
} else {
*name = '*';
- target = &y_regs[PLUS_REGISTER];
+ target = &y_regs[STAR_REGISTER];
}
return target; // unnamed register
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 113c47f112..9a375c0675 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -97,121 +97,6 @@
#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x))
#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x))
-/*
- * Definition of the PV_ values for buffer-local options.
- * The BV_ values are defined in option_defs.h.
- */
-#define PV_AI OPT_BUF(BV_AI)
-#define PV_AR OPT_BOTH(OPT_BUF(BV_AR))
-#define PV_BKC OPT_BOTH(OPT_BUF(BV_BKC))
-# define PV_BH OPT_BUF(BV_BH)
-# define PV_BT OPT_BUF(BV_BT)
-# define PV_EFM OPT_BOTH(OPT_BUF(BV_EFM))
-# define PV_GP OPT_BOTH(OPT_BUF(BV_GP))
-# define PV_MP OPT_BOTH(OPT_BUF(BV_MP))
-#define PV_BIN OPT_BUF(BV_BIN)
-#define PV_BL OPT_BUF(BV_BL)
-# define PV_BOMB OPT_BUF(BV_BOMB)
-#define PV_CI OPT_BUF(BV_CI)
-# define PV_CIN OPT_BUF(BV_CIN)
-# define PV_CINK OPT_BUF(BV_CINK)
-# define PV_CINO OPT_BUF(BV_CINO)
-# define PV_CINW OPT_BUF(BV_CINW)
-#define PV_CM OPT_BOTH(OPT_BUF(BV_CM))
-# define PV_CMS OPT_BUF(BV_CMS)
-# define PV_COM OPT_BUF(BV_COM)
-# define PV_CPT OPT_BUF(BV_CPT)
-# define PV_DICT OPT_BOTH(OPT_BUF(BV_DICT))
-# define PV_TSR OPT_BOTH(OPT_BUF(BV_TSR))
-# define PV_CFU OPT_BUF(BV_CFU)
-# define PV_DEF OPT_BOTH(OPT_BUF(BV_DEF))
-# define PV_INC OPT_BOTH(OPT_BUF(BV_INC))
-#define PV_EOL OPT_BUF(BV_EOL)
-#define PV_EP OPT_BOTH(OPT_BUF(BV_EP))
-#define PV_ET OPT_BUF(BV_ET)
-# define PV_FENC OPT_BUF(BV_FENC)
-# define PV_FEX OPT_BUF(BV_FEX)
-#define PV_FF OPT_BUF(BV_FF)
-#define PV_FLP OPT_BUF(BV_FLP)
-#define PV_FO OPT_BUF(BV_FO)
-# define PV_FT OPT_BUF(BV_FT)
-#define PV_IMI OPT_BUF(BV_IMI)
-#define PV_IMS OPT_BUF(BV_IMS)
-# define PV_INDE OPT_BUF(BV_INDE)
-# define PV_INDK OPT_BUF(BV_INDK)
-# define PV_INEX OPT_BUF(BV_INEX)
-#define PV_INF OPT_BUF(BV_INF)
-#define PV_ISK OPT_BUF(BV_ISK)
-# define PV_KMAP OPT_BUF(BV_KMAP)
-#define PV_KP OPT_BOTH(OPT_BUF(BV_KP))
-# define PV_LISP OPT_BUF(BV_LISP)
-# define PV_LW OPT_BOTH(OPT_BUF(BV_LW))
-#define PV_MA OPT_BUF(BV_MA)
-#define PV_ML OPT_BUF(BV_ML)
-#define PV_MOD OPT_BUF(BV_MOD)
-#define PV_MPS OPT_BUF(BV_MPS)
-#define PV_NF OPT_BUF(BV_NF)
-# define PV_OFU OPT_BUF(BV_OFU)
-#define PV_PATH OPT_BOTH(OPT_BUF(BV_PATH))
-#define PV_PI OPT_BUF(BV_PI)
-# define PV_QE OPT_BUF(BV_QE)
-#define PV_RO OPT_BUF(BV_RO)
-# define PV_SI OPT_BUF(BV_SI)
-# define PV_SMC OPT_BUF(BV_SMC)
-# define PV_SYN OPT_BUF(BV_SYN)
-# define PV_SPC OPT_BUF(BV_SPC)
-# define PV_SPF OPT_BUF(BV_SPF)
-# define PV_SPL OPT_BUF(BV_SPL)
-#define PV_STS OPT_BUF(BV_STS)
-# define PV_SUA OPT_BUF(BV_SUA)
-#define PV_SW OPT_BUF(BV_SW)
-#define PV_SWF OPT_BUF(BV_SWF)
-#define PV_TAGS OPT_BOTH(OPT_BUF(BV_TAGS))
-#define PV_TS OPT_BUF(BV_TS)
-#define PV_TW OPT_BUF(BV_TW)
-# define PV_UDF OPT_BUF(BV_UDF)
-#define PV_WM OPT_BUF(BV_WM)
-
-/*
- * Definition of the PV_ values for window-local options.
- * The WV_ values are defined in option_defs.h.
- */
-#define PV_LIST OPT_WIN(WV_LIST)
-# define PV_ARAB OPT_WIN(WV_ARAB)
-# define PV_BRI OPT_WIN(WV_BRI)
-# define PV_BRIOPT OPT_WIN(WV_BRIOPT)
-# define PV_DIFF OPT_WIN(WV_DIFF)
-# define PV_FDC OPT_WIN(WV_FDC)
-# define PV_FEN OPT_WIN(WV_FEN)
-# define PV_FDI OPT_WIN(WV_FDI)
-# define PV_FDL OPT_WIN(WV_FDL)
-# define PV_FDM OPT_WIN(WV_FDM)
-# define PV_FML OPT_WIN(WV_FML)
-# define PV_FDN OPT_WIN(WV_FDN)
-# define PV_FDE OPT_WIN(WV_FDE)
-# define PV_FDT OPT_WIN(WV_FDT)
-# define PV_FMR OPT_WIN(WV_FMR)
-# define PV_LBR OPT_WIN(WV_LBR)
-#define PV_NU OPT_WIN(WV_NU)
-#define PV_RNU OPT_WIN(WV_RNU)
-# define PV_NUW OPT_WIN(WV_NUW)
-# define PV_PVW OPT_WIN(WV_PVW)
-# define PV_RL OPT_WIN(WV_RL)
-# define PV_RLC OPT_WIN(WV_RLC)
-# define PV_SCBIND OPT_WIN(WV_SCBIND)
-#define PV_SCROLL OPT_WIN(WV_SCROLL)
-# define PV_SPELL OPT_WIN(WV_SPELL)
-# define PV_CUC OPT_WIN(WV_CUC)
-# define PV_CUL OPT_WIN(WV_CUL)
-# define PV_CC OPT_WIN(WV_CC)
-# define PV_STL OPT_BOTH(OPT_WIN(WV_STL))
-#define PV_UL OPT_BOTH(OPT_BUF(BV_UL))
-# define PV_WFH OPT_WIN(WV_WFH)
-# define PV_WFW OPT_WIN(WV_WFW)
-#define PV_WRAP OPT_WIN(WV_WRAP)
-# define PV_CRBIND OPT_WIN(WV_CRBIND)
-# define PV_COCU OPT_WIN(WV_COCU)
-# define PV_COLE OPT_WIN(WV_COLE)
/* WV_ and BV_ values get typecasted to this for the "indir" field */
typedef enum {
@@ -380,1303 +265,10 @@ typedef struct vimoption {
* The options with a NULL variable are 'hidden': a set command for them is
* ignored and they are not printed.
*/
-static vimoption_T
- options[] =
-{
- {"aleph", "al", P_NUM|P_VI_DEF|P_CURSWANT,
- (char_u *)&p_aleph, PV_NONE,
- {
- (char_u *)224L,
- (char_u *)0L
- } SCRIPTID_INIT},
- {"antialias", "anti", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
- (char_u *)NULL, PV_NONE,
- {(char_u *)FALSE, (char_u *)FALSE}
- SCRIPTID_INIT},
- {"arabic", "arab", P_BOOL|P_VI_DEF|P_VIM|P_CURSWANT,
- VAR_WIN, PV_ARAB,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"arabicshape", "arshape", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
- (char_u *)&p_arshape, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"allowrevins", "ari", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_ari, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"altkeymap", "akm", P_BOOL|P_VI_DEF,
- (char_u *)&p_altkeymap, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"ambiwidth", "ambw", P_STRING|P_VI_DEF|P_RCLR,
- (char_u *)&p_ambw, PV_NONE,
- {(char_u *)"single", (char_u *)0L}
- SCRIPTID_INIT},
- {"autochdir", "acd", P_BOOL|P_VI_DEF,
- (char_u *)&p_acd, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"autoindent", "ai", P_BOOL,
- (char_u *)&p_ai, PV_AI,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"autoread", "ar", P_BOOL|P_VIM,
- (char_u *)&p_ar, PV_AR,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"autowrite", "aw", P_BOOL|P_VI_DEF,
- (char_u *)&p_aw, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"autowriteall","awa", P_BOOL|P_VI_DEF,
- (char_u *)&p_awa, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"background", "bg", P_STRING|P_VI_DEF|P_RCLR,
- (char_u *)&p_bg, PV_NONE,
- {
- (char_u *)"light",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"backspace", "bs", P_STRING|P_VIM|P_COMMA|P_NODUP,
- (char_u *)&p_bs, PV_NONE,
- {(char_u *)"", (char_u *)"indent,eol,start"} SCRIPTID_INIT},
- {"backup", "bk", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_bk, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"backupcopy", "bkc", P_STRING|P_VIM|P_COMMA|P_NODUP,
- (char_u *)&p_bkc, PV_BKC,
-#ifdef UNIX
- {(char_u *)"yes", (char_u *)"auto"}
-#else
- {(char_u *)"auto", (char_u *)"auto"}
-#endif
- SCRIPTID_INIT},
- {"backupdir", "bdir", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP|P_SECURE,
- (char_u *)&p_bdir, PV_NONE,
- {(char_u *)DFLT_BDIR, (char_u *)0L} SCRIPTID_INIT},
- {"backupext", "bex", P_STRING|P_VI_DEF|P_NFNAME,
- (char_u *)&p_bex, PV_NONE,
- {
- (char_u *)"~",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"backupskip", "bsk", P_STRING|P_VI_DEF|P_COMMA,
- (char_u *)&p_bsk, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"binary", "bin", P_BOOL|P_VI_DEF|P_RSTAT,
- (char_u *)&p_bin, PV_BIN,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"bomb", NULL, P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
- (char_u *)&p_bomb, PV_BOMB,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"breakat", "brk", P_STRING|P_VI_DEF|P_RALL|P_FLAGLIST,
- (char_u *)&p_breakat, PV_NONE,
- {(char_u *)" \t!@*-+;:,./?", (char_u *)0L}
- SCRIPTID_INIT},
- {"breakindent", "bri", P_BOOL|P_VI_DEF|P_VIM|P_RWIN,
- VAR_WIN, PV_BRI,
- {(char_u *)FALSE, (char_u *)0L}
- SCRIPTID_INIT},
- {"breakindentopt", "briopt", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_COMMA|P_NODUP,
- VAR_WIN, PV_BRIOPT,
- {(char_u *)"", (char_u *)NULL}
- SCRIPTID_INIT},
- {"browsedir", "bsdir",P_STRING|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)0L, (char_u *)0L}
- SCRIPTID_INIT},
- {"bufhidden", "bh", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB,
- (char_u *)&p_bh, PV_BH,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"buflisted", "bl", P_BOOL|P_VI_DEF|P_NOGLOB,
- (char_u *)&p_bl, PV_BL,
- {(char_u *)1L, (char_u *)0L}
- SCRIPTID_INIT},
- {"buftype", "bt", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB,
- (char_u *)&p_bt, PV_BT,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"casemap", "cmp", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_cmp, PV_NONE,
- {(char_u *)"internal,keepascii", (char_u *)0L}
- SCRIPTID_INIT},
- {"cdpath", "cd", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_cdpath, PV_NONE,
- {(char_u *)",,", (char_u *)0L}
- SCRIPTID_INIT},
- {"cedit", NULL, P_STRING,
- (char_u *)&p_cedit, PV_NONE,
- {(char_u *)"", (char_u *)CTRL_F_STR}
- SCRIPTID_INIT},
- {"charconvert", "ccv", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_ccv, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"cindent", "cin", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_cin, PV_CIN,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"cinkeys", "cink", P_STRING|P_ALLOCED|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_cink, PV_CINK,
- {(char_u *)"0{,0},0),:,0#,!^F,o,O,e", (char_u *)0L}
- SCRIPTID_INIT},
- {"cinoptions", "cino", P_STRING|P_ALLOCED|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_cino, PV_CINO,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"cinwords", "cinw", P_STRING|P_ALLOCED|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_cinw, PV_CINW,
- {(char_u *)"if,else,while,do,for,switch",
- (char_u *)0L}
- SCRIPTID_INIT},
- {"clipboard", "cb", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_cb, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"cmdheight", "ch", P_NUM|P_VI_DEF|P_RALL,
- (char_u *)&p_ch, PV_NONE,
- {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT},
- {"cmdwinheight", "cwh", P_NUM|P_VI_DEF,
- (char_u *)&p_cwh, PV_NONE,
- {(char_u *)7L, (char_u *)0L} SCRIPTID_INIT},
- {"colorcolumn", "cc", P_STRING|P_VI_DEF|P_COMMA|P_NODUP|P_RWIN,
- VAR_WIN, PV_CC,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"columns", "co", P_NUM|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RCLR,
- (char_u *)&Columns, PV_NONE,
- {(char_u *)80L, (char_u *)0L} SCRIPTID_INIT},
- {"comments", "com", P_STRING|P_ALLOCED|P_VI_DEF|P_COMMA|P_NODUP|
- P_CURSWANT,
- (char_u *)&p_com, PV_COM,
- {(char_u *)"s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-",
- (char_u *)0L}
- SCRIPTID_INIT},
- {"commentstring", "cms", P_STRING|P_ALLOCED|P_VI_DEF|P_CURSWANT,
- (char_u *)&p_cms, PV_CMS,
- {(char_u *)"/*%s*/", (char_u *)0L}
- SCRIPTID_INIT},
- /* P_PRI_MKRC isn't needed here, optval_default()
- * always returns TRUE for 'compatible' */
- {"compatible", "cp", P_BOOL|P_RALL,
- (char_u *)&p_force_off, PV_NONE,
- {(char_u *)TRUE, (char_u *)FALSE} SCRIPTID_INIT},
- {"complete", "cpt", P_STRING|P_ALLOCED|P_COMMA|P_NODUP,
- (char_u *)&p_cpt, PV_CPT,
- {(char_u *)".,w,b,u,t,i", (char_u *)".,w,b,u,t"}
- SCRIPTID_INIT},
- {"concealcursor","cocu", P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF,
- VAR_WIN, PV_COCU,
- {(char_u *)"", (char_u *)NULL}
- SCRIPTID_INIT},
- {"conceallevel","cole", P_NUM|P_RWIN|P_VI_DEF,
- VAR_WIN, PV_COLE,
- {(char_u *)0L, (char_u *)0L}
- SCRIPTID_INIT},
- {"completefunc", "cfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE,
- (char_u *)&p_cfu, PV_CFU,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"completeopt", "cot", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_cot, PV_NONE,
- {(char_u *)"menu,preview", (char_u *)0L}
- SCRIPTID_INIT},
- {"confirm", "cf", P_BOOL|P_VI_DEF,
- (char_u *)&p_confirm, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"copyindent", "ci", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_ci, PV_CI,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"cpoptions", "cpo", P_STRING|P_VIM|P_RALL|P_FLAGLIST,
- (char_u *)&p_cpo, PV_NONE,
- {(char_u *)CPO_VI, (char_u *)CPO_VIM}
- SCRIPTID_INIT},
- {"cscopepathcomp", "cspc", P_NUM|P_VI_DEF|P_VIM,
- (char_u *)&p_cspc, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"cscopeprg", "csprg", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_csprg, PV_NONE,
- {(char_u *)"cscope", (char_u *)0L}
- SCRIPTID_INIT},
- {"cscopequickfix", "csqf", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_csqf, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"cscoperelative", "csre", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_csre, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"cscopetag", "cst", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_cst, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"cscopetagorder", "csto", P_NUM|P_VI_DEF|P_VIM,
- (char_u *)&p_csto, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"cscopeverbose", "csverb", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_csverbose, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"cursorbind", "crb", P_BOOL|P_VI_DEF,
- VAR_WIN, PV_CRBIND,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"cursorcolumn", "cuc", P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_CUC,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"cursorline", "cul", P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_CUL,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"debug", NULL, P_STRING|P_VI_DEF,
- (char_u *)&p_debug, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"define", "def", P_STRING|P_ALLOCED|P_VI_DEF|P_CURSWANT,
- (char_u *)&p_def, PV_DEF,
- {(char_u *)"^\\s*#\\s*define", (char_u *)0L}
- SCRIPTID_INIT},
- {"delcombine", "deco", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_deco, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"dictionary", "dict", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_dict, PV_DICT,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"diff", NULL, P_BOOL|P_VI_DEF|P_RWIN|P_NOGLOB,
- VAR_WIN, PV_DIFF,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"diffexpr", "dex", P_STRING|P_VI_DEF|P_SECURE|P_CURSWANT,
- (char_u *)&p_dex, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"diffopt", "dip", P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN|P_COMMA|P_NODUP,
- (char_u *)&p_dip, PV_NONE,
- {(char_u *)"filler", (char_u *)NULL}
- SCRIPTID_INIT},
- {"digraph", "dg", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_dg, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"directory", "dir", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP|P_SECURE,
- (char_u *)&p_dir, PV_NONE,
- {(char_u *)DFLT_DIR, (char_u *)0L} SCRIPTID_INIT},
- {"display", "dy", P_STRING|P_VIM|P_COMMA|P_RALL|P_NODUP,
- (char_u *)&p_dy, PV_NONE,
- {(char_u *)"", (char_u *)"lastline"} SCRIPTID_INIT},
- {"eadirection", "ead", P_STRING|P_VI_DEF,
- (char_u *)&p_ead, PV_NONE,
- {(char_u *)"both", (char_u *)0L}
- SCRIPTID_INIT},
- {"edcompatible","ed", P_BOOL|P_VI_DEF,
- (char_u *)&p_force_off, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"encoding", "enc", P_STRING|P_VI_DEF|P_RCLR|P_NO_ML,
- (char_u *)&p_enc, PV_NONE,
- {(char_u *)ENC_DFLT, (char_u *)0L}
- SCRIPTID_INIT},
- {"endofline", "eol", P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
- (char_u *)&p_eol, PV_EOL,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"equalalways", "ea", P_BOOL|P_VI_DEF|P_RALL,
- (char_u *)&p_ea, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"equalprg", "ep", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_ep, PV_EP,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"errorbells", "eb", P_BOOL|P_VI_DEF,
- (char_u *)&p_eb, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"errorfile", "ef", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_ef, PV_NONE,
- {(char_u *)DFLT_ERRORFILE, (char_u *)0L}
- SCRIPTID_INIT},
- {"errorformat", "efm", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_efm, PV_EFM,
- {(char_u *)DFLT_EFM, (char_u *)0L}
- SCRIPTID_INIT},
- {"esckeys", "ek", P_BOOL|P_VIM,
- (char_u *)&p_ek, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"eventignore", "ei", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_ei, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"expandtab", "et", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_et, PV_ET,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"exrc", "ex", P_BOOL|P_VI_DEF|P_SECURE,
- (char_u *)&p_exrc, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"fileencoding","fenc", P_STRING|P_ALLOCED|P_VI_DEF|P_RSTAT|P_RBUF|P_NO_MKRC,
- (char_u *)&p_fenc, PV_FENC,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"fileencodings","fencs", P_STRING|P_VI_DEF|P_COMMA,
- (char_u *)&p_fencs, PV_NONE,
- {(char_u *)"ucs-bom", (char_u *)0L}
- SCRIPTID_INIT},
- {"fileformat", "ff", P_STRING|P_ALLOCED|P_VI_DEF|P_RSTAT|P_NO_MKRC|
- P_CURSWANT,
- (char_u *)&p_ff, PV_FF,
- {(char_u *)DFLT_FF, (char_u *)0L} SCRIPTID_INIT},
- {"fileformats", "ffs", P_STRING|P_VIM|P_COMMA|P_NODUP,
- (char_u *)&p_ffs, PV_NONE,
- {(char_u *)DFLT_FFS_VI, (char_u *)DFLT_FFS_VIM}
- SCRIPTID_INIT},
- {"fileignorecase", "fic", P_BOOL|P_VI_DEF,
- (char_u *)&p_fic, PV_NONE,
- {
-#ifdef CASE_INSENSITIVE_FILENAME
- (char_u *)TRUE,
-#else
- (char_u *)FALSE,
-#endif
- (char_u *)0L
- } SCRIPTID_INIT},
- {"filetype", "ft", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB|P_NFNAME,
- (char_u *)&p_ft, PV_FT,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"fillchars", "fcs", P_STRING|P_VI_DEF|P_RALL|P_COMMA|P_NODUP,
- (char_u *)&p_fcs, PV_NONE,
- {(char_u *)"vert:|,fold:-", (char_u *)0L}
- SCRIPTID_INIT},
- {"fkmap", "fk", P_BOOL|P_VI_DEF,
- (char_u *)&p_fkmap, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"foldclose", "fcl", P_STRING|P_VI_DEF|P_COMMA|P_NODUP|P_RWIN,
- (char_u *)&p_fcl, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"foldcolumn", "fdc", P_NUM|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FDC,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"foldenable", "fen", P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FEN,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"foldexpr", "fde", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FDE,
- {(char_u *)"0", (char_u *)NULL}
- SCRIPTID_INIT},
- {"foldignore", "fdi", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FDI,
- {(char_u *)"#", (char_u *)NULL} SCRIPTID_INIT},
- {"foldlevel", "fdl", P_NUM|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FDL,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"foldlevelstart","fdls", P_NUM|P_VI_DEF|P_CURSWANT,
- (char_u *)&p_fdls, PV_NONE,
- {(char_u *)-1L, (char_u *)0L} SCRIPTID_INIT},
- {"foldmarker", "fmr", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|
- P_RWIN|P_COMMA|P_NODUP,
- VAR_WIN, PV_FMR,
- {(char_u *)"{{{,}}}", (char_u *)NULL}
- SCRIPTID_INIT},
- {"foldmethod", "fdm", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FDM,
- {(char_u *)"manual", (char_u *)NULL} SCRIPTID_INIT},
- {"foldminlines","fml", P_NUM|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FML,
- {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT},
- {"foldnestmax", "fdn", P_NUM|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FDN,
- {(char_u *)20L, (char_u *)0L} SCRIPTID_INIT},
- {"foldopen", "fdo", P_STRING|P_VI_DEF|P_COMMA|P_NODUP|P_CURSWANT,
- (char_u *)&p_fdo, PV_NONE,
- {(char_u *)"block,hor,mark,percent,quickfix,search,tag,undo",
- (char_u *)0L} SCRIPTID_INIT},
- {"foldtext", "fdt", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_FDT,
- {(char_u *)"foldtext()", (char_u *)NULL}
- SCRIPTID_INIT},
- {"formatexpr", "fex", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM,
- (char_u *)&p_fex, PV_FEX,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"formatoptions","fo", P_STRING|P_ALLOCED|P_VIM|P_FLAGLIST,
- (char_u *)&p_fo, PV_FO,
- {(char_u *)DFLT_FO_VI, (char_u *)DFLT_FO_VIM}
- SCRIPTID_INIT},
- {"formatlistpat","flp", P_STRING|P_ALLOCED|P_VI_DEF,
- (char_u *)&p_flp, PV_FLP,
- {(char_u *)"^\\s*\\d\\+[\\]:.)}\\t ]\\s*",
- (char_u *)0L} SCRIPTID_INIT},
- {"formatprg", "fp", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_fp, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"fsync", "fs", P_BOOL|P_SECURE|P_VI_DEF,
-#ifdef HAVE_FSYNC
- (char_u *)&p_fs, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L}
-#else
- (char_u *)NULL, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L}
-#endif
- SCRIPTID_INIT},
- {"gdefault", "gd", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_gd, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"grepformat", "gfm", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_gefm, PV_NONE,
- {(char_u *)DFLT_GREPFORMAT, (char_u *)0L}
- SCRIPTID_INIT},
- {"grepprg", "gp", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_gp, PV_GP,
- {
-# ifdef UNIX
- /* Add an extra file name so that grep will always
- * insert a file name in the match line. */
- (char_u *)"grep -n $* /dev/null",
-# else
- (char_u *)"grep -n ",
-# endif
- (char_u *)0L
- }
- SCRIPTID_INIT},
- {"guicursor", "gcr", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_guicursor, PV_NONE,
- {
- (char_u *)"n-v-c:block,o:hor50,i-ci:hor15,r-cr:hor30,sm:block",
- (char_u *)0L
- }
- SCRIPTID_INIT},
- {"guifont", "gfn", P_STRING|P_VI_DEF|P_RCLR|P_COMMA|P_NODUP,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"guifontset", "gfs", P_STRING|P_VI_DEF|P_RCLR|P_COMMA,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"guifontwide", "gfw", P_STRING|P_VI_DEF|P_RCLR|P_COMMA|P_NODUP,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"guiheadroom", "ghr", P_NUM|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)50L, (char_u *)0L} SCRIPTID_INIT},
- {"guioptions", "go", P_STRING|P_VI_DEF|P_RALL|P_FLAGLIST,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"guitablabel", "gtl", P_STRING|P_VI_DEF|P_RWIN,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"guitabtooltip", "gtt", P_STRING|P_VI_DEF|P_RWIN,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"helpfile", "hf", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_hf, PV_NONE,
- {(char_u *)DFLT_HELPFILE, (char_u *)0L}
- SCRIPTID_INIT},
- {"helpheight", "hh", P_NUM|P_VI_DEF,
- (char_u *)&p_hh, PV_NONE,
- {(char_u *)20L, (char_u *)0L} SCRIPTID_INIT},
- {"helplang", "hlg", P_STRING|P_VI_DEF|P_COMMA,
- (char_u *)&p_hlg, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"hidden", "hid", P_BOOL|P_VI_DEF,
- (char_u *)&p_hid, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"highlight", "hl", P_STRING|P_VI_DEF|P_RCLR|P_COMMA|P_NODUP,
- (char_u *)&p_hl, PV_NONE,
- {(char_u *)HIGHLIGHT_INIT, (char_u *)0L}
- SCRIPTID_INIT},
- {"history", "hi", P_NUM|P_VIM,
- (char_u *)&p_hi, PV_NONE,
- {(char_u *)0L, (char_u *)50L} SCRIPTID_INIT},
- {"hkmap", "hk", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_hkmap, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"hkmapp", "hkp", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_hkmapp, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"hlsearch", "hls", P_BOOL|P_VIM|P_RALL,
- (char_u *)&p_hls, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"icon", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_icon, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"iconstring", NULL, P_STRING|P_VI_DEF,
- (char_u *)&p_iconstring, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"ignorecase", "ic", P_BOOL|P_VI_DEF,
- (char_u *)&p_ic, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"imactivatekey","imak",P_STRING|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"imcmdline", "imc", P_BOOL|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"imdisable", "imd", P_BOOL|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L}
- SCRIPTID_INIT},
- {"iminsert", "imi", P_NUM|P_VI_DEF,
- (char_u *)&p_iminsert, PV_IMI,
-#ifdef B_IMODE_IM
- {(char_u *)B_IMODE_IM, (char_u *)0L}
-#else
- {(char_u *)B_IMODE_NONE, (char_u *)0L}
-#endif
- SCRIPTID_INIT},
- {"imsearch", "ims", P_NUM|P_VI_DEF,
- (char_u *)&p_imsearch, PV_IMS,
-#ifdef B_IMODE_IM
- {(char_u *)B_IMODE_IM, (char_u *)0L}
-#else
- {(char_u *)B_IMODE_NONE, (char_u *)0L}
-#endif
- SCRIPTID_INIT},
- {"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"include", "inc", P_STRING|P_ALLOCED|P_VI_DEF,
- (char_u *)&p_inc, PV_INC,
- {(char_u *)"^\\s*#\\s*include", (char_u *)0L}
- SCRIPTID_INIT},
- {"includeexpr", "inex", P_STRING|P_ALLOCED|P_VI_DEF,
- (char_u *)&p_inex, PV_INEX,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"incsearch", "is", P_BOOL|P_VIM,
- (char_u *)&p_is, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"indentexpr", "inde", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM,
- (char_u *)&p_inde, PV_INDE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"indentkeys", "indk", P_STRING|P_ALLOCED|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_indk, PV_INDK,
- {(char_u *)"0{,0},:,0#,!^F,o,O,e", (char_u *)0L}
- SCRIPTID_INIT},
- {"infercase", "inf", P_BOOL|P_VI_DEF,
- (char_u *)&p_inf, PV_INF,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"insertmode", "im", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_im, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"isfname", "isf", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_isf, PV_NONE,
- {
-#ifdef BACKSLASH_IN_FILENAME
- /* Excluded are: & and ^ are special in cmd.exe
- * ( and ) are used in text separating fnames */
- (char_u *)"@,48-57,/,\\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,=",
-#else
- (char_u *)"@,48-57,/,.,-,_,+,,,#,$,%,~,=",
-#endif
- (char_u *)0L
- } SCRIPTID_INIT},
- {"isident", "isi", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_isi, PV_NONE,
- {
- (char_u *)"@,48-57,_,192-255",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"iskeyword", "isk", P_STRING|P_ALLOCED|P_VIM|P_COMMA|P_NODUP,
- (char_u *)&p_isk, PV_ISK,
- {
- (char_u *)"@,48-57,_",
- ISK_LATIN1
- } SCRIPTID_INIT},
- {"isprint", "isp", P_STRING|P_VI_DEF|P_RALL|P_COMMA|P_NODUP,
- (char_u *)&p_isp, PV_NONE,
- {
-#if defined(MSWIN)
- (char_u *)"@,~-255",
-#else
- ISP_LATIN1,
-#endif
- (char_u *)0L
- } SCRIPTID_INIT},
- {"joinspaces", "js", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_js, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"keymap", "kmp", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_RSTAT|P_NFNAME|
- P_PRI_MKRC,
- (char_u *)&p_keymap, PV_KMAP,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"keymodel", "km", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_km, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"keywordprg", "kp", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_kp, PV_KP,
- {
-# ifdef USEMAN_S
- (char_u *)"man -s",
-# else
- (char_u *)"man",
-# endif
- (char_u *)0L
- } SCRIPTID_INIT},
- {"langmap", "lmap", P_STRING|P_VI_DEF|P_COMMA|P_NODUP|P_SECURE,
- (char_u *)&p_langmap, PV_NONE,
- {(char_u *)"", /* unmatched } */
- (char_u *)0L} SCRIPTID_INIT},
- {"langmenu", "lm", P_STRING|P_VI_DEF|P_NFNAME,
- (char_u *)&p_lm, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"langnoremap", "lnr", P_BOOL,
- (char_u *)&p_lnr, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"laststatus", "ls", P_NUM|P_VI_DEF|P_RALL,
- (char_u *)&p_ls, PV_NONE,
- {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT},
- {"lazyredraw", "lz", P_BOOL|P_VI_DEF,
- (char_u *)&p_lz, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"linebreak", "lbr", P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_LBR,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"lines", NULL, P_NUM|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RCLR,
- (char_u *)&Rows, PV_NONE,
- {
- (char_u *)24L,
- (char_u *)0L
- } SCRIPTID_INIT},
- {"linespace", "lsp", P_NUM|P_VI_DEF|P_RCLR,
- (char_u *)NULL, PV_NONE,
- {(char_u *)0L, (char_u *)0L}
- SCRIPTID_INIT},
- {"lisp", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_lisp, PV_LISP,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"lispwords", "lw", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_lispwords, PV_LW,
- {(char_u *)LISPWORD_VALUE, (char_u *)0L}
- SCRIPTID_INIT},
- {"list", NULL, P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_LIST,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"listchars", "lcs", P_STRING|P_VI_DEF|P_RALL|P_COMMA|P_NODUP,
- (char_u *)&p_lcs, PV_NONE,
- {(char_u *)"eol:$", (char_u *)0L} SCRIPTID_INIT},
- {"loadplugins", "lpl", P_BOOL|P_VI_DEF,
- (char_u *)&p_lpl, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"magic", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_magic, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"makeef", "mef", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_mef, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"makeprg", "mp", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_mp, PV_MP,
- {(char_u *)"make", (char_u *)0L}
- SCRIPTID_INIT},
- {"matchpairs", "mps", P_STRING|P_ALLOCED|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_mps, PV_MPS,
- {(char_u *)"(:),{:},[:]", (char_u *)0L}
- SCRIPTID_INIT},
- {"matchtime", "mat", P_NUM|P_VI_DEF,
- (char_u *)&p_mat, PV_NONE,
- {(char_u *)5L, (char_u *)0L} SCRIPTID_INIT},
- {"maxcombine", "mco", P_NUM|P_VI_DEF|P_CURSWANT,
- (char_u *)&p_mco, PV_NONE,
- {(char_u *)2, (char_u *)0L} SCRIPTID_INIT},
- {"maxfuncdepth", "mfd", P_NUM|P_VI_DEF,
- (char_u *)&p_mfd, PV_NONE,
- {(char_u *)100L, (char_u *)0L} SCRIPTID_INIT},
- {"maxmapdepth", "mmd", P_NUM|P_VI_DEF,
- (char_u *)&p_mmd, PV_NONE,
- {(char_u *)1000L, (char_u *)0L} SCRIPTID_INIT},
- {"maxmem", "mm", P_NUM|P_VI_DEF,
- (char_u *)&p_mm, PV_NONE,
- {(char_u *)DFLT_MAXMEM, (char_u *)0L}
- SCRIPTID_INIT},
- {"maxmempattern","mmp", P_NUM|P_VI_DEF,
- (char_u *)&p_mmp, PV_NONE,
- {(char_u *)1000L, (char_u *)0L} SCRIPTID_INIT},
- {"maxmemtot", "mmt", P_NUM|P_VI_DEF,
- (char_u *)&p_mmt, PV_NONE,
- {(char_u *)DFLT_MAXMEMTOT, (char_u *)0L}
- SCRIPTID_INIT},
- {"menuitems", "mis", P_NUM|P_VI_DEF,
- (char_u *)&p_mis, PV_NONE,
- {(char_u *)25L, (char_u *)0L} SCRIPTID_INIT},
- {"mkspellmem", "msm", P_STRING|P_VI_DEF|P_EXPAND|P_SECURE,
- (char_u *)&p_msm, PV_NONE,
- {(char_u *)"460000,2000,500", (char_u *)0L}
- SCRIPTID_INIT},
- {"modeline", "ml", P_BOOL|P_VIM,
- (char_u *)&p_ml, PV_ML,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"modelines", "mls", P_NUM|P_VI_DEF,
- (char_u *)&p_mls, PV_NONE,
- {(char_u *)5L, (char_u *)0L} SCRIPTID_INIT},
- {"modifiable", "ma", P_BOOL|P_VI_DEF|P_NOGLOB,
- (char_u *)&p_ma, PV_MA,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"modified", "mod", P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
- (char_u *)&p_mod, PV_MOD,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"more", NULL, P_BOOL|P_VIM,
- (char_u *)&p_more, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"mouse", NULL, P_STRING|P_FLAGLIST,
- (char_u *)&p_mouse, PV_NONE,
- {
- (char_u *)"",
- (char_u *)"a"
- } SCRIPTID_INIT},
- {"mousefocus", "mousef", P_BOOL|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"mousehide", "mh", P_BOOL|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"mousemodel", "mousem", P_STRING|P_VI_DEF,
- (char_u *)&p_mousem, PV_NONE,
- {
- (char_u *)"extend",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"mouseshape", "mouses", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)NULL, PV_NONE,
- {(char_u *)NULL, (char_u *)0L}
- SCRIPTID_INIT},
- {"mousetime", "mouset", P_NUM|P_VI_DEF,
- (char_u *)&p_mouset, PV_NONE,
- {(char_u *)500L, (char_u *)0L} SCRIPTID_INIT},
- {"nrformats", "nf", P_STRING|P_ALLOCED|P_VIM|P_COMMA|P_NODUP,
- (char_u *)&p_nf, PV_NF,
- {(char_u *)"octal,hex", (char_u *)"hex"}
- SCRIPTID_INIT},
- {"number", "nu", P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_NU,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"numberwidth", "nuw", P_NUM|P_RWIN|P_VIM,
- VAR_WIN, PV_NUW,
- {(char_u *)8L, (char_u *)4L} SCRIPTID_INIT},
- {"omnifunc", "ofu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE,
- (char_u *)&p_ofu, PV_OFU,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"opendevice", "odev", P_BOOL|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)FALSE, (char_u *)FALSE}
- SCRIPTID_INIT},
- {"operatorfunc", "opfunc", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_opfunc, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"paragraphs", "para", P_STRING|P_VI_DEF,
- (char_u *)&p_para, PV_NONE,
- {(char_u *)"IPLPPPQPP TPHPLIPpLpItpplpipbp",
- (char_u *)0L} SCRIPTID_INIT},
- {"paste", NULL, P_BOOL|P_VI_DEF|P_PRI_MKRC,
- (char_u *)&p_paste, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"pastetoggle", "pt", P_STRING|P_VI_DEF,
- (char_u *)&p_pt, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"patchexpr", "pex", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_pex, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"patchmode", "pm", P_STRING|P_VI_DEF|P_NFNAME,
- (char_u *)&p_pm, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"path", "pa", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_path, PV_PATH,
- {
- (char_u *)".,/usr/include,,",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"preserveindent", "pi", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_pi, PV_PI,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"previewheight", "pvh", P_NUM|P_VI_DEF,
- (char_u *)&p_pvh, PV_NONE,
- {(char_u *)12L, (char_u *)0L} SCRIPTID_INIT},
- {"previewwindow", "pvw", P_BOOL|P_VI_DEF|P_RSTAT|P_NOGLOB,
- VAR_WIN, PV_PVW,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"printdevice", "pdev", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_pdev, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"printencoding", "penc", P_STRING|P_VI_DEF,
- (char_u *)&p_penc, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"printexpr", "pexpr", P_STRING|P_VI_DEF,
- (char_u *)&p_pexpr, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"printfont", "pfn", P_STRING|P_VI_DEF,
- (char_u *)&p_pfn, PV_NONE,
- {
- (char_u *)"courier",
- (char_u *)0L
- }
- SCRIPTID_INIT},
- {"printheader", "pheader", P_STRING|P_VI_DEF|P_GETTEXT,
- (char_u *)&p_header, PV_NONE,
- {(char_u *)N_("%<%f%h%m%=Page %N"), (char_u *)0L}
- SCRIPTID_INIT},
- {"printmbcharset", "pmbcs", P_STRING|P_VI_DEF,
- (char_u *)&p_pmcs, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"printmbfont", "pmbfn", P_STRING|P_VI_DEF,
- (char_u *)&p_pmfn, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"printoptions", "popt", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_popt, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"prompt", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_prompt, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"pumheight", "ph", P_NUM|P_VI_DEF,
- (char_u *)&p_ph, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"quoteescape", "qe", P_STRING|P_ALLOCED|P_VI_DEF,
- (char_u *)&p_qe, PV_QE,
- {(char_u *)"\\", (char_u *)0L}
- SCRIPTID_INIT},
- {"readonly", "ro", P_BOOL|P_VI_DEF|P_RSTAT|P_NOGLOB,
- (char_u *)&p_ro, PV_RO,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"redrawtime", "rdt", P_NUM|P_VI_DEF,
- (char_u *)&p_rdt, PV_NONE,
- {(char_u *)2000L, (char_u *)0L} SCRIPTID_INIT},
- {"regexpengine", "re", P_NUM|P_VI_DEF,
- (char_u *)&p_re, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"relativenumber", "rnu", P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_RNU,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"remap", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_remap, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"report", NULL, P_NUM|P_VI_DEF,
- (char_u *)&p_report, PV_NONE,
- {(char_u *)2L, (char_u *)0L} SCRIPTID_INIT},
- {"restorescreen", "rs", P_BOOL|P_VI_DEF,
- (char_u *)NULL, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"revins", "ri", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_ri, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"rightleft", "rl", P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_RL,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"rightleftcmd", "rlc", P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_RLC,
- {(char_u *)"search", (char_u *)NULL}
- SCRIPTID_INIT},
- {"ruler", "ru", P_BOOL|P_VI_DEF|P_VIM|P_RSTAT,
- (char_u *)&p_ru, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"rulerformat", "ruf", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT,
- (char_u *)&p_ruf, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"runtimepath", "rtp", P_STRING|P_VI_DEF|P_EXPAND|P_COMMA|P_NODUP|P_SECURE,
- (char_u *)&p_rtp, PV_NONE,
- {(char_u *)DFLT_RUNTIMEPATH, (char_u *)0L}
- SCRIPTID_INIT},
- {"scroll", "scr", P_NUM|P_NO_MKRC|P_VI_DEF,
- VAR_WIN, PV_SCROLL,
- {(char_u *)12L, (char_u *)0L} SCRIPTID_INIT},
- {"scrollbind", "scb", P_BOOL|P_VI_DEF,
- VAR_WIN, PV_SCBIND,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"scrolljump", "sj", P_NUM|P_VI_DEF|P_VIM,
- (char_u *)&p_sj, PV_NONE,
- {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT},
- {"scrolloff", "so", P_NUM|P_VI_DEF|P_VIM|P_RALL,
- (char_u *)&p_so, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"scrollopt", "sbo", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_sbo, PV_NONE,
- {(char_u *)"ver,jump", (char_u *)0L}
- SCRIPTID_INIT},
- {"sections", "sect", P_STRING|P_VI_DEF,
- (char_u *)&p_sections, PV_NONE,
- {(char_u *)"SHNHH HUnhsh", (char_u *)0L}
- SCRIPTID_INIT},
- {"secure", NULL, P_BOOL|P_VI_DEF|P_SECURE,
- (char_u *)&p_secure, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"selection", "sel", P_STRING|P_VI_DEF,
- (char_u *)&p_sel, PV_NONE,
- {(char_u *)"inclusive", (char_u *)0L}
- SCRIPTID_INIT},
- {"selectmode", "slm", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_slm, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"sessionoptions", "ssop", P_STRING|P_VIM|P_COMMA|P_NODUP,
- (char_u *)&p_ssop, PV_NONE,
- {(char_u *)"blank,buffers,curdir,folds,help,options,tabpages,winsize",
- (char_u *)"blank,buffers,curdir,folds,help,tabpages,winsize"}
- SCRIPTID_INIT},
- {"shell", "sh", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_sh, PV_NONE,
- {
- (char_u *)"sh",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"shellcmdflag","shcf", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_shcf, PV_NONE,
- {
- (char_u *)"-c",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"shellpipe", "sp", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_sp, PV_NONE,
- {
-#if defined(UNIX)
- (char_u *)"| tee",
-#else
- (char_u *)">",
-#endif
- (char_u *)0L
- }
- SCRIPTID_INIT},
- {"shellquote", "shq", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_shq, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"shellredir", "srr", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_srr, PV_NONE,
- {(char_u *)">", (char_u *)0L} SCRIPTID_INIT},
- {"shellslash", "ssl", P_BOOL|P_VI_DEF,
-#ifdef BACKSLASH_IN_FILENAME
- (char_u *)&p_ssl, PV_NONE,
-#else
- (char_u *)NULL, PV_NONE,
-#endif
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"shelltemp", "stmp", P_BOOL,
- (char_u *)&p_stmp, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"shellxquote", "sxq", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_sxq, PV_NONE,
- {
- (char_u *)"",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"shellxescape", "sxe", P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_sxe, PV_NONE,
- {
- (char_u *)"",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"shiftround", "sr", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_sr, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"shiftwidth", "sw", P_NUM|P_VI_DEF,
- (char_u *)&p_sw, PV_SW,
- {(char_u *)8L, (char_u *)0L} SCRIPTID_INIT},
- {"shortmess", "shm", P_STRING|P_VIM|P_FLAGLIST,
- (char_u *)&p_shm, PV_NONE,
- {(char_u *)"", (char_u *)"filnxtToO"}
- SCRIPTID_INIT},
- {"showbreak", "sbr", P_STRING|P_VI_DEF|P_RALL,
- (char_u *)&p_sbr, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"showcmd", "sc", P_BOOL|P_VIM,
- (char_u *)&p_sc, PV_NONE,
- {(char_u *)FALSE,
-#ifdef UNIX
- (char_u *)FALSE
-#else
- (char_u *) TRUE
-#endif
- } SCRIPTID_INIT},
- {"showfulltag", "sft", P_BOOL|P_VI_DEF,
- (char_u *)&p_sft, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"showmatch", "sm", P_BOOL|P_VI_DEF,
- (char_u *)&p_sm, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"showmode", "smd", P_BOOL|P_VIM,
- (char_u *)&p_smd, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"showtabline", "stal", P_NUM|P_VI_DEF|P_RALL,
- (char_u *)&p_stal, PV_NONE,
- {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT},
- {"sidescroll", "ss", P_NUM|P_VI_DEF,
- (char_u *)&p_ss, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"sidescrolloff", "siso", P_NUM|P_VI_DEF|P_VIM|P_RBUF,
- (char_u *)&p_siso, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"smartcase", "scs", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_scs, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"smartindent", "si", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_si, PV_SI,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"smarttab", "sta", P_BOOL|P_VIM,
- (char_u *)&p_sta, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"softtabstop", "sts", P_NUM|P_VI_DEF|P_VIM,
- (char_u *)&p_sts, PV_STS,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"spell", NULL, P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_SPELL,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"spellcapcheck", "spc", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF,
- (char_u *)&p_spc, PV_SPC,
- {(char_u *)"[.?!]\\_[\\])'\" ]\\+", (char_u *)0L}
- SCRIPTID_INIT},
- {"spellfile", "spf", P_STRING|P_EXPAND|P_ALLOCED|P_VI_DEF|P_SECURE|P_COMMA,
- (char_u *)&p_spf, PV_SPF,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"spelllang", "spl", P_STRING|P_ALLOCED|P_VI_DEF|P_COMMA|P_RBUF|P_EXPAND,
- (char_u *)&p_spl, PV_SPL,
- {(char_u *)"en", (char_u *)0L}
- SCRIPTID_INIT},
- {"spellsuggest", "sps", P_STRING|P_VI_DEF|P_EXPAND|P_SECURE|P_COMMA,
- (char_u *)&p_sps, PV_NONE,
- {(char_u *)"best", (char_u *)0L}
- SCRIPTID_INIT},
- {"splitbelow", "sb", P_BOOL|P_VI_DEF,
- (char_u *)&p_sb, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"splitright", "spr", P_BOOL|P_VI_DEF,
- (char_u *)&p_spr, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"startofline", "sol", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_sol, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"statusline","stl", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT,
- (char_u *)&p_stl, PV_STL,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"suffixes", "su", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_su, PV_NONE,
- {(char_u *)".bak,~,.o,.h,.info,.swp,.obj",
- (char_u *)0L} SCRIPTID_INIT},
- {"suffixesadd", "sua", P_STRING|P_VI_DEF|P_ALLOCED|P_COMMA|P_NODUP,
- (char_u *)&p_sua, PV_SUA,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"swapfile", "swf", P_BOOL|P_VI_DEF|P_RSTAT,
- (char_u *)&p_swf, PV_SWF,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"swapsync", "sws", P_STRING|P_VI_DEF,
- (char_u *)&p_sws, PV_NONE,
- {(char_u *)"fsync", (char_u *)0L} SCRIPTID_INIT},
- {"switchbuf", "swb", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_swb, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"synmaxcol", "smc", P_NUM|P_VI_DEF|P_RBUF,
- (char_u *)&p_smc, PV_SMC,
- {(char_u *)3000L, (char_u *)0L}
- SCRIPTID_INIT},
- {"syntax", "syn", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB|P_NFNAME,
- (char_u *)&p_syn, PV_SYN,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"tabline", "tal", P_STRING|P_VI_DEF|P_RALL,
- (char_u *)&p_tal, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"tabpagemax", "tpm", P_NUM|P_VIM,
- (char_u *)&p_tpm, PV_NONE,
- {(char_u *)10L, (char_u *)50L} SCRIPTID_INIT},
- {"tabstop", "ts", P_NUM|P_VI_DEF|P_RBUF,
- (char_u *)&p_ts, PV_TS,
- {(char_u *)8L, (char_u *)0L} SCRIPTID_INIT},
- {"tagbsearch", "tbs", P_BOOL|P_VI_DEF,
- (char_u *)&p_tbs, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L}
- SCRIPTID_INIT},
- {"taglength", "tl", P_NUM|P_VI_DEF,
- (char_u *)&p_tl, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"tagrelative", "tr", P_BOOL|P_VIM,
- (char_u *)&p_tr, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"tags", "tag", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_tags, PV_TAGS,
- {
- (char_u *)"./tags;,tags",
- (char_u *)0L
- } SCRIPTID_INIT},
- {"tagstack", "tgst", P_BOOL|P_VI_DEF,
- (char_u *)&p_tgst, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"termbidi", "tbidi", P_BOOL|P_VI_DEF,
- (char_u *)&p_tbidi, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"termencoding", "tenc", P_STRING|P_VI_DEF|P_RCLR,
- (char_u *)NULL, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"terse", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_terse, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"textwidth", "tw", P_NUM|P_VI_DEF|P_VIM|P_RBUF,
- (char_u *)&p_tw, PV_TW,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"thesaurus", "tsr", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_tsr, PV_TSR,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"tildeop", "top", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_to, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"timeout", "to", P_BOOL|P_VI_DEF,
- (char_u *)&p_timeout, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"timeoutlen", "tm", P_NUM|P_VI_DEF,
- (char_u *)&p_tm, PV_NONE,
- {(char_u *)1000L, (char_u *)0L} SCRIPTID_INIT},
- {"title", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_title, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"titlelen", NULL, P_NUM|P_VI_DEF,
- (char_u *)&p_titlelen, PV_NONE,
- {(char_u *)85L, (char_u *)0L} SCRIPTID_INIT},
- {"titleold", NULL, P_STRING|P_VI_DEF|P_GETTEXT|P_SECURE|P_NO_MKRC,
- (char_u *)&p_titleold, PV_NONE,
- {(char_u *)N_("Thanks for flying Vim"),
- (char_u *)0L}
- SCRIPTID_INIT},
- {"titlestring", NULL, P_STRING|P_VI_DEF,
- (char_u *)&p_titlestring, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"ttimeout", NULL, P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_ttimeout, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"ttimeoutlen", "ttm", P_NUM|P_VI_DEF,
- (char_u *)&p_ttm, PV_NONE,
- {(char_u *)-1L, (char_u *)0L} SCRIPTID_INIT},
- {"ttyfast", "tf", P_BOOL|P_NO_MKRC|P_VI_DEF,
- (char_u *)&p_force_on, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"undodir", "udir", P_STRING|P_EXPAND|P_COMMA|P_NODUP|P_SECURE|P_VI_DEF,
- (char_u *)&p_udir, PV_NONE,
- {(char_u *)".", (char_u *)0L}
- SCRIPTID_INIT},
- {"undofile", "udf", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_udf, PV_UDF,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"undolevels", "ul", P_NUM|P_VI_DEF,
- (char_u *)&p_ul, PV_UL,
- {
-#if defined(UNIX) || defined(WIN3264)
- (char_u *)1000L,
-#else
- (char_u *)100L,
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "options.generated.h"
#endif
- (char_u *)0L
- } SCRIPTID_INIT},
- {"undoreload", "ur", P_NUM|P_VI_DEF,
- (char_u *)&p_ur, PV_NONE,
- { (char_u *)10000L, (char_u *)0L} SCRIPTID_INIT},
- {"updatecount", "uc", P_NUM|P_VI_DEF,
- (char_u *)&p_uc, PV_NONE,
- {(char_u *)200L, (char_u *)0L} SCRIPTID_INIT},
- {"updatetime", "ut", P_NUM|P_VI_DEF,
- (char_u *)&p_ut, PV_NONE,
- {(char_u *)4000L, (char_u *)0L} SCRIPTID_INIT},
- {"verbose", "vbs", P_NUM|P_VI_DEF,
- (char_u *)&p_verbose, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"verbosefile", "vfile", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_vfile, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"viewdir", "vdir", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
- (char_u *)&p_vdir, PV_NONE,
- {(char_u *)DFLT_VDIR, (char_u *)0L}
- SCRIPTID_INIT},
- {"viewoptions", "vop", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_vop, PV_NONE,
- {(char_u *)"folds,options,cursor", (char_u *)0L}
- SCRIPTID_INIT},
- {"viminfo", "vi", P_STRING|P_COMMA|P_NODUP|P_SECURE,
- (char_u *)&p_viminfo, PV_NONE,
- {(char_u *)"", (char_u *)"!,'100,<50,s10,h"}
- SCRIPTID_INIT},
- {"virtualedit", "ve", P_STRING|P_COMMA|P_NODUP|P_VI_DEF|P_VIM|P_CURSWANT,
- (char_u *)&p_ve, PV_NONE,
- {(char_u *)"", (char_u *)""}
- SCRIPTID_INIT},
- {"visualbell", "vb", P_BOOL|P_VI_DEF,
- (char_u *)&p_vb, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"warn", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_warn, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"whichwrap", "ww", P_STRING|P_VIM|P_COMMA|P_FLAGLIST,
- (char_u *)&p_ww, PV_NONE,
- {(char_u *)"", (char_u *)"b,s"} SCRIPTID_INIT},
- {"wildchar", "wc", P_NUM|P_VIM,
- (char_u *)&p_wc, PV_NONE,
- {(char_u *)(long)Ctrl_E, (char_u *)(long)TAB}
- SCRIPTID_INIT},
- {"wildcharm", "wcm", P_NUM|P_VI_DEF,
- (char_u *)&p_wcm, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"wildignore", "wig", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
- (char_u *)&p_wig, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"wildignorecase", "wic", P_BOOL|P_VI_DEF,
- (char_u *)&p_wic, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"wildmenu", "wmnu", P_BOOL|P_VIM,
- (char_u *)&p_wmnu, PV_NONE,
- {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT},
- {"wildmode", "wim", P_STRING|P_VIM|P_COMMA|P_NODUP,
- (char_u *)&p_wim, PV_NONE,
- {(char_u *)"", (char_u *)"list:longest,full"} SCRIPTID_INIT},
- {"wildoptions", "wop", P_STRING|P_VI_DEF,
- (char_u *)&p_wop, PV_NONE,
- {(char_u *)"", (char_u *)0L}
- SCRIPTID_INIT},
- {"winaltkeys", "wak", P_STRING|P_VI_DEF,
- (char_u *)&p_wak, PV_NONE,
- {(char_u *)"menu", (char_u *)0L}
- SCRIPTID_INIT},
- {"window", "wi", P_NUM|P_VI_DEF,
- (char_u *)&p_window, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"winheight", "wh", P_NUM|P_VI_DEF,
- (char_u *)&p_wh, PV_NONE,
- {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT},
- {"winfixheight", "wfh", P_BOOL|P_VI_DEF|P_RSTAT,
- VAR_WIN, PV_WFH,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"winfixwidth", "wfw", P_BOOL|P_VI_DEF|P_RSTAT,
- VAR_WIN, PV_WFW,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"winminheight", "wmh", P_NUM|P_VI_DEF,
- (char_u *)&p_wmh, PV_NONE,
- {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT},
- {"winminwidth", "wmw", P_NUM|P_VI_DEF,
- (char_u *)&p_wmw, PV_NONE,
- {(char_u *)1L, (char_u *)0L} SCRIPTID_INIT},
- {"winwidth", "wiw", P_NUM|P_VI_DEF,
- (char_u *)&p_wiw, PV_NONE,
- {(char_u *)20L, (char_u *)0L} SCRIPTID_INIT},
- {"wrap", NULL, P_BOOL|P_VI_DEF|P_RWIN,
- VAR_WIN, PV_WRAP,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"wrapmargin", "wm", P_NUM|P_VI_DEF,
- (char_u *)&p_wm, PV_WM,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
- {"wrapscan", "ws", P_BOOL|P_VI_DEF,
- (char_u *)&p_ws, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"write", NULL, P_BOOL|P_VI_DEF,
- (char_u *)&p_write, PV_NONE,
- {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
- {"writeany", "wa", P_BOOL|P_VI_DEF,
- (char_u *)&p_wa, PV_NONE,
- {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"writebackup", "wb", P_BOOL|P_VI_DEF|P_VIM,
- (char_u *)&p_wb, PV_NONE,
- {
- (char_u *)TRUE,
- (char_u *)0L
- } SCRIPTID_INIT},
- {"writedelay", "wd", P_NUM|P_VI_DEF,
- (char_u *)&p_wd, PV_NONE,
- {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
-
- /* end marker */
- {
- NULL, NULL, 0, NULL, PV_NONE, {NULL, NULL} SCRIPTID_INIT
- }
-};
#define PARAM_COUNT ARRAY_SIZE(options)
@@ -1724,12 +316,6 @@ void set_init_1(void)
/* Be nocompatible */
p_cp = FALSE;
- /* Use POSIX compatibility when $VIM_POSIX is set. */
- if (os_env_exists("VIM_POSIX")) {
- set_string_default("cpo", (char_u *)CPO_ALL);
- set_string_default("shm", (char_u *)"A");
- }
-
/*
* Find default value for 'shell' option.
* Don't use it if it is empty.
@@ -4226,7 +2812,7 @@ did_set_string_option (
if (varp == &p_shm)
p = (char_u *)SHM_ALL;
else if (varp == &(p_cpo))
- p = (char_u *)CPO_ALL;
+ p = (char_u *)CPO_VI;
else if (varp == &(curbuf->b_p_fo))
p = (char_u *)FO_ALL;
else if (varp == &curwin->w_p_cocu)
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index b13ead9cbb..e35f8bc55b 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -128,21 +128,11 @@
#define CPO_PLUS '+' /* ":write file" resets 'modified' */
#define CPO_SPECI '<' /* don't recognize <> in mappings */
#define CPO_REGAPPEND '>' /* insert NL when appending to a register */
-/* POSIX flags */
-#define CPO_HASH '#' /* "D", "o" and "O" do not use a count */
-#define CPO_PARA '{' /* "{" is also a paragraph boundary */
-#define CPO_TSIZE '|' /* $LINES and $COLUMNS overrule term size */
-#define CPO_PRESERVE '&' /* keep swap file after :preserve */
-#define CPO_SUBPERCENT '/' /* % in :s string uses previous one */
-#define CPO_BACKSL '\\' /* \ is not special in [] */
-#define CPO_CHDIR '.' /* don't chdir if buffer is modified */
#define CPO_SCOLON ';' /* using "," and ";" will skip over char if
* cursor would not move */
-/* default values for Vim, Vi and POSIX */
+/* default values for Vim and Vi */
#define CPO_VIM "aABceFs"
#define CPO_VI "aAbBcCdDeEfFiIJkKlLmMnoOpPqrRsStuvWxXyZ$!%+<>;"
-#define CPO_ALL \
- "aAbBcCdDeEfFiIJkKlLmMnoOpPqrRsStuvWxXyZ$!%+<>#{|&/\\.;"
/* characters for p_ww option: */
#define WW_ALL "bshl<>[],~"
@@ -200,11 +190,10 @@
#define GO_ASELPLUS 'P' /* autoselectPlus */
#define GO_RIGHT 'r' /* use right scrollbar */
#define GO_VRIGHT 'R' /* right scrollbar with vert split */
-#define GO_TEAROFF 't' /* add tear-off menu items */
#define GO_TOOLBAR 'T' /* add toolbar */
#define GO_FOOTER 'F' /* add footer */
#define GO_VERTICAL 'v' /* arrange dialog buttons vertically */
-#define GO_ALL "aAbcefFghilmMprtTv" /* all possible flags for 'go' */
+#define GO_ALL "aAbcefFghilmMprTv" /* all possible flags for 'go' */
/* flags for 'comments' option */
#define COM_NEST 'n' /* comments strings nest */
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
new file mode 100644
index 0000000000..b269bfdc98
--- /dev/null
+++ b/src/nvim/options.lua
@@ -0,0 +1,2777 @@
+-- {
+-- {
+-- full_name='aleph', abbreviation='al',
+-- varname='p_aleph', pv_name=nil,
+-- type='number', list=nil, scope={'global'},
+-- deny_duplicates=nil,
+-- enable_if=nil,
+-- 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,
+-- expand=nil, nodefault=nil, no_mkrc=nil, vi_def=true, vim=true,
+-- alloced=nil,
+-- save_pv_indir=nil,
+-- redraw={'curswant'},
+-- }
+-- }
+-- types: bool, number, string
+-- lists: (nil), comma, flags, flagscomma
+-- scopes: global, buffer, window
+-- redraw options: statuslines, current_window, current_buffer, all_windows,
+-- everything, curswant
+-- default: {vi=…[, vim=…]}
+-- defaults: {condition=#if condition, if_true=default, if_false=default}
+-- #if condition:
+-- string: #ifdef string
+-- !string: #ifndef string
+-- {string, string}: #if defined(string) && defined(string)
+-- {!string, !string}: #if !defined(string) && !defined(string)
+local cstr = function(s)
+ return '"' .. s:gsub('["\\]', '\\%0'):gsub('\t', '\\t') .. '"'
+end
+local macros=function(s)
+ return function()
+ return s
+ end
+end
+local N_=function(s)
+ return function()
+ return 'N_(' .. cstr(s) .. ')'
+ end
+end
+return {
+ cstr=cstr,
+ options={
+ {
+ full_name='aleph', abbreviation='al',
+ type='number', scope={'global'},
+ vi_def=true,
+ redraw={'curswant'},
+ varname='p_aleph',
+ defaults={if_true={vi=224}}
+ },
+ {
+ full_name='antialias', abbreviation='anti',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ redraw={'everything'},
+ enable_if=false,
+ defaults={if_true={vi=false, vim=false}}
+ },
+ {
+ full_name='arabic', abbreviation='arab',
+ type='bool', scope={'window'},
+ vi_def=true,
+ vim=true,
+ redraw={'curswant'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='arabicshape', abbreviation='arshape',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ redraw={'everything'},
+ varname='p_arshape',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='allowrevins', abbreviation='ari',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_ari',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='altkeymap', abbreviation='akm',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_altkeymap',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='ambiwidth', abbreviation='ambw',
+ type='string', scope={'global'},
+ vi_def=true,
+ redraw={'everything'},
+ varname='p_ambw',
+ defaults={if_true={vi="single"}}
+ },
+ {
+ full_name='autochdir', abbreviation='acd',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_acd',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='autoindent', abbreviation='ai',
+ type='bool', scope={'buffer'},
+ varname='p_ai',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='autoread', abbreviation='ar',
+ type='bool', scope={'global', 'buffer'},
+ varname='p_ar',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='autowrite', abbreviation='aw',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_aw',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='autowriteall', abbreviation='awa',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_awa',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='background', abbreviation='bg',
+ type='string', scope={'global'},
+ vi_def=true,
+ redraw={'everything'},
+ varname='p_bg',
+ defaults={if_true={vi="light"}}
+ },
+ {
+ full_name='backspace', abbreviation='bs',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vim=true,
+ varname='p_bs',
+ defaults={if_true={vi="", vim="indent,eol,start"}}
+ },
+ {
+ full_name='backup', abbreviation='bk',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_bk',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='backupcopy', abbreviation='bkc',
+ type='string', list='comma', scope={'global', 'buffer'},
+ deny_duplicates=true,
+ vim=true,
+ varname='p_bkc',
+ defaults={
+ condition='UNIX',
+ if_true={vi="yes", vim="auto"},
+ if_false={vi="auto", vim="auto"}
+ },
+ },
+ {
+ full_name='backupdir', abbreviation='bdir',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_bdir',
+ defaults={if_true={vi=macros('DFLT_BDIR')}}
+ },
+ {
+ full_name='backupext', abbreviation='bex',
+ type='string', scope={'global'},
+ normal_fname_chars=true,
+ vi_def=true,
+ varname='p_bex',
+ defaults={if_true={vi="~"}}
+ },
+ {
+ full_name='backupskip', abbreviation='bsk',
+ type='string', list='comma', scope={'global'},
+ vi_def=true,
+ varname='p_bsk',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='binary', abbreviation='bin',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ redraw={'statuslines'},
+ varname='p_bin',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='bomb',
+ type='bool', scope={'buffer'},
+ no_mkrc=true,
+ vi_def=true,
+ redraw={'statuslines'},
+ varname='p_bomb',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='breakat', abbreviation='brk',
+ type='string', list='flags', scope={'global'},
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_breakat',
+ defaults={if_true={vi=" \t!@*-+;:,./?"}}
+ },
+ {
+ full_name='breakindent', abbreviation='bri',
+ type='bool', scope={'window'},
+ vi_def=true,
+ vim=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='breakindentopt', abbreviation='briopt',
+ type='string', list='comma', scope={'window'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ redraw={'current_buffer'},
+ defaults={if_true={vi=""}},
+ },
+ {
+ full_name='browsedir', abbreviation='bsdir',
+ type='string', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ },
+ {
+ full_name='bufhidden', abbreviation='bh',
+ type='string', scope={'buffer'},
+ noglob=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_bh',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='buflisted', abbreviation='bl',
+ type='bool', scope={'buffer'},
+ noglob=true,
+ vi_def=true,
+ varname='p_bl',
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='buftype', abbreviation='bt',
+ type='string', scope={'buffer'},
+ noglob=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_bt',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='casemap', abbreviation='cmp',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_cmp',
+ defaults={if_true={vi="internal,keepascii"}}
+ },
+ {
+ full_name='cdpath', abbreviation='cd',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ expand=true,
+ varname='p_cdpath',
+ defaults={if_true={vi=",,"}}
+ },
+ {
+ full_name='cedit',
+ type='string', scope={'global'},
+ varname='p_cedit',
+ defaults={if_true={vi="", vim=macros('CTRL_F_STR')}}
+ },
+ {
+ full_name='charconvert', abbreviation='ccv',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_ccv',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='cindent', abbreviation='cin',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_cin',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='cinkeys', abbreviation='cink',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_cink',
+ defaults={if_true={vi="0{,0},0),:,0#,!^F,o,O,e"}}
+ },
+ {
+ full_name='cinoptions', abbreviation='cino',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_cino',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='cinwords', abbreviation='cinw',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_cinw',
+ defaults={if_true={vi="if,else,while,do,for,switch"}}
+ },
+ {
+ full_name='clipboard', abbreviation='cb',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_cb',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='cmdheight', abbreviation='ch',
+ type='number', scope={'global'},
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_ch',
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='cmdwinheight', abbreviation='cwh',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_cwh',
+ defaults={if_true={vi=7}}
+ },
+ {
+ full_name='colorcolumn', abbreviation='cc',
+ type='string', list='comma', scope={'window'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='columns', abbreviation='co',
+ type='number', scope={'global'},
+ no_mkrc=true,
+ nodefault=true,
+ vi_def=true,
+ redraw={'everything'},
+ varname='Columns',
+ defaults={if_true={vi=macros('DFLT_COLS')}}
+ },
+ {
+ full_name='comments', abbreviation='com',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ redraw={'curswant'},
+ varname='p_com',
+ defaults={if_true={vi="s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-"}}
+ },
+ {
+ full_name='commentstring', abbreviation='cms',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ alloced=true,
+ redraw={'curswant'},
+ varname='p_cms',
+ defaults={if_true={vi="/*%s*/"}}
+ },
+ {
+ full_name='compatible', abbreviation='cp',
+ type='bool', scope={'global'},
+ redraw={'all_windows'},
+ varname='p_force_off',
+ -- pri_mkrc isn't needed here, optval_default()
+ -- always returns TRUE for 'compatible'
+ defaults={if_true={vi=true, vim=false}}
+ },
+ {
+ full_name='complete', abbreviation='cpt',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ alloced=true,
+ varname='p_cpt',
+ defaults={if_true={vi=".,w,b,u,t,i", vim=".,w,b,u,t"}}
+ },
+ {
+ full_name='concealcursor', abbreviation='cocu',
+ type='string', scope={'window'},
+ vi_def=true,
+ alloced=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='conceallevel', abbreviation='cole',
+ type='number', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='completefunc', abbreviation='cfu',
+ type='string', scope={'buffer'},
+ secure=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_cfu',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='completeopt', abbreviation='cot',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_cot',
+ defaults={if_true={vi="menu,preview"}}
+ },
+ {
+ full_name='confirm', abbreviation='cf',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_confirm',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='copyindent', abbreviation='ci',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_ci',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='cpoptions', abbreviation='cpo',
+ type='string', list='flags', scope={'global'},
+ vim=true,
+ redraw={'all_windows'},
+ varname='p_cpo',
+ defaults={if_true={vi=macros('CPO_VI'), vim=macros('CPO_VIM')}}
+ },
+ {
+ full_name='cscopepathcomp', abbreviation='cspc',
+ type='number', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_cspc',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='cscopeprg', abbreviation='csprg',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_csprg',
+ defaults={if_true={vi="cscope"}}
+ },
+ {
+ full_name='cscopequickfix', abbreviation='csqf',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_csqf',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='cscoperelative', abbreviation='csre',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_csre',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='cscopetag', abbreviation='cst',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_cst',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='cscopetagorder', abbreviation='csto',
+ type='number', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_csto',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='cscopeverbose', abbreviation='csverb',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_csverbose',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='cursorbind', abbreviation='crb',
+ type='bool', scope={'window'},
+ vi_def=true,
+ pv_name='p_crbind',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='cursorcolumn', abbreviation='cuc',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='cursorline', abbreviation='cul',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='debug',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_debug',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='define', abbreviation='def',
+ type='string', scope={'global', 'buffer'},
+ vi_def=true,
+ alloced=true,
+ redraw={'curswant'},
+ varname='p_def',
+ defaults={if_true={vi="^\\s*#\\s*define"}}
+ },
+ {
+ full_name='delcombine', abbreviation='deco',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_deco',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='dictionary', abbreviation='dict',
+ type='string', list='comma', scope={'global', 'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ expand=true,
+ varname='p_dict',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='diff',
+ type='bool', scope={'window'},
+ noglob=true,
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='diffexpr', abbreviation='dex',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ redraw={'curswant'},
+ varname='p_dex',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='diffopt', abbreviation='dip',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ redraw={'current_window'},
+ varname='p_dip',
+ defaults={if_true={vi="filler"}}
+ },
+ {
+ full_name='digraph', abbreviation='dg',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_dg',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='directory', abbreviation='dir',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_dir',
+ defaults={if_true={vi=macros('DFLT_DIR')}}
+ },
+ {
+ full_name='display', abbreviation='dy',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vim=true,
+ redraw={'all_windows'},
+ varname='p_dy',
+ defaults={if_true={vi="", vim="lastline"}}
+ },
+ {
+ full_name='eadirection', abbreviation='ead',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_ead',
+ defaults={if_true={vi="both"}}
+ },
+ {
+ full_name='edcompatible', abbreviation='ed',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_force_off',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='encoding', abbreviation='enc',
+ type='string', scope={'global'},
+ deny_in_modelines=true,
+ vi_def=true,
+ redraw={'everything'},
+ varname='p_enc',
+ defaults={if_true={vi=macros('ENC_DFLT')}}
+ },
+ {
+ full_name='endofline', abbreviation='eol',
+ type='bool', scope={'buffer'},
+ no_mkrc=true,
+ vi_def=true,
+ redraw={'statuslines'},
+ varname='p_eol',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='equalalways', abbreviation='ea',
+ type='bool', scope={'global'},
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_ea',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='equalprg', abbreviation='ep',
+ type='string', scope={'global', 'buffer'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_ep',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='errorbells', abbreviation='eb',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_eb',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='errorfile', abbreviation='ef',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_ef',
+ defaults={if_true={vi=macros('DFLT_ERRORFILE')}}
+ },
+ {
+ full_name='errorformat', abbreviation='efm',
+ type='string', list='comma', scope={'global', 'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_efm',
+ defaults={if_true={vi=macros('DFLT_EFM')}}
+ },
+ {
+ full_name='esckeys', abbreviation='ek',
+ type='bool', scope={'global'},
+ vim=true,
+ varname='p_ek',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='eventignore', abbreviation='ei',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_ei',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='expandtab', abbreviation='et',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_et',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='exrc', abbreviation='ex',
+ type='bool', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_exrc',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='fileencoding', abbreviation='fenc',
+ type='string', scope={'buffer'},
+ no_mkrc=true,
+ vi_def=true,
+ alloced=true,
+ redraw={'statuslines', 'current_buffer'},
+ varname='p_fenc',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='fileencodings', abbreviation='fencs',
+ type='string', list='comma', scope={'global'},
+ vi_def=true,
+ varname='p_fencs',
+ defaults={if_true={vi="ucs-bom"}}
+ },
+ {
+ full_name='fileformat', abbreviation='ff',
+ type='string', scope={'buffer'},
+ no_mkrc=true,
+ vi_def=true,
+ alloced=true,
+ redraw={'curswant', 'statuslines'},
+ varname='p_ff',
+ defaults={if_true={vi=macros('DFLT_FF')}}
+ },
+ {
+ full_name='fileformats', abbreviation='ffs',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vim=true,
+ varname='p_ffs',
+ defaults={if_true={vi=macros('DFLT_FFS_VI'), vim=macros('DFLT_FFS_VIM')}}
+ },
+ {
+ full_name='fileignorecase', abbreviation='fic',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_fic',
+ defaults={
+ condition='CASE_INSENSITIVE_FILENAME',
+ if_true={vi=true},
+ if_false={vi=false},
+ }
+ },
+ {
+ full_name='filetype', abbreviation='ft',
+ type='string', scope={'buffer'},
+ noglob=true,
+ normal_fname_chars=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_ft',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='fillchars', abbreviation='fcs',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_fcs',
+ defaults={if_true={vi="vert:|,fold:-"}}
+ },
+ {
+ full_name='fkmap', abbreviation='fk',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_fkmap',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='foldclose', abbreviation='fcl',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'current_window'},
+ varname='p_fcl',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='foldcolumn', abbreviation='fdc',
+ type='number', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='foldenable', abbreviation='fen',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='foldexpr', abbreviation='fde',
+ type='string', scope={'window'},
+ vi_def=true,
+ vim=true,
+ alloced=true,
+ redraw={'current_window'},
+ defaults={if_true={vi="0"}}
+ },
+ {
+ full_name='foldignore', abbreviation='fdi',
+ type='string', scope={'window'},
+ vi_def=true,
+ vim=true,
+ alloced=true,
+ redraw={'current_window'},
+ defaults={if_true={vi="#"}}
+ },
+ {
+ full_name='foldlevel', abbreviation='fdl',
+ type='number', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='foldlevelstart', abbreviation='fdls',
+ type='number', scope={'global'},
+ vi_def=true,
+ redraw={'curswant'},
+ varname='p_fdls',
+ defaults={if_true={vi=-1}}
+ },
+ {
+ full_name='foldmarker', abbreviation='fmr',
+ type='string', list='comma', scope={'window'},
+ deny_duplicates=true,
+ vi_def=true,
+ vim=true,
+ alloced=true,
+ redraw={'current_window'},
+ defaults={if_true={vi="{{{,}}}"}}
+ },
+ {
+ full_name='foldmethod', abbreviation='fdm',
+ type='string', scope={'window'},
+ vi_def=true,
+ vim=true,
+ alloced=true,
+ redraw={'current_window'},
+ defaults={if_true={vi="manual"}}
+ },
+ {
+ full_name='foldminlines', abbreviation='fml',
+ type='number', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='foldnestmax', abbreviation='fdn',
+ type='number', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=20}}
+ },
+ {
+ full_name='foldopen', abbreviation='fdo',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'curswant'},
+ varname='p_fdo',
+ defaults={if_true={vi="block,hor,mark,percent,quickfix,search,tag,undo"}}
+ },
+ {
+ full_name='foldtext', abbreviation='fdt',
+ type='string', scope={'window'},
+ vi_def=true,
+ vim=true,
+ alloced=true,
+ redraw={'current_window'},
+ defaults={if_true={vi="foldtext()"}}
+ },
+ {
+ full_name='formatexpr', abbreviation='fex',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ alloced=true,
+ varname='p_fex',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='formatoptions', abbreviation='fo',
+ type='string', list='flags', scope={'buffer'},
+ vim=true,
+ alloced=true,
+ varname='p_fo',
+ defaults={if_true={vi=macros('DFLT_FO_VI'), vim=macros('DFLT_FO_VIM')}}
+ },
+ {
+ full_name='formatlistpat', abbreviation='flp',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ alloced=true,
+ varname='p_flp',
+ defaults={if_true={vi="^\\s*\\d\\+[\\]:.)}\\t ]\\s*"}}
+ },
+ {
+ full_name='formatprg', abbreviation='fp',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_fp',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='fsync', abbreviation='fs',
+ type='bool', scope={'global'},
+ secure=true,
+ vi_def=true,
+ enable_if='HAVE_FSYNC',
+ varname='p_fs',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='gdefault', abbreviation='gd',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_gd',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='grepformat', abbreviation='gfm',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_gefm',
+ defaults={if_true={vi=macros('DFLT_GREPFORMAT')}}
+ },
+ {
+ full_name='grepprg', abbreviation='gp',
+ type='string', scope={'global', 'buffer'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_gp',
+ defaults={
+ condition='UNIX',
+ -- Add an extra file name so that grep will always
+ -- insert a file name in the match line. */
+ if_true={vi="grep -n $* /dev/null"},
+ if_false={vi="grep -n "},
+ }
+ },
+ {
+ full_name='guicursor', abbreviation='gcr',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_guicursor',
+ defaults={if_true={vi="n-v-c:block,o:hor50,i-ci:hor15,r-cr:hor30,sm:block"}}
+ },
+ {
+ full_name='guifont', abbreviation='gfn',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'everything'},
+ enable_if=false,
+ },
+ {
+ full_name='guifontset', abbreviation='gfs',
+ type='string', list='comma', scope={'global'},
+ vi_def=true,
+ redraw={'everything'},
+ enable_if=false,
+ },
+ {
+ full_name='guifontwide', abbreviation='gfw',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'everything'},
+ enable_if=false,
+ },
+ {
+ full_name='guiheadroom', abbreviation='ghr',
+ type='number', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ defaults={if_true={vi=50}}
+ },
+ {
+ full_name='guioptions', abbreviation='go',
+ type='string', list='flags', scope={'global'},
+ vi_def=true,
+ redraw={'all_windows'},
+ enable_if=false,
+ },
+ {
+ full_name='guitablabel', abbreviation='gtl',
+ type='string', scope={'global'},
+ vi_def=true,
+ redraw={'current_window'},
+ enable_if=false,
+ },
+ {
+ full_name='guitabtooltip', abbreviation='gtt',
+ type='string', scope={'global'},
+ vi_def=true,
+ redraw={'current_window'},
+ enable_if=false,
+ },
+ {
+ full_name='helpfile', abbreviation='hf',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_hf',
+ defaults={if_true={vi=macros('DFLT_HELPFILE')}}
+ },
+ {
+ full_name='helpheight', abbreviation='hh',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_hh',
+ defaults={if_true={vi=20}}
+ },
+ {
+ full_name='helplang', abbreviation='hlg',
+ type='string', list='comma', scope={'global'},
+ vi_def=true,
+ varname='p_hlg',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='hidden', abbreviation='hid',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_hid',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='highlight', abbreviation='hl',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'everything'},
+ varname='p_hl',
+ defaults={if_true={vi=macros('HIGHLIGHT_INIT')}}
+ },
+ {
+ full_name='history', abbreviation='hi',
+ type='number', scope={'global'},
+ vim=true,
+ varname='p_hi',
+ defaults={if_true={vi=0, vim=10000}}
+ },
+ {
+ full_name='hkmap', abbreviation='hk',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_hkmap',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='hkmapp', abbreviation='hkp',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_hkmapp',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='hlsearch', abbreviation='hls',
+ type='bool', scope={'global'},
+ vim=true,
+ redraw={'all_windows'},
+ varname='p_hls',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='icon',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_icon',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='iconstring',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_iconstring',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='ignorecase', abbreviation='ic',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_ic',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='imactivatefunc', abbreviation='imaf',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ enable_if=false,
+ },
+ {
+ full_name='imactivatekey', abbreviation='imak',
+ type='string', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='imcmdline', abbreviation='imc',
+ type='bool', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='imdisable', abbreviation='imd',
+ type='bool', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='iminsert', abbreviation='imi',
+ type='number', scope={'buffer'},
+ vi_def=true,
+ varname='p_iminsert', pv_name='p_imi',
+ defaults={
+ condition='B_IMODE_IM',
+ if_true={vi=macros('B_IMODE_IM')},
+ if_false={vi=macros('B_IMODE_NONE')},
+ }
+ },
+ {
+ full_name='imsearch', abbreviation='ims',
+ type='number', scope={'buffer'},
+ vi_def=true,
+ varname='p_imsearch', pv_name='p_ims',
+ defaults={
+ condition='B_IMODE_IM',
+ if_true={vi=macros('B_IMODE_IM')},
+ if_false={vi=macros('B_IMODE_NONE')},
+ }
+ },
+ {
+ full_name='imstatusfunc', abbreviation='imsf',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ enable_if=false,
+ },
+ {
+ full_name='include', abbreviation='inc',
+ type='string', scope={'global', 'buffer'},
+ vi_def=true,
+ alloced=true,
+ varname='p_inc',
+ defaults={if_true={vi="^\\s*#\\s*include"}}
+ },
+ {
+ full_name='includeexpr', abbreviation='inex',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ alloced=true,
+ varname='p_inex',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='incsearch', abbreviation='is',
+ type='bool', scope={'global'},
+ vim=true,
+ varname='p_is',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='indentexpr', abbreviation='inde',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ alloced=true,
+ varname='p_inde',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='indentkeys', abbreviation='indk',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_indk',
+ defaults={if_true={vi="0{,0},:,0#,!^F,o,O,e"}}
+ },
+ {
+ full_name='infercase', abbreviation='inf',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ varname='p_inf',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='insertmode', abbreviation='im',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_im',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='isfname', abbreviation='isf',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_isf',
+ defaults={
+ condition='BACKSLASH_IN_FILENAME',
+ -- Excluded are: & and ^ are special in cmd.exe
+ -- ( and ) are used in text separating fnames */
+ if_true={vi="@,48-57,/,\\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,="},
+ if_false={vi="@,48-57,/,.,-,_,+,,,#,$,%,~,="}
+ }
+ },
+ {
+ full_name='isident', abbreviation='isi',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_isi',
+ defaults={if_true={vi="@,48-57,_,192-255"}}
+ },
+ {
+ full_name='iskeyword', abbreviation='isk',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ vim=true,
+ alloced=true,
+ varname='p_isk',
+ defaults={if_true={vi="@,48-57,_", vim=macros('ISK_LATIN1')}}
+ },
+ {
+ full_name='isprint', abbreviation='isp',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_isp',
+ defaults={
+ condition='MSWIN',
+ if_true={vi="@,~-255"},
+ if_false={vi=macros("ISP_LATIN1")}
+ }
+ },
+ {
+ full_name='joinspaces', abbreviation='js',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_js',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='keymap', abbreviation='kmp',
+ type='string', scope={'buffer'},
+ normal_fname_chars=true,
+ pri_mkrc=true,
+ vi_def=true,
+ alloced=true,
+ redraw={'statuslines', 'current_buffer'},
+ varname='p_keymap', pv_name='p_kmap',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='keymodel', abbreviation='km',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_km',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='keywordprg', abbreviation='kp',
+ type='string', scope={'global', 'buffer'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_kp',
+ defaults={
+ condition='USEMAN_S',
+ if_true={vi="man -s"},
+ if_false={vi="man"},
+ }
+ },
+ {
+ full_name='langmap', abbreviation='lmap',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ secure=true,
+ vi_def=true,
+ varname='p_langmap',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='langmenu', abbreviation='lm',
+ type='string', scope={'global'},
+ normal_fname_chars=true,
+ vi_def=true,
+ varname='p_lm',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='langnoremap', abbreviation='lnr',
+ type='bool', scope={'global'},
+ varname='p_lnr',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='laststatus', abbreviation='ls',
+ type='number', scope={'global'},
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_ls',
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='lazyredraw', abbreviation='lz',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_lz',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='linebreak', abbreviation='lbr',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='lines',
+ type='number', scope={'global'},
+ no_mkrc=true,
+ nodefault=true,
+ vi_def=true,
+ redraw={'everything'},
+ varname='Rows',
+ defaults={if_true={vi=macros('DFLT_ROWS')}}
+ },
+ {
+ full_name='linespace', abbreviation='lsp',
+ type='number', scope={'global'},
+ vi_def=true,
+ redraw={'everything'},
+ enable_if=false,
+ },
+ {
+ full_name='lisp',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ varname='p_lisp',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='lispwords', abbreviation='lw',
+ type='string', list='comma', scope={'global', 'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_lispwords', pv_name='p_lw',
+ defaults={if_true={vi=macros('LISPWORD_VALUE')}}
+ },
+ {
+ full_name='list',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='listchars', abbreviation='lcs',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_lcs',
+ defaults={if_true={vi="eol:$"}}
+ },
+ {
+ full_name='loadplugins', abbreviation='lpl',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_lpl',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='magic',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_magic',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='makeef', abbreviation='mef',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_mef',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='makeprg', abbreviation='mp',
+ type='string', scope={'global', 'buffer'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_mp',
+ defaults={if_true={vi="make"}}
+ },
+ {
+ full_name='matchpairs', abbreviation='mps',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_mps',
+ defaults={if_true={vi="(:),{:},[:]"}}
+ },
+ {
+ full_name='matchtime', abbreviation='mat',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mat',
+ defaults={if_true={vi=5}}
+ },
+ {
+ full_name='maxcombine', abbreviation='mco',
+ type='number', scope={'global'},
+ vi_def=true,
+ redraw={'curswant'},
+ varname='p_mco',
+ defaults={if_true={vi=2}}
+ },
+ {
+ full_name='maxfuncdepth', abbreviation='mfd',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mfd',
+ defaults={if_true={vi=100}}
+ },
+ {
+ full_name='maxmapdepth', abbreviation='mmd',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mmd',
+ defaults={if_true={vi=1000}}
+ },
+ {
+ full_name='maxmem', abbreviation='mm',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mm',
+ defaults={if_true={vi=macros('DFLT_MAXMEM')}}
+ },
+ {
+ full_name='maxmempattern', abbreviation='mmp',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mmp',
+ defaults={if_true={vi=1000}}
+ },
+ {
+ full_name='maxmemtot', abbreviation='mmt',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mmt',
+ defaults={if_true={vi=macros('DFLT_MAXMEMTOT')}}
+ },
+ {
+ full_name='menuitems', abbreviation='mis',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mis',
+ defaults={if_true={vi=25}}
+ },
+ {
+ full_name='mkspellmem', abbreviation='msm',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_msm',
+ defaults={if_true={vi="460000,2000,500"}}
+ },
+ {
+ full_name='modeline', abbreviation='ml',
+ type='bool', scope={'buffer'},
+ vim=true,
+ varname='p_ml',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='modelines', abbreviation='mls',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mls',
+ defaults={if_true={vi=5}}
+ },
+ {
+ full_name='modifiable', abbreviation='ma',
+ type='bool', scope={'buffer'},
+ noglob=true,
+ vi_def=true,
+ varname='p_ma',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='modified', abbreviation='mod',
+ type='bool', scope={'buffer'},
+ no_mkrc=true,
+ vi_def=true,
+ redraw={'statuslines'},
+ varname='p_mod',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='more',
+ type='bool', scope={'global'},
+ vim=true,
+ varname='p_more',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='mouse',
+ type='string', list='flags', scope={'global'},
+ varname='p_mouse',
+ defaults={if_true={vi="", vim="a"}}
+ },
+ {
+ full_name='mousefocus', abbreviation='mousef',
+ type='bool', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='mousehide', abbreviation='mh',
+ type='bool', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='mousemodel', abbreviation='mousem',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_mousem',
+ defaults={if_true={vi="extend"}}
+ },
+ {
+ full_name='mouseshape', abbreviation='mouses',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ enable_if=false,
+ },
+ {
+ full_name='mousetime', abbreviation='mouset',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_mouset',
+ defaults={if_true={vi=500}}
+ },
+ {
+ full_name='nrformats', abbreviation='nf',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ alloced=true,
+ varname='p_nf',
+ defaults={if_true={vi="octal,hex", vim="hex"}}
+ },
+ {
+ full_name='number', abbreviation='nu',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='numberwidth', abbreviation='nuw',
+ type='number', scope={'window'},
+ vim=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=8, vim=4}}
+ },
+ {
+ full_name='omnifunc', abbreviation='ofu',
+ type='string', scope={'buffer'},
+ secure=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_ofu',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='opendevice', abbreviation='odev',
+ type='bool', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ defaults={if_true={vi=false, vim=false}}
+ },
+ {
+ full_name='operatorfunc', abbreviation='opfunc',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_opfunc',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='paragraphs', abbreviation='para',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_para',
+ defaults={if_true={vi="IPLPPPQPP TPHPLIPpLpItpplpipbp"}}
+ },
+ {
+ full_name='paste',
+ type='bool', scope={'global'},
+ pri_mkrc=true,
+ vi_def=true,
+ varname='p_paste',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='pastetoggle', abbreviation='pt',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_pt',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='patchexpr', abbreviation='pex',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_pex',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='patchmode', abbreviation='pm',
+ type='string', scope={'global'},
+ normal_fname_chars=true,
+ vi_def=true,
+ varname='p_pm',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='path', abbreviation='pa',
+ type='string', list='comma', scope={'global', 'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ expand=true,
+ varname='p_path',
+ defaults={if_true={vi=".,/usr/include,,"}}
+ },
+ {
+ full_name='preserveindent', abbreviation='pi',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_pi',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='previewheight', abbreviation='pvh',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_pvh',
+ defaults={if_true={vi=12}}
+ },
+ {
+ full_name='previewwindow', abbreviation='pvw',
+ type='bool', scope={'window'},
+ noglob=true,
+ vi_def=true,
+ redraw={'statuslines'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='printdevice', abbreviation='pdev',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_pdev',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='printencoding', abbreviation='penc',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_penc',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='printexpr', abbreviation='pexpr',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_pexpr',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='printfont', abbreviation='pfn',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_pfn',
+ defaults={if_true={vi="courier"}}
+ },
+ {
+ full_name='printheader', abbreviation='pheader',
+ type='string', scope={'global'},
+ gettext=true,
+ vi_def=true,
+ varname='p_header',
+ defaults={if_true={vi=N_("%<%f%h%m%=Page %N")}}
+ },
+ {
+ full_name='printmbcharset', abbreviation='pmbcs',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_pmcs',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='printmbfont', abbreviation='pmbfn',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_pmfn',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='printoptions', abbreviation='popt',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_popt',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='prompt',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_prompt',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='pumheight', abbreviation='ph',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_ph',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='quoteescape', abbreviation='qe',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ alloced=true,
+ varname='p_qe',
+ defaults={if_true={vi="\\"}}
+ },
+ {
+ full_name='readonly', abbreviation='ro',
+ type='bool', scope={'buffer'},
+ noglob=true,
+ vi_def=true,
+ redraw={'statuslines'},
+ varname='p_ro',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='redrawtime', abbreviation='rdt',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_rdt',
+ defaults={if_true={vi=2000}}
+ },
+ {
+ full_name='regexpengine', abbreviation='re',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_re',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='relativenumber', abbreviation='rnu',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='remap',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_remap',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='report',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_report',
+ defaults={if_true={vi=2}}
+ },
+ {
+ full_name='restorescreen', abbreviation='rs',
+ type='bool', scope={'global'},
+ vi_def=true,
+ enable_if=false,
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='revins', abbreviation='ri',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_ri',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='rightleft', abbreviation='rl',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='rightleftcmd', abbreviation='rlc',
+ type='string', scope={'window'},
+ vi_def=true,
+ alloced=true,
+ redraw={'current_window'},
+ defaults={if_true={vi="search"}}
+ },
+ {
+ full_name='ruler', abbreviation='ru',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ redraw={'statuslines'},
+ varname='p_ru',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='rulerformat', abbreviation='ruf',
+ type='string', scope={'global'},
+ vi_def=true,
+ alloced=true,
+ redraw={'statuslines'},
+ varname='p_ruf',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='runtimepath', abbreviation='rtp',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_rtp',
+ defaults={if_true={vi=macros('DFLT_RUNTIMEPATH')}}
+ },
+ {
+ full_name='scroll', abbreviation='scr',
+ type='number', scope={'window'},
+ no_mkrc=true,
+ vi_def=true,
+ pv_name='p_scroll',
+ defaults={if_true={vi=12}}
+ },
+ {
+ full_name='scrollbind', abbreviation='scb',
+ type='bool', scope={'window'},
+ vi_def=true,
+ pv_name='p_scbind',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='scrolljump', abbreviation='sj',
+ type='number', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_sj',
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='scrolloff', abbreviation='so',
+ type='number', scope={'global'},
+ vi_def=true,
+ vim=true,
+ redraw={'all_windows'},
+ varname='p_so',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='scrollopt', abbreviation='sbo',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_sbo',
+ defaults={if_true={vi="ver,jump"}}
+ },
+ {
+ full_name='sections', abbreviation='sect',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_sections',
+ defaults={if_true={vi="SHNHH HUnhsh"}}
+ },
+ {
+ full_name='secure',
+ type='bool', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_secure',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='selection', abbreviation='sel',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_sel',
+ defaults={if_true={vi="inclusive"}}
+ },
+ {
+ full_name='selectmode', abbreviation='slm',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_slm',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='sessionoptions', abbreviation='ssop',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vim=true,
+ varname='p_ssop',
+ defaults={if_true={
+ vi="blank,buffers,curdir,folds,help,options,tabpages,winsize",
+ vim="blank,buffers,curdir,folds,help,tabpages,winsize"
+ }}
+ },
+ {
+ full_name='shell', abbreviation='sh',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_sh',
+ defaults={if_true={vi="sh"}}
+ },
+ {
+ full_name='shellcmdflag', abbreviation='shcf',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_shcf',
+ defaults={if_true={vi="-c"}}
+ },
+ {
+ full_name='shellpipe', abbreviation='sp',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_sp',
+ defaults={
+ condition='UNIX',
+ if_true={vi="| tee"},
+ if_false={vi=">"},
+ }
+ },
+ {
+ full_name='shellquote', abbreviation='shq',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_shq',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='shellredir', abbreviation='srr',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_srr',
+ defaults={if_true={vi=">"}}
+ },
+ {
+ full_name='shellslash', abbreviation='ssl',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_ssl',
+ enable_if='BACKSLASH_IN_FILENAME',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='shelltemp', abbreviation='stmp',
+ type='bool', scope={'global'},
+ varname='p_stmp',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='shellxquote', abbreviation='sxq',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_sxq',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='shellxescape', abbreviation='sxe',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ varname='p_sxe',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='shiftround', abbreviation='sr',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_sr',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='shiftwidth', abbreviation='sw',
+ type='number', scope={'buffer'},
+ vi_def=true,
+ varname='p_sw',
+ defaults={if_true={vi=8}}
+ },
+ {
+ full_name='shortmess', abbreviation='shm',
+ type='string', list='flags', scope={'global'},
+ vim=true,
+ varname='p_shm',
+ defaults={if_true={vi="", vim="filnxtToO"}}
+ },
+ {
+ full_name='showbreak', abbreviation='sbr',
+ type='string', scope={'global'},
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_sbr',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='showcmd', abbreviation='sc',
+ type='bool', scope={'global'},
+ vim=true,
+ varname='p_sc',
+ defaults={
+ condition='UNIX',
+ if_true={vi=false, vim=false},
+ if_false={vi=false, vim=true},
+ }
+ },
+ {
+ full_name='showfulltag', abbreviation='sft',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_sft',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='showmatch', abbreviation='sm',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_sm',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='showmode', abbreviation='smd',
+ type='bool', scope={'global'},
+ vim=true,
+ varname='p_smd',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='showtabline', abbreviation='stal',
+ type='number', scope={'global'},
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_stal',
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='sidescroll', abbreviation='ss',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_ss',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='sidescrolloff', abbreviation='siso',
+ type='number', scope={'global'},
+ vi_def=true,
+ vim=true,
+ redraw={'current_buffer'},
+ varname='p_siso',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='smartcase', abbreviation='scs',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_scs',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='smartindent', abbreviation='si',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_si',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='smarttab', abbreviation='sta',
+ type='bool', scope={'global'},
+ vim=true,
+ varname='p_sta',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='softtabstop', abbreviation='sts',
+ type='number', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_sts',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='spell',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='spellcapcheck', abbreviation='spc',
+ type='string', scope={'buffer'},
+ vi_def=true,
+ alloced=true,
+ redraw={'current_buffer'},
+ varname='p_spc',
+ defaults={if_true={vi="[.?!]\\_[\\])'\" ]\\+"}}
+ },
+ {
+ full_name='spellfile', abbreviation='spf',
+ type='string', list='comma', scope={'buffer'},
+ secure=true,
+ vi_def=true,
+ alloced=true,
+ expand=true,
+ varname='p_spf',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='spelllang', abbreviation='spl',
+ type='string', list='comma', scope={'buffer'},
+ vi_def=true,
+ alloced=true,
+ expand=true,
+ redraw={'current_buffer'},
+ varname='p_spl',
+ defaults={if_true={vi="en"}}
+ },
+ {
+ full_name='spellsuggest', abbreviation='sps',
+ type='string', list='comma', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_sps',
+ defaults={if_true={vi="best"}}
+ },
+ {
+ full_name='splitbelow', abbreviation='sb',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_sb',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='splitright', abbreviation='spr',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_spr',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='startofline', abbreviation='sol',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_sol',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='statusline', abbreviation='stl',
+ type='string', scope={'global', 'window'},
+ vi_def=true,
+ alloced=true,
+ redraw={'statuslines'},
+ varname='p_stl',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='suffixes', abbreviation='su',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_su',
+ defaults={if_true={vi=".bak,~,.o,.h,.info,.swp,.obj"}}
+ },
+ {
+ full_name='suffixesadd', abbreviation='sua',
+ type='string', list='comma', scope={'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_sua',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='swapfile', abbreviation='swf',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ redraw={'statuslines'},
+ varname='p_swf',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='swapsync', abbreviation='sws',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_sws',
+ defaults={if_true={vi="fsync"}}
+ },
+ {
+ full_name='switchbuf', abbreviation='swb',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_swb',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='synmaxcol', abbreviation='smc',
+ type='number', scope={'buffer'},
+ vi_def=true,
+ redraw={'current_buffer'},
+ varname='p_smc',
+ defaults={if_true={vi=3000}}
+ },
+ {
+ full_name='syntax', abbreviation='syn',
+ type='string', scope={'buffer'},
+ noglob=true,
+ normal_fname_chars=true,
+ vi_def=true,
+ alloced=true,
+ varname='p_syn',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='tabline', abbreviation='tal',
+ type='string', scope={'global'},
+ vi_def=true,
+ redraw={'all_windows'},
+ varname='p_tal',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='tabpagemax', abbreviation='tpm',
+ type='number', scope={'global'},
+ vim=true,
+ varname='p_tpm',
+ defaults={if_true={vi=10, vim=50}}
+ },
+ {
+ full_name='tabstop', abbreviation='ts',
+ type='number', scope={'buffer'},
+ vi_def=true,
+ redraw={'current_buffer'},
+ varname='p_ts',
+ defaults={if_true={vi=8}}
+ },
+ {
+ full_name='tagbsearch', abbreviation='tbs',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_tbs',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='taglength', abbreviation='tl',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_tl',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='tagrelative', abbreviation='tr',
+ type='bool', scope={'global'},
+ vim=true,
+ varname='p_tr',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='tags', abbreviation='tag',
+ type='string', list='comma', scope={'global', 'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ expand=true,
+ varname='p_tags',
+ defaults={if_true={vi="./tags;,tags"}}
+ },
+ {
+ full_name='tagstack', abbreviation='tgst',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_tgst',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='termbidi', abbreviation='tbidi',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_tbidi',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='termencoding', abbreviation='tenc',
+ type='string', scope={'global'},
+ vi_def=true,
+ redraw={'everything'},
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='terse',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_terse',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='textwidth', abbreviation='tw',
+ type='number', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ redraw={'current_buffer'},
+ varname='p_tw',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='thesaurus', abbreviation='tsr',
+ type='string', list='comma', scope={'global', 'buffer'},
+ deny_duplicates=true,
+ vi_def=true,
+ expand=true,
+ varname='p_tsr',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='tildeop', abbreviation='top',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_to',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='timeout', abbreviation='to',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_timeout',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='timeoutlen', abbreviation='tm',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_tm',
+ defaults={if_true={vi=1000}}
+ },
+ {
+ full_name='title',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_title',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='titlelen',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_titlelen',
+ defaults={if_true={vi=85}}
+ },
+ {
+ full_name='titleold',
+ type='string', scope={'global'},
+ secure=true,
+ gettext=true,
+ no_mkrc=true,
+ vi_def=true,
+ varname='p_titleold',
+ defaults={if_true={vi=N_("Thanks for flying Vim")}}
+ },
+ {
+ full_name='titlestring',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_titlestring',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='ttimeout',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_ttimeout',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='ttimeoutlen', abbreviation='ttm',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_ttm',
+ defaults={if_true={vi=-1}}
+ },
+ {
+ full_name='ttyfast', abbreviation='tf',
+ type='bool', scope={'global'},
+ no_mkrc=true,
+ vi_def=true,
+ varname='p_force_on',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='undodir', abbreviation='udir',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_udir',
+ defaults={if_true={vi="."}}
+ },
+ {
+ full_name='undofile', abbreviation='udf',
+ type='bool', scope={'buffer'},
+ vi_def=true,
+ vim=true,
+ varname='p_udf',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='undolevels', abbreviation='ul',
+ type='number', scope={'global', 'buffer'},
+ vi_def=true,
+ varname='p_ul',
+ defaults={
+ condition={'!UNIX', '!WIN3264'},
+ if_true={vi=100},
+ if_false={vi=1000},
+ }
+ },
+ {
+ full_name='undoreload', abbreviation='ur',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_ur',
+ defaults={if_true={vi=10000}}
+ },
+ {
+ full_name='updatecount', abbreviation='uc',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_uc',
+ defaults={if_true={vi=200}}
+ },
+ {
+ full_name='updatetime', abbreviation='ut',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_ut',
+ defaults={if_true={vi=4000}}
+ },
+ {
+ full_name='verbose', abbreviation='vbs',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_verbose',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='verbosefile', abbreviation='vfile',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_vfile',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='viewdir', abbreviation='vdir',
+ type='string', scope={'global'},
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_vdir',
+ defaults={if_true={vi=macros('DFLT_VDIR')}}
+ },
+ {
+ full_name='viewoptions', abbreviation='vop',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_vop',
+ defaults={if_true={vi="folds,options,cursor"}}
+ },
+ {
+ full_name='viminfo', abbreviation='vi',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ secure=true,
+ varname='p_viminfo',
+ defaults={if_true={vi="", vim="!,'100,<50,s10,h"}}
+ },
+ {
+ full_name='virtualedit', abbreviation='ve',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ vim=true,
+ redraw={'curswant'},
+ varname='p_ve',
+ defaults={if_true={vi="", vim=""}}
+ },
+ {
+ full_name='visualbell', abbreviation='vb',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_vb',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='warn',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_warn',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='whichwrap', abbreviation='ww',
+ type='string', list='flagscomma', scope={'global'},
+ vim=true,
+ varname='p_ww',
+ defaults={if_true={vi="", vim="b,s"}}
+ },
+ {
+ full_name='wildchar', abbreviation='wc',
+ type='number', scope={'global'},
+ vim=true,
+ varname='p_wc',
+ defaults={if_true={vi=macros('Ctrl_E'), vim=macros('TAB')}}
+ },
+ {
+ full_name='wildcharm', abbreviation='wcm',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_wcm',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='wildignore', abbreviation='wig',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vi_def=true,
+ varname='p_wig',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='wildignorecase', abbreviation='wic',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_wic',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='wildmenu', abbreviation='wmnu',
+ type='bool', scope={'global'},
+ vim=true,
+ varname='p_wmnu',
+ defaults={if_true={vi=false, vim=true}}
+ },
+ {
+ full_name='wildmode', abbreviation='wim',
+ type='string', list='comma', scope={'global'},
+ deny_duplicates=true,
+ vim=true,
+ varname='p_wim',
+ defaults={if_true={vi="", vim="list:longest,full"}}
+ },
+ {
+ full_name='wildoptions', abbreviation='wop',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_wop',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='winaltkeys', abbreviation='wak',
+ type='string', scope={'global'},
+ vi_def=true,
+ varname='p_wak',
+ defaults={if_true={vi="menu"}}
+ },
+ {
+ full_name='window', abbreviation='wi',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_window',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='winheight', abbreviation='wh',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_wh',
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='winfixheight', abbreviation='wfh',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'statuslines'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='winfixwidth', abbreviation='wfw',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'statuslines'},
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='winminheight', abbreviation='wmh',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_wmh',
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='winminwidth', abbreviation='wmw',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_wmw',
+ defaults={if_true={vi=1}}
+ },
+ {
+ full_name='winwidth', abbreviation='wiw',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_wiw',
+ defaults={if_true={vi=20}}
+ },
+ {
+ full_name='wrap',
+ type='bool', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='wrapmargin', abbreviation='wm',
+ type='number', scope={'buffer'},
+ vi_def=true,
+ varname='p_wm',
+ defaults={if_true={vi=0}}
+ },
+ {
+ full_name='wrapscan', abbreviation='ws',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_ws',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='write',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_write',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='writeany', abbreviation='wa',
+ type='bool', scope={'global'},
+ vi_def=true,
+ varname='p_wa',
+ defaults={if_true={vi=false}}
+ },
+ {
+ full_name='writebackup', abbreviation='wb',
+ type='bool', scope={'global'},
+ vi_def=true,
+ vim=true,
+ varname='p_wb',
+ defaults={if_true={vi=true}}
+ },
+ {
+ full_name='writedelay', abbreviation='wd',
+ type='number', scope={'global'},
+ vi_def=true,
+ varname='p_wd',
+ defaults={if_true={vi=0}}
+ },
+ }
+}
diff --git a/src/nvim/os/event.c b/src/nvim/os/event.c
deleted file mode 100644
index 56874b495d..0000000000
--- a/src/nvim/os/event.c
+++ /dev/null
@@ -1,177 +0,0 @@
-#include <assert.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include <uv.h>
-
-#include "nvim/os/event.h"
-#include "nvim/os/input.h"
-#include "nvim/msgpack_rpc/defs.h"
-#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/msgpack_rpc/server.h"
-#include "nvim/msgpack_rpc/helpers.h"
-#include "nvim/os/signal.h"
-#include "nvim/os/rstream.h"
-#include "nvim/os/wstream.h"
-#include "nvim/os/job.h"
-#include "nvim/vim.h"
-#include "nvim/memory.h"
-#include "nvim/misc2.h"
-#include "nvim/ui.h"
-#include "nvim/screen.h"
-#include "nvim/terminal.h"
-
-#include "nvim/lib/klist.h"
-
-// event will be cleaned up after it gets processed
-#define _destroy_event(x) // do nothing
-KLIST_INIT(Event, Event, _destroy_event)
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/event.c.generated.h"
-#endif
-// deferred_events: Events that should be processed as the K_EVENT special key
-// immediate_events: Events that should be processed after exiting libuv event
-// loop(to avoid recursion), but before returning from
-// `event_poll`
-static klist_t(Event) *deferred_events = NULL, *immediate_events = NULL;
-static int deferred_events_allowed = 0;
-
-void event_init(void)
-{
- // Initialize the event queues
- deferred_events = kl_init(Event);
- immediate_events = kl_init(Event);
- // early msgpack-rpc initialization
- msgpack_rpc_init_method_table();
- msgpack_rpc_helpers_init();
- // Initialize input events
- input_init();
- // Timer to wake the event loop if a timeout argument is passed to
- // `event_poll`
- // Signals
- signal_init();
- // Jobs
- job_init();
- // finish mspgack-rpc initialization
- channel_init();
- server_init();
- terminal_init();
-}
-
-void event_teardown(void)
-{
- if (!deferred_events) {
- // Not initialized(possibly a --version invocation)
- return;
- }
-
- process_events_from(immediate_events);
- process_events_from(deferred_events);
- input_stop();
- channel_teardown();
- job_teardown();
- server_teardown();
- signal_teardown();
- terminal_teardown();
-
- // this last `uv_run` will return after all handles are stopped, it will
- // also take care of finishing any uv_close calls made by other *_teardown
- // functions.
- do {
- uv_run(uv_default_loop(), UV_RUN_DEFAULT);
- } while (uv_loop_close(uv_default_loop()));
-}
-
-// Wait for some event
-void event_poll(int ms)
-{
- static int recursive = 0;
-
- if (recursive++) {
- abort(); // Should not re-enter uv_run
- }
-
- uv_run_mode run_mode = UV_RUN_ONCE;
- uv_timer_t timer;
-
- if (ms > 0) {
- uv_timer_init(uv_default_loop(), &timer);
- // Use a repeating timeout of ms milliseconds to make sure
- // we do not block indefinitely for I/O.
- uv_timer_start(&timer, timer_cb, (uint64_t)ms, (uint64_t)ms);
- } else if (ms == 0) {
- // For ms == 0, we need to do a non-blocking event poll by
- // setting the run mode to UV_RUN_NOWAIT.
- run_mode = UV_RUN_NOWAIT;
- }
-
- loop(run_mode);
-
- if (ms > 0) {
- // Ensure the timer handle is closed and run the event loop
- // once more to let libuv perform it's cleanup
- uv_timer_stop(&timer);
- uv_close((uv_handle_t *)&timer, NULL);
- loop(UV_RUN_NOWAIT);
- }
-
- recursive--; // Can re-enter uv_run now
-
- // In case this is run before event_init, don't process any events.
- if (immediate_events) {
- process_events_from(immediate_events);
- }
-}
-
-bool event_has_deferred(void)
-{
- return deferred_events_allowed && !kl_empty(deferred_events);
-}
-
-void event_enable_deferred(void)
-{
- ++deferred_events_allowed;
-}
-
-void event_disable_deferred(void)
-{
- --deferred_events_allowed;
-}
-
-// Queue an event
-void event_push(Event event, bool deferred)
-{
- // Sometimes libuv will run pending callbacks(timer for example) before
- // blocking for a poll. If this happens and the callback pushes a event to one
- // of the queues, the event would only be processed after the poll
- // returns(user hits a key for example). To avoid this scenario, we call
- // uv_stop when a event is enqueued.
- uv_stop(uv_default_loop());
- kl_push(Event, deferred ? deferred_events : immediate_events, event);
-}
-
-void event_process(void)
-{
- process_events_from(deferred_events);
-}
-
-static void process_events_from(klist_t(Event) *queue)
-{
- while (!kl_empty(queue)) {
- Event event = kl_shift(Event, queue);
- event.handler(event);
- }
-}
-
-static void timer_cb(uv_timer_t *handle)
-{
-}
-
-static void loop(uv_run_mode run_mode)
-{
- DLOG("Enter event loop");
- uv_run(uv_default_loop(), run_mode);
- DLOG("Exit event loop");
-}
diff --git a/src/nvim/os/event.h b/src/nvim/os/event.h
deleted file mode 100644
index db02b38c7f..0000000000
--- a/src/nvim/os/event.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef NVIM_OS_EVENT_H
-#define NVIM_OS_EVENT_H
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#include "nvim/os/event_defs.h"
-#include "nvim/os/job_defs.h"
-#include "nvim/os/time.h"
-
-// Poll for events until a condition or timeout
-#define event_poll_until(timeout, condition) \
- do { \
- int remaining = timeout; \
- uint64_t before = (remaining > 0) ? os_hrtime() : 0; \
- while (!(condition)) { \
- event_poll(remaining); \
- if (remaining == 0) { \
- break; \
- } else if (remaining > 0) { \
- uint64_t now = os_hrtime(); \
- remaining -= (int) ((now - before) / 1000000); \
- before = now; \
- if (remaining <= 0) { \
- break; \
- } \
- } \
- } \
- } while (0)
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/event.h.generated.h"
-#endif
-
-#endif // NVIM_OS_EVENT_H
diff --git a/src/nvim/os/event_defs.h b/src/nvim/os/event_defs.h
deleted file mode 100644
index 2dd9403d9f..0000000000
--- a/src/nvim/os/event_defs.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef NVIM_OS_EVENT_DEFS_H
-#define NVIM_OS_EVENT_DEFS_H
-
-#include <stdbool.h>
-
-#include "nvim/os/job_defs.h"
-#include "nvim/os/rstream_defs.h"
-
-typedef struct event Event;
-typedef void (*event_handler)(Event event);
-
-struct event {
- void *data;
- event_handler handler;
-};
-
-#endif // NVIM_OS_EVENT_DEFS_H
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 553dda5e88..e4776999e5 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -279,19 +279,31 @@ bool os_file_is_readonly(const char *name)
return access(name, W_OK) != 0;
}
+/// Check if a file is readable.
+///
+/// @return true if `name` is readable, otherwise false.
+bool os_file_is_readable(const char *name)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ uv_fs_t req;
+ int r = uv_fs_access(&fs_loop, &req, name, R_OK, NULL);
+ uv_fs_req_cleanup(&req);
+ return (r == 0);
+}
+
/// Check if a file is writable.
///
/// @return `0` if `name` is not writable,
/// @return `1` if `name` is writable,
/// @return `2` for a directory which we have rights to write into.
int os_file_is_writable(const char *name)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- if (access(name, W_OK) == 0) {
- if (os_isdir((char_u *)name)) {
- return 2;
- }
- return 1;
+ uv_fs_t req;
+ int r = uv_fs_access(&fs_loop, &req, name, W_OK, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r == 0) {
+ return os_isdir((char_u *)name) ? 2 : 1;
}
return 0;
}
@@ -316,7 +328,7 @@ int os_rename(const char_u *path, const char_u *new_path)
/// Make a directory.
///
-/// @return `0` for success, non-zero for failure.
+/// @return `0` for success, -errno for failure.
int os_mkdir(const char *path, int32_t mode)
FUNC_ATTR_NONNULL_ALL
{
@@ -326,6 +338,54 @@ int os_mkdir(const char *path, int32_t mode)
return result;
}
+/// Make a directory, with higher levels when needed
+///
+/// @param[in] dir Directory to create.
+/// @param[in] mode Permissions for the newly-created directory.
+/// @param[out] failed_dir If it failed to create directory, then this
+/// argument is set to an allocated string containing
+/// the name of the directory which os_mkdir_recurse
+/// failed to create. I.e. it will contain dir or any
+/// of the higher level directories.
+///
+/// @return `0` for success, -errno for failure.
+int os_mkdir_recurse(const char *const dir, int32_t mode,
+ char **const failed_dir)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // Get end of directory name in "dir".
+ // We're done when it's "/" or "c:/".
+ const size_t dirlen = strlen(dir);
+ char *const curdir = xmemdupz(dir, dirlen);
+ char *const past_head = (char *) get_past_head((char_u *) curdir);
+ char *e = curdir + dirlen;
+ const char *const real_end = e;
+ const char past_head_save = *past_head;
+ while (!os_isdir((char_u *) curdir)) {
+ e = (char *) path_tail_with_sep((char_u *) curdir);
+ if (e <= past_head) {
+ *past_head = NUL;
+ break;
+ }
+ *e = NUL;
+ }
+ while (e != real_end) {
+ if (e > past_head) {
+ *e = '/';
+ } else {
+ *past_head = past_head_save;
+ }
+ e += strlen(e);
+ int ret;
+ if ((ret = os_mkdir(curdir, mode)) != 0) {
+ *failed_dir = curdir;
+ return ret;
+ }
+ }
+ xfree(curdir);
+ return 0;
+}
+
/// Create a unique temporary directory.
///
/// @param[in] template Template of the path to the directory with XXXXXX
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 726335bd9a..09f162f79d 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -6,9 +6,8 @@
#include "nvim/api/private/defs.h"
#include "nvim/os/input.h"
-#include "nvim/os/event.h"
-#include "nvim/os/rstream_defs.h"
-#include "nvim/os/rstream.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/rstream.h"
#include "nvim/ascii.h"
#include "nvim/vim.h"
#include "nvim/ui.h"
@@ -30,10 +29,11 @@ typedef enum {
kInputEof
} InbufPollResult;
-static RStream *read_stream = NULL;
-static RBuffer *read_buffer = NULL, *input_buffer = NULL;
+static Stream read_stream = {.closed = true};
+static RBuffer *input_buffer = NULL;
static bool input_eof = false;
static int global_fd = 0;
+static int events_enabled = 0;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/input.c.generated.h"
@@ -54,26 +54,23 @@ int input_global_fd(void)
void input_start(int fd)
{
- if (read_stream) {
+ if (!read_stream.closed) {
return;
}
global_fd = fd;
- read_buffer = rbuffer_new(READ_BUFFER_SIZE);
- read_stream = rstream_new(read_cb, read_buffer, NULL);
- rstream_set_file(read_stream, fd);
- rstream_start(read_stream);
+ rstream_init_fd(&loop, &read_stream, fd, READ_BUFFER_SIZE, NULL);
+ rstream_start(&read_stream, read_cb);
}
void input_stop(void)
{
- if (!read_stream) {
+ if (read_stream.closed) {
return;
}
- rstream_stop(read_stream);
- rstream_free(read_stream);
- read_stream = NULL;
+ rstream_stop(&read_stream);
+ stream_close(&read_stream, NULL);
}
// Low level input function
@@ -114,8 +111,8 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
}
- // If there are deferred events, return the keys directly
- if (event_has_deferred()) {
+ // If there are events, return the keys directly
+ if (pending_events()) {
return push_event_key(buf, maxlen);
}
@@ -135,11 +132,21 @@ bool os_char_avail(void)
// Check for CTRL-C typed by reading all available characters.
void os_breakcheck(void)
{
- if (!disable_breakcheck && !got_int) {
- event_poll(0);
+ if (!got_int) {
+ loop_poll_events(&loop, 0);
}
}
+void input_enable_events(void)
+{
+ events_enabled++;
+}
+
+void input_disable_events(void)
+{
+ events_enabled--;
+}
+
/// Test whether a file descriptor refers to a terminal.
///
/// @param fd File descriptor.
@@ -285,7 +292,7 @@ static bool input_poll(int ms)
prof_inchar_enter();
}
- event_poll_until(ms, input_ready() || input_eof);
+ LOOP_PROCESS_EVENTS_UNTIL(&loop, NULL, ms, input_ready() || input_eof);
if (do_profiling == PROF_YES && ms) {
prof_inchar_exit();
@@ -309,16 +316,17 @@ static InbufPollResult inbuf_poll(int ms)
return input_eof ? kInputEof : kInputNone;
}
-static void read_cb(RStream *rstream, RBuffer *buf, void *data, bool at_eof)
+static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
+ bool at_eof)
{
if (at_eof) {
input_eof = true;
}
- assert(rbuffer_space(input_buffer) >= rbuffer_size(read_buffer));
- RBUFFER_UNTIL_EMPTY(read_buffer, ptr, len) {
+ assert(rbuffer_space(input_buffer) >= rbuffer_size(buf));
+ RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
(void)rbuffer_write(input_buffer, ptr, len);
- rbuffer_consumed(read_buffer, len);
+ rbuffer_consumed(buf, len);
}
}
@@ -362,7 +370,7 @@ static bool input_ready(void)
{
return typebuf_was_filled || // API call filled typeahead
rbuffer_size(input_buffer) || // Input buffer filled
- event_has_deferred(); // Events must be processed
+ pending_events(); // Events must be processed
}
// Exit because of an input read error.
@@ -373,3 +381,8 @@ static void read_error_exit(void)
STRCPY(IObuff, _("Vim: Error reading input, exiting...\n"));
preserve_exit();
}
+
+static bool pending_events(void)
+{
+ return events_enabled && !queue_empty(loop.events);
+}
diff --git a/src/nvim/os/job.c b/src/nvim/os/job.c
deleted file mode 100644
index 4769ee4d2f..0000000000
--- a/src/nvim/os/job.c
+++ /dev/null
@@ -1,472 +0,0 @@
-#include <stdint.h>
-#include <stdbool.h>
-
-#include <uv.h>
-
-#include "nvim/os/uv_helpers.h"
-#include "nvim/os/job.h"
-#include "nvim/os/job_defs.h"
-#include "nvim/os/job_private.h"
-#include "nvim/os/pty_process.h"
-#include "nvim/os/rstream.h"
-#include "nvim/os/rstream_defs.h"
-#include "nvim/os/wstream.h"
-#include "nvim/os/wstream_defs.h"
-#include "nvim/os/event.h"
-#include "nvim/os/event_defs.h"
-#include "nvim/os/time.h"
-#include "nvim/vim.h"
-#include "nvim/memory.h"
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-// {SIGNAL}_TIMEOUT is the time (in nanoseconds) that a job has to cleanly exit
-// before we send SIGNAL to it
-#define TERM_TIMEOUT 1000000000
-#define KILL_TIMEOUT (TERM_TIMEOUT * 2)
-#define JOB_BUFFER_SIZE 0xFFFF
-
-#define close_job_stream(job, stream, type) \
- do { \
- if (job->stream) { \
- type##stream_free(job->stream); \
- job->stream = NULL; \
- if (!uv_is_closing((uv_handle_t *)job->proc_std##stream)) { \
- uv_close((uv_handle_t *)job->proc_std##stream, close_cb); \
- } \
- } \
- } while (0)
-
-#define close_job_in(job) close_job_stream(job, in, w)
-#define close_job_out(job) close_job_stream(job, out, r)
-#define close_job_err(job) close_job_stream(job, err, r)
-
-Job *table[MAX_RUNNING_JOBS] = {NULL};
-size_t stop_requests = 0;
-uv_timer_t job_stop_timer;
-uv_signal_t schld;
-
-// Some helpers shared in this module
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/job.c.generated.h"
-#endif
-// Callbacks for libuv
-
-/// Initializes job control resources
-void job_init(void)
-{
- uv_disable_stdio_inheritance();
- uv_timer_init(uv_default_loop(), &job_stop_timer);
- uv_signal_init(uv_default_loop(), &schld);
- uv_signal_start(&schld, chld_handler, SIGCHLD);
-}
-
-/// Releases job control resources and terminates running jobs
-void job_teardown(void)
-{
- // Stop all jobs
- for (int i = 0; i < MAX_RUNNING_JOBS; i++) {
- Job *job;
- if ((job = table[i]) != NULL) {
- uv_kill(job->pid, SIGTERM);
- job->term_sent = true;
- job_stop(job);
- }
- }
-
- // Wait until all jobs are closed
- event_poll_until(-1, !stop_requests);
- uv_signal_stop(&schld);
- uv_close((uv_handle_t *)&schld, NULL);
- // Close the timer
- uv_close((uv_handle_t *)&job_stop_timer, NULL);
-}
-
-/// Tries to start a new job.
-///
-/// @param[out] status The job id if the job started successfully, 0 if the job
-/// table is full, -1 if the program could not be executed.
-/// @return The job pointer if the job started successfully, NULL otherwise
-Job *job_start(JobOptions opts, int *status)
-{
- int i;
- Job *job;
-
- // Search for a free slot in the table
- for (i = 0; i < MAX_RUNNING_JOBS; i++) {
- if (table[i] == NULL) {
- break;
- }
- }
-
- if (i == MAX_RUNNING_JOBS) {
- // No free slots
- shell_free_argv(opts.argv);
- *status = 0;
- return NULL;
- }
-
- job = xmalloc(sizeof(Job));
- // Initialize
- job->id = i + 1;
- *status = job->id;
- job->status = -1;
- job->refcount = 1;
- job->stopped_time = 0;
- job->term_sent = false;
- job->in = NULL;
- job->out = NULL;
- job->err = NULL;
- job->opts = opts;
- job->closed = false;
-
- process_init(job);
-
- if (opts.writable) {
- handle_set_job((uv_handle_t *)job->proc_stdin, job);
- job->refcount++;
- }
-
- if (opts.stdout_cb) {
- handle_set_job((uv_handle_t *)job->proc_stdout, job);
- job->refcount++;
- }
-
- if (opts.stderr_cb) {
- handle_set_job((uv_handle_t *)job->proc_stderr, job);
- job->refcount++;
- }
-
- // Spawn the job
- if (!process_spawn(job)) {
- if (opts.writable) {
- uv_close((uv_handle_t *)job->proc_stdin, close_cb);
- }
- if (opts.stdout_cb) {
- uv_close((uv_handle_t *)job->proc_stdout, close_cb);
- }
- if (opts.stderr_cb) {
- uv_close((uv_handle_t *)job->proc_stderr, close_cb);
- }
- process_close(job);
- event_poll(0);
- // Manually invoke the close_cb to free the job resources
- *status = -1;
- return NULL;
- }
-
- if (opts.writable) {
- job->in = wstream_new(opts.maxmem);
- wstream_set_stream(job->in, job->proc_stdin);
- }
-
- // Start the readable streams
- if (opts.stdout_cb) {
- job->out = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job);
- rstream_set_stream(job->out, job->proc_stdout);
- rstream_start(job->out);
- }
-
- if (opts.stderr_cb) {
- job->err = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job);
- rstream_set_stream(job->err, job->proc_stderr);
- rstream_start(job->err);
- }
- // Save the job to the table
- table[i] = job;
-
- return job;
-}
-
-/// Finds a job instance by id
-///
-/// @param id The job id
-/// @return the Job instance
-Job *job_find(int id)
-{
- Job *job;
-
- if (id <= 0 || id > MAX_RUNNING_JOBS || !(job = table[id - 1])
- || job->stopped_time) {
- return NULL;
- }
-
- return job;
-}
-
-/// Terminates a job. This is a non-blocking operation, but if the job exists
-/// it's guaranteed to succeed(SIGKILL will eventually be sent)
-///
-/// @param job The Job instance
-void job_stop(Job *job)
-{
- if (job->stopped_time) {
- return;
- }
-
- job->stopped_time = os_hrtime();
- if (job->opts.pty) {
- // close all streams for pty jobs to send SIGHUP to the process
- job_close_streams(job);
- pty_process_close_master(job);
- } else {
- // Close the job's stdin. If the job doesn't close its own stdout/stderr,
- // they will be closed when the job exits(possibly due to being terminated
- // after a timeout)
- close_job_in(job);
- }
-
- if (!stop_requests++) {
- // When there's at least one stop request pending, start a timer that
- // will periodically check if a signal should be send to a to the job
- DLOG("Starting job kill timer");
- uv_timer_start(&job_stop_timer, job_stop_timer_cb, 100, 100);
- }
-}
-
-/// job_wait - synchronously wait for a job to finish
-///
-/// @param job The job instance
-/// @param ms Number of milliseconds to wait, 0 for not waiting, -1 for
-/// waiting until the job quits.
-/// @return returns the status code of the exited job. -1 if the job is
-/// still running and the `timeout` has expired. Note that this is
-/// indistinguishable from the process returning -1 by itself. Which
-/// is possible on some OS. Returns -2 if the job was interrupted.
-int job_wait(Job *job, int ms) FUNC_ATTR_NONNULL_ALL
-{
- // The default status is -1, which represents a timeout
- int status = -1;
- bool interrupted = false;
-
- // Increase refcount to stop the job from being freed before we have a
- // chance to get the status.
- job->refcount++;
- event_poll_until(ms,
- // Until...
- got_int || // interrupted by the user
- job->refcount == 1); // job exited
-
- // we'll assume that a user frantically hitting interrupt doesn't like
- // the current job. Signal that it has to be killed.
- if (got_int) {
- interrupted = true;
- got_int = false;
- job_stop(job);
- if (ms == -1) {
- // We can only return, if all streams/handles are closed and the job
- // exited.
- event_poll_until(-1, job->refcount == 1);
- } else {
- event_poll(0);
- }
- }
-
- if (job->refcount == 1) {
- // Job exited, collect status and manually invoke close_cb to free the job
- // resources
- status = interrupted ? -2 : job->status;
- job_close_streams(job);
- job_decref(job);
- } else {
- job->refcount--;
- }
-
- return status;
-}
-
-/// Close the pipe used to write to the job.
-///
-/// This can be used for example to indicate to the job process that no more
-/// input is coming, and that it should shut down cleanly.
-///
-/// It has no effect when the input pipe doesn't exist or was already
-/// closed.
-///
-/// @param job The job instance
-void job_close_in(Job *job) FUNC_ATTR_NONNULL_ALL
-{
- close_job_in(job);
-}
-
-// Close the job stdout stream.
-void job_close_out(Job *job) FUNC_ATTR_NONNULL_ALL
-{
- close_job_out(job);
-}
-
-// Close the job stderr stream.
-void job_close_err(Job *job) FUNC_ATTR_NONNULL_ALL
-{
- close_job_out(job);
-}
-
-/// All writes that complete after calling this function will be reported
-/// to `cb`.
-///
-/// Use this function to be notified about the status of an in-flight write.
-///
-/// @see {wstream_set_write_cb}
-///
-/// @param job The job instance
-/// @param cb The function that will be called on write completion or
-/// failure. It will be called with the job as the `data` argument.
-void job_write_cb(Job *job, wstream_cb cb) FUNC_ATTR_NONNULL_ALL
-{
- wstream_set_write_cb(job->in, cb, job);
-}
-
-/// Writes data to the job's stdin. This is a non-blocking operation, it
-/// returns when the write request was sent.
-///
-/// @param job The Job instance
-/// @param buffer The buffer which contains the data to be written
-/// @return true if the write request was successfully sent, false if writing
-/// to the job stream failed (possibly because the OS buffer is full)
-bool job_write(Job *job, WBuffer *buffer)
-{
- return wstream_write(job->in, buffer);
-}
-
-/// Get the job id
-///
-/// @param job A pointer to the job
-/// @return The job id
-int job_id(Job *job)
-{
- return job->id;
-}
-
-// Get the job pid
-int job_pid(Job *job)
-{
- return job->pid;
-}
-
-/// Get data associated with a job
-///
-/// @param job A pointer to the job
-/// @return The job data
-void *job_data(Job *job)
-{
- return job->opts.data;
-}
-
-/// Resize the window for a pty job
-bool job_resize(Job *job, uint16_t width, uint16_t height)
-{
- if (!job->opts.pty) {
- return false;
- }
- pty_process_resize(job, width, height);
- return true;
-}
-
-void job_close_streams(Job *job)
-{
- close_job_in(job);
- close_job_out(job);
- close_job_err(job);
-}
-
-JobOptions *job_opts(Job *job)
-{
- return &job->opts;
-}
-
-/// Iterates the table, sending SIGTERM to stopped jobs and SIGKILL to those
-/// that didn't die from SIGTERM after a while(exit_timeout is 0).
-static void job_stop_timer_cb(uv_timer_t *handle)
-{
- Job *job;
- uint64_t now = os_hrtime();
-
- for (size_t i = 0; i < MAX_RUNNING_JOBS; i++) {
- if ((job = table[i]) == NULL || !job->stopped_time) {
- continue;
- }
-
- uint64_t elapsed = now - job->stopped_time;
-
- if (!job->term_sent && elapsed >= TERM_TIMEOUT) {
- ILOG("Sending SIGTERM to job(id: %d)", job->id);
- uv_kill(job->pid, SIGTERM);
- job->term_sent = true;
- } else if (elapsed >= KILL_TIMEOUT) {
- ILOG("Sending SIGKILL to job(id: %d)", job->id);
- uv_kill(job->pid, SIGKILL);
- process_close(job);
- }
- }
-}
-
-// Wraps the call to std{out,err}_cb and emits a JobExit event if necessary.
-static void read_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
-{
- Job *job = data;
-
- if (rstream == job->out) {
- job->opts.stdout_cb(rstream, buf, data, eof);
- if (eof) {
- close_job_out(job);
- }
- } else {
- job->opts.stderr_cb(rstream, buf, data, eof);
- if (eof) {
- close_job_err(job);
- }
- }
-}
-
-static void close_cb(uv_handle_t *handle)
-{
- job_decref(handle_get_job(handle));
-}
-
-static void job_exited(Event event)
-{
- Job *job = event.data;
- process_close(job);
-}
-
-static void chld_handler(uv_signal_t *handle, int signum)
-{
- int stat = 0;
- int pid;
-
- do {
- pid = waitpid(-1, &stat, WNOHANG);
- } while (pid < 0 && errno == EINTR);
-
- if (pid <= 0) {
- return;
- }
-
- if (WIFSTOPPED(stat) || WIFCONTINUED(stat)) {
- // Only care for processes that exited
- return;
- }
-
- Job *job = NULL;
- // find the job corresponding to the exited pid
- for (int i = 0; i < MAX_RUNNING_JOBS; i++) {
- if ((job = table[i]) != NULL && job->pid == pid) {
- if (WIFEXITED(stat)) {
- job->status = WEXITSTATUS(stat);
- } else if (WIFSIGNALED(stat)) {
- job->status = WTERMSIG(stat);
- }
- if (exiting) {
- // don't enqueue more events when exiting
- process_close(job);
- } else {
- event_push((Event) {.handler = job_exited, .data = job}, false);
- }
- break;
- }
- }
-}
-
diff --git a/src/nvim/os/job.h b/src/nvim/os/job.h
deleted file mode 100644
index e0ca615626..0000000000
--- a/src/nvim/os/job.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Job is a short name we use to refer to child processes that run in parallel
-// with the editor, probably executing long-running tasks and sending updates
-// asynchronously. Communication happens through anonymous pipes connected to
-// the job's std{in,out,err}. They are more like bash/zsh co-processes than the
-// usual shell background job. The name 'Job' was chosen because it applies to
-// the concept while being significantly shorter.
-#ifndef NVIM_OS_JOB_H
-#define NVIM_OS_JOB_H
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#include "nvim/os/rstream_defs.h"
-#include "nvim/os/event_defs.h"
-#include "nvim/os/wstream.h"
-#include "nvim/os/wstream_defs.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/job.h.generated.h"
-#endif
-#endif // NVIM_OS_JOB_H
diff --git a/src/nvim/os/job_defs.h b/src/nvim/os/job_defs.h
deleted file mode 100644
index 7fee900ac0..0000000000
--- a/src/nvim/os/job_defs.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef NVIM_OS_JOB_DEFS_H
-#define NVIM_OS_JOB_DEFS_H
-
-#include <uv.h>
-#include "nvim/os/rstream_defs.h"
-#include "nvim/os/wstream_defs.h"
-
-#define MAX_RUNNING_JOBS 100
-typedef struct job Job;
-
-/// Function called when the job reads data
-///
-/// @param id The job id
-/// @param data Some data associated with the job by the caller
-typedef void (*job_exit_cb)(Job *job, int status, void *data);
-
-// Job startup options
-// job_exit_cb Callback that will be invoked when the job exits
-// maxmem Maximum amount of memory used by the job WStream
-typedef struct {
- // Argument vector for the process. The first item is the
- // executable to run.
- // [consumed]
- char **argv;
- // Caller data that will be associated with the job
- void *data;
- // If true the job stdin will be available for writing with job_write,
- // otherwise it will be redirected to /dev/null
- bool writable;
- // Callback that will be invoked when data is available on stdout. If NULL
- // stdout will be redirected to /dev/null.
- rstream_cb stdout_cb;
- // Callback that will be invoked when data is available on stderr. If NULL
- // stderr will be redirected to /dev/null.
- rstream_cb stderr_cb;
- // Callback that will be invoked when the job has exited and will not send
- // data
- job_exit_cb exit_cb;
- // Maximum memory used by the job's WStream
- size_t maxmem;
- // Connect the job to a pseudo terminal
- bool pty;
- // Initial window dimensions if the job is connected to a pseudo terminal
- uint16_t width, height;
- // Value for the $TERM environment variable. A default value of "ansi" is
- // assumed if NULL
- char *term_name;
-} JobOptions;
-
-#define JOB_OPTIONS_INIT ((JobOptions) { \
- .argv = NULL, \
- .data = NULL, \
- .writable = true, \
- .stdout_cb = NULL, \
- .stderr_cb = NULL, \
- .exit_cb = NULL, \
- .maxmem = 0, \
- .pty = false, \
- .width = 80, \
- .height = 24, \
- .term_name = NULL \
- })
-#endif // NVIM_OS_JOB_DEFS_H
diff --git a/src/nvim/os/job_private.h b/src/nvim/os/job_private.h
deleted file mode 100644
index 983106d918..0000000000
--- a/src/nvim/os/job_private.h
+++ /dev/null
@@ -1,118 +0,0 @@
-#ifndef NVIM_OS_JOB_PRIVATE_H
-#define NVIM_OS_JOB_PRIVATE_H
-
-#include <stdlib.h>
-
-#include <uv.h>
-
-#include "nvim/os/rstream_defs.h"
-#include "nvim/os/wstream_defs.h"
-#include "nvim/os/pipe_process.h"
-#include "nvim/os/pty_process.h"
-#include "nvim/os/shell.h"
-#include "nvim/log.h"
-#include "nvim/memory.h"
-
-struct job {
- // Job id the index in the job table plus one.
- int id;
- // Process id
- int pid;
- // Exit status code of the job process
- int status;
- // Number of references to the job. The job resources will only be freed by
- // close_cb when this is 0
- int refcount;
- // Time when job_stop was called for the job.
- uint64_t stopped_time;
- // If SIGTERM was already sent to the job(only send one before SIGKILL)
- bool term_sent;
- // Readable streams(std{out,err})
- RStream *out, *err;
- // Writable stream(stdin)
- WStream *in;
- // Libuv streams representing stdin/stdout/stderr
- uv_stream_t *proc_stdin, *proc_stdout, *proc_stderr;
- // Extra data set by the process spawner
- void *process;
- // If process_close has been called on this job
- bool closed;
- // Startup options
- JobOptions opts;
-};
-
-extern Job *table[];
-extern size_t stop_requests;
-extern uv_timer_t job_stop_timer;
-
-static inline bool process_spawn(Job *job)
-{
- return job->opts.pty ? pty_process_spawn(job) : pipe_process_spawn(job);
-}
-
-static inline void process_init(Job *job)
-{
- if (job->opts.pty) {
- pty_process_init(job);
- } else {
- pipe_process_init(job);
- }
-}
-
-static inline void process_close(Job *job)
-{
- if (job->closed) {
- return;
- }
- job->closed = true;
- if (job->opts.pty) {
- pty_process_close(job);
- } else {
- pipe_process_close(job);
- }
-}
-
-static inline void process_destroy(Job *job)
-{
- if (job->opts.pty) {
- pty_process_destroy(job);
- } else {
- pipe_process_destroy(job);
- }
-}
-
-static inline void job_exit_callback(Job *job)
-{
- // Free the slot now, 'exit_cb' may want to start another job to replace
- // this one
- table[job->id - 1] = NULL;
-
- if (job->opts.exit_cb) {
- // Invoke the exit callback
- job->opts.exit_cb(job, job->status, job->opts.data);
- }
-
- if (stop_requests && !--stop_requests) {
- // Stop the timer if no more stop requests are pending
- DLOG("Stopping job kill timer");
- uv_timer_stop(&job_stop_timer);
- }
-}
-
-static inline void job_decref(Job *job)
-{
- if (--job->refcount == 0) {
- // Invoke the exit_cb
- job_exit_callback(job);
- // Free all memory allocated for the job
- xfree(job->proc_stdin->data);
- xfree(job->proc_stdout->data);
- xfree(job->proc_stderr->data);
- shell_free_argv(job->opts.argv);
- process_destroy(job);
- xfree(job);
- }
-}
-
-
-#endif // NVIM_OS_JOB_PRIVATE_H
diff --git a/src/nvim/os/os.h b/src/nvim/os/os.h
index 3dd099890c..69bd1ff4fd 100644
--- a/src/nvim/os/os.h
+++ b/src/nvim/os/os.h
@@ -12,7 +12,6 @@
# include "os/mem.h.generated.h"
# include "os/env.h.generated.h"
# include "os/users.h.generated.h"
-# include "os/stream.h.generated.h"
#endif
#endif // NVIM_OS_OS_H
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index 0e7632a79d..1d16111066 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -135,4 +135,9 @@
// For dup(3).
#define HAVE_DUP
+/// Function to convert -errno error to char * error description
+///
+/// -errno errors are returned by a number of os functions.
+#define os_strerror uv_strerror
+
#endif // NVIM_OS_OS_DEFS_H
diff --git a/src/nvim/os/pipe_process.c b/src/nvim/os/pipe_process.c
deleted file mode 100644
index 2ac305e967..0000000000
--- a/src/nvim/os/pipe_process.c
+++ /dev/null
@@ -1,110 +0,0 @@
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include <uv.h>
-
-#include "nvim/os/uv_helpers.h"
-#include "nvim/os/job.h"
-#include "nvim/os/job_defs.h"
-#include "nvim/os/job_private.h"
-#include "nvim/os/pipe_process.h"
-#include "nvim/memory.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/pipe_process.c.generated.h"
-#endif
-
-typedef struct {
- // Structures for process spawning/management used by libuv
- uv_process_t proc;
- uv_process_options_t proc_opts;
- uv_stdio_container_t stdio[3];
- uv_pipe_t proc_stdin, proc_stdout, proc_stderr;
-} UvProcess;
-
-void pipe_process_init(Job *job)
-{
- UvProcess *pipeproc = xmalloc(sizeof(UvProcess));
- pipeproc->proc_opts.file = job->opts.argv[0];
- pipeproc->proc_opts.args = job->opts.argv;
- pipeproc->proc_opts.stdio = pipeproc->stdio;
- pipeproc->proc_opts.stdio_count = 3;
- pipeproc->proc_opts.flags = UV_PROCESS_WINDOWS_HIDE;
- pipeproc->proc_opts.exit_cb = exit_cb;
- pipeproc->proc_opts.cwd = NULL;
- pipeproc->proc_opts.env = NULL;
- pipeproc->proc.data = NULL;
- pipeproc->proc_stdin.data = NULL;
- pipeproc->proc_stdout.data = NULL;
- pipeproc->proc_stderr.data = NULL;
-
- // Initialize the job std{in,out,err}
- pipeproc->stdio[0].flags = UV_IGNORE;
- pipeproc->stdio[1].flags = UV_IGNORE;
- pipeproc->stdio[2].flags = UV_IGNORE;
-
- handle_set_job((uv_handle_t *)&pipeproc->proc, job);
-
- if (job->opts.writable) {
- uv_pipe_init(uv_default_loop(), &pipeproc->proc_stdin, 0);
- pipeproc->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
- pipeproc->stdio[0].data.stream = (uv_stream_t *)&pipeproc->proc_stdin;
- }
-
- if (job->opts.stdout_cb) {
- uv_pipe_init(uv_default_loop(), &pipeproc->proc_stdout, 0);
- pipeproc->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
- pipeproc->stdio[1].data.stream = (uv_stream_t *)&pipeproc->proc_stdout;
- }
-
- if (job->opts.stderr_cb) {
- uv_pipe_init(uv_default_loop(), &pipeproc->proc_stderr, 0);
- pipeproc->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
- pipeproc->stdio[2].data.stream = (uv_stream_t *)&pipeproc->proc_stderr;
- }
-
- job->proc_stdin = (uv_stream_t *)&pipeproc->proc_stdin;
- job->proc_stdout = (uv_stream_t *)&pipeproc->proc_stdout;
- job->proc_stderr = (uv_stream_t *)&pipeproc->proc_stderr;
- job->process = pipeproc;
-}
-
-void pipe_process_destroy(Job *job)
-{
- UvProcess *pipeproc = job->process;
- xfree(pipeproc->proc.data);
- xfree(pipeproc);
- job->process = NULL;
-}
-
-bool pipe_process_spawn(Job *job)
-{
- UvProcess *pipeproc = job->process;
-
- if (uv_spawn(uv_default_loop(), &pipeproc->proc, &pipeproc->proc_opts) != 0) {
- return false;
- }
-
- job->pid = pipeproc->proc.pid;
- return true;
-}
-
-void pipe_process_close(Job *job)
-{
- UvProcess *pipeproc = job->process;
- uv_close((uv_handle_t *)&pipeproc->proc, close_cb);
-}
-
-static void exit_cb(uv_process_t *proc, int64_t status, int term_signal)
-{
- Job *job = handle_get_job((uv_handle_t *)proc);
- job->status = (int)status;
- pipe_process_close(job);
-}
-
-static void close_cb(uv_handle_t *handle)
-{
- Job *job = handle_get_job(handle);
- job_close_streams(job);
- job_decref(job);
-}
diff --git a/src/nvim/os/pipe_process.h b/src/nvim/os/pipe_process.h
deleted file mode 100644
index 17a4255ddc..0000000000
--- a/src/nvim/os/pipe_process.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef NVIM_OS_PIPE_PROCESS_H
-#define NVIM_OS_PIPE_PROCESS_H
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/pipe_process.h.generated.h"
-#endif
-#endif // NVIM_OS_PIPE_PROCESS_H
diff --git a/src/nvim/os/pty_process.h b/src/nvim/os/pty_process.h
deleted file mode 100644
index 62fcd1671f..0000000000
--- a/src/nvim/os/pty_process.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef NVIM_OS_PTY_PROCESS_H
-#define NVIM_OS_PTY_PROCESS_H
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/pty_process.h.generated.h"
-#endif
-#endif // NVIM_OS_PTY_PROCESS_H
diff --git a/src/nvim/os/rstream.c b/src/nvim/os/rstream.c
deleted file mode 100644
index af84288f0f..0000000000
--- a/src/nvim/os/rstream.c
+++ /dev/null
@@ -1,253 +0,0 @@
-#include <assert.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include <uv.h>
-
-#include "nvim/os/uv_helpers.h"
-#include "nvim/os/rstream_defs.h"
-#include "nvim/os/rstream.h"
-#include "nvim/ascii.h"
-#include "nvim/vim.h"
-#include "nvim/memory.h"
-#include "nvim/log.h"
-#include "nvim/misc1.h"
-
-struct rstream {
- void *data;
- uv_buf_t uvbuf;
- size_t fpos;
- RBuffer *buffer;
- uv_stream_t *stream;
- uv_idle_t *fread_idle;
- uv_handle_type file_type;
- uv_file fd;
- rstream_cb cb;
- bool free_handle;
-};
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/rstream.c.generated.h"
-#endif
-
-/// Creates a new RStream instance. A RStream encapsulates all the boilerplate
-/// necessary for reading from a libuv stream.
-///
-/// @param cb A function that will be called whenever some data is available
-/// for reading with `rstream_read`
-/// @param buffer RBuffer instance to associate with the RStream
-/// @param data Some state to associate with the `RStream` instance
-/// @return The newly-allocated `RStream` instance
-RStream * rstream_new(rstream_cb cb, RBuffer *buffer, void *data)
-{
- RStream *rv = xmalloc(sizeof(RStream));
- buffer->data = rv;
- buffer->full_cb = on_rbuffer_full;
- buffer->nonfull_cb = on_rbuffer_nonfull;
- rv->buffer = buffer;
- rv->fpos = 0;
- rv->data = data;
- rv->cb = cb;
- rv->stream = NULL;
- rv->fread_idle = NULL;
- rv->free_handle = false;
- rv->file_type = UV_UNKNOWN_HANDLE;
-
- return rv;
-}
-
-static void on_rbuffer_full(RBuffer *buf, void *data)
-{
- rstream_stop(data);
-}
-
-static void on_rbuffer_nonfull(RBuffer *buf, void *data)
-{
- rstream_start(data);
-}
-
-/// Frees all memory allocated for a RStream instance
-///
-/// @param rstream The `RStream` instance
-void rstream_free(RStream *rstream)
-{
- if (rstream->free_handle) {
- if (rstream->fread_idle != NULL) {
- uv_close((uv_handle_t *)rstream->fread_idle, close_cb);
- } else {
- uv_close((uv_handle_t *)rstream->stream, close_cb);
- }
- }
-
- rbuffer_free(rstream->buffer);
- xfree(rstream);
-}
-
-/// Sets the underlying `uv_stream_t` instance
-///
-/// @param rstream The `RStream` instance
-/// @param stream The new `uv_stream_t` instance
-void rstream_set_stream(RStream *rstream, uv_stream_t *stream)
-{
- handle_set_rstream((uv_handle_t *)stream, rstream);
- rstream->stream = stream;
-}
-
-/// Sets the underlying file descriptor that will be read from. Only pipes
-/// and regular files are supported for now.
-///
-/// @param rstream The `RStream` instance
-/// @param file The file descriptor
-void rstream_set_file(RStream *rstream, uv_file file)
-{
- rstream->file_type = uv_guess_handle(file);
-
- if (rstream->free_handle) {
- // If this is the second time we're calling this function, free the
- // previously allocated memory
- if (rstream->fread_idle != NULL) {
- uv_close((uv_handle_t *)rstream->fread_idle, close_cb);
- rstream->fread_idle = NULL;
- } else {
- uv_close((uv_handle_t *)rstream->stream, close_cb);
- rstream->stream = NULL;
- }
- }
-
- if (rstream->file_type == UV_FILE) {
- // Non-blocking file reads are simulated with an idle handle that reads
- // in chunks of rstream->buffer_size, giving time for other events to
- // be processed between reads.
- rstream->fread_idle = xmalloc(sizeof(uv_idle_t));
- uv_idle_init(uv_default_loop(), rstream->fread_idle);
- rstream->fread_idle->data = NULL;
- handle_set_rstream((uv_handle_t *)rstream->fread_idle, rstream);
- } else {
- // Only pipes are supported for now
- assert(rstream->file_type == UV_NAMED_PIPE
- || rstream->file_type == UV_TTY);
- rstream->stream = xmalloc(sizeof(uv_pipe_t));
- uv_pipe_init(uv_default_loop(), (uv_pipe_t *)rstream->stream, 0);
- uv_pipe_open((uv_pipe_t *)rstream->stream, file);
- rstream->stream->data = NULL;
- handle_set_rstream((uv_handle_t *)rstream->stream, rstream);
- }
-
- rstream->fd = file;
- rstream->free_handle = true;
-}
-
-/// Starts watching for events from a `RStream` instance.
-///
-/// @param rstream The `RStream` instance
-void rstream_start(RStream *rstream)
-{
- if (rstream->file_type == UV_FILE) {
- uv_idle_start(rstream->fread_idle, fread_idle_cb);
- } else {
- uv_read_start(rstream->stream, alloc_cb, read_cb);
- }
-}
-
-/// Stops watching for events from a `RStream` instance.
-///
-/// @param rstream The `RStream` instance
-void rstream_stop(RStream *rstream)
-{
- if (rstream->file_type == UV_FILE) {
- uv_idle_stop(rstream->fread_idle);
- } else {
- uv_read_stop(rstream->stream);
- }
-}
-
-// Callbacks used by libuv
-
-// Called by libuv to allocate memory for reading.
-static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
-{
- RStream *rstream = handle_get_rstream(handle);
- buf->base = rbuffer_write_ptr(rstream->buffer, &buf->len);
-}
-
-// Callback invoked by libuv after it copies the data into the buffer provided
-// by `alloc_cb`. This is also called on EOF or when `alloc_cb` returns a
-// 0-length buffer.
-static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf)
-{
- RStream *rstream = handle_get_rstream((uv_handle_t *)stream);
-
- if (cnt <= 0) {
- if (cnt != UV_ENOBUFS
- // cnt == 0 means libuv asked for a buffer and decided it wasn't needed:
- // http://docs.libuv.org/en/latest/stream.html#c.uv_read_start.
- //
- // We don't need to do anything with the RBuffer because the next call
- // to `alloc_cb` will return the same unused pointer(`rbuffer_produced`
- // won't be called)
- && cnt != 0) {
- DLOG("Closing RStream(%p) because of %s(%zd)", rstream,
- uv_strerror((int)cnt), cnt);
- // Read error or EOF, either way stop the stream and invoke the callback
- // with eof == true
- uv_read_stop(stream);
- rstream->cb(rstream, rstream->buffer, rstream->data, true);
- }
- return;
- }
-
- // at this point we're sure that cnt is positive, no error occurred
- size_t nread = (size_t)cnt;
- // Data was already written, so all we need is to update 'wpos' to reflect
- // the space actually used in the buffer.
- rbuffer_produced(rstream->buffer, nread);
- rstream->cb(rstream, rstream->buffer, rstream->data, false);
-}
-
-// Called by the by the 'idle' handle to emulate a reading event
-static void fread_idle_cb(uv_idle_t *handle)
-{
- uv_fs_t req;
- RStream *rstream = handle_get_rstream((uv_handle_t *)handle);
-
- rstream->uvbuf.base = rbuffer_write_ptr(rstream->buffer, &rstream->uvbuf.len);
-
- // the offset argument to uv_fs_read is int64_t, could someone really try
- // to read more than 9 quintillion (9e18) bytes?
- // upcast is meant to avoid tautological condition warning on 32 bits
- uintmax_t fpos_intmax = rstream->fpos;
- if (fpos_intmax > INT64_MAX) {
- ELOG("stream offset overflow");
- preserve_exit();
- }
-
- // Synchronous read
- uv_fs_read(
- uv_default_loop(),
- &req,
- rstream->fd,
- &rstream->uvbuf,
- 1,
- (int64_t) rstream->fpos,
- NULL);
-
- uv_fs_req_cleanup(&req);
-
- if (req.result <= 0) {
- uv_idle_stop(rstream->fread_idle);
- rstream->cb(rstream, rstream->buffer, rstream->data, true);
- return;
- }
-
- // no errors (req.result (ssize_t) is positive), it's safe to cast.
- size_t nread = (size_t) req.result;
- rbuffer_produced(rstream->buffer, nread);
- rstream->fpos += nread;
-}
-
-static void close_cb(uv_handle_t *handle)
-{
- xfree(handle->data);
- xfree(handle);
-}
diff --git a/src/nvim/os/rstream.h b/src/nvim/os/rstream.h
deleted file mode 100644
index 3e24724573..0000000000
--- a/src/nvim/os/rstream.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef NVIM_OS_RSTREAM_H
-#define NVIM_OS_RSTREAM_H
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <uv.h>
-#include "nvim/os/event_defs.h"
-#include "nvim/os/rstream_defs.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/rstream.h.generated.h"
-#endif
-#endif // NVIM_OS_RSTREAM_H
diff --git a/src/nvim/os/rstream_defs.h b/src/nvim/os/rstream_defs.h
deleted file mode 100644
index 45dced0b62..0000000000
--- a/src/nvim/os/rstream_defs.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef NVIM_OS_RSTREAM_DEFS_H
-#define NVIM_OS_RSTREAM_DEFS_H
-
-#include <stdbool.h>
-
-#include "nvim/rbuffer.h"
-
-typedef struct rstream RStream;
-
-/// Type of function called when the RStream receives data
-///
-/// @param rstream The RStream instance
-/// @param rbuffer The associated RBuffer instance
-/// @param data State associated with the RStream instance
-/// @param eof If the stream reached EOF.
-typedef void (*rstream_cb)(RStream *rstream, RBuffer *buf, void *data,
- bool eof);
-
-#endif // NVIM_OS_RSTREAM_DEFS_H
-
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 48174533a6..2d97c4bf4f 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -8,9 +8,9 @@
#include "nvim/ascii.h"
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
-#include "nvim/os/event.h"
-#include "nvim/os/job.h"
-#include "nvim/os/rstream.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/uv_process.h"
+#include "nvim/event/rstream.h"
#include "nvim/os/shell.h"
#include "nvim/os/signal.h"
#include "nvim/types.h"
@@ -189,7 +189,7 @@ static int do_os_system(char **argv,
{
// the output buffer
DynamicBuffer buf = DYNAMIC_BUFFER_INIT;
- rstream_cb data_cb = system_data_cb;
+ stream_read_cb data_cb = system_data_cb;
if (nread) {
*nread = 0;
}
@@ -204,48 +204,60 @@ static int do_os_system(char **argv,
char prog[MAXPATHL];
xstrlcpy(prog, argv[0], MAXPATHL);
- int status;
- JobOptions opts = JOB_OPTIONS_INIT;
- opts.argv = argv;
- opts.data = &buf;
- opts.writable = input != NULL;
- opts.stdout_cb = data_cb;
- opts.stderr_cb = data_cb;
- opts.exit_cb = NULL;
- Job *job = job_start(opts, &status);
-
- if (status <= 0) {
+ Stream in, out, err;
+ UvProcess uvproc = uv_process_init(&loop, &buf);
+ Process *proc = &uvproc.process;
+ Queue *events = queue_new_child(loop.events);
+ proc->events = events;
+ proc->argv = argv;
+ proc->in = input != NULL ? &in : NULL;
+ proc->out = &out;
+ proc->err = &err;
+ if (!process_spawn(proc)) {
+ loop_poll_events(&loop, 0);
// Failed, probably due to `sh` not being executable
if (!silent) {
MSG_PUTS(_("\nCannot execute "));
msg_outtrans((char_u *)prog);
msg_putchar('\n');
}
+ queue_free(events);
return -1;
}
+ // We want to deal with stream events as fast a possible while queueing
+ // process events, so reset everything to NULL. It prevents closing the
+ // streams while there's still data in the OS buffer(due to the process
+ // exiting before all data is read).
+ if (input != NULL) {
+ proc->in->events = NULL;
+ wstream_init(proc->in, 0);
+ }
+ proc->out->events = NULL;
+ rstream_init(proc->out, 0);
+ rstream_start(proc->out, data_cb);
+ proc->err->events = NULL;
+ rstream_init(proc->err, 0);
+ rstream_start(proc->err, data_cb);
+
// write the input, if any
if (input) {
WBuffer *input_buffer = wstream_new_buffer((char *) input, len, 1, NULL);
- if (!job_write(job, input_buffer)) {
- // couldn't write, stop the job and tell the user about it
- job_stop(job);
+ if (!wstream_write(&in, input_buffer)) {
+ // couldn't write, stop the process and tell the user about it
+ process_stop(proc);
return -1;
}
// close the input stream after everything is written
- job_write_cb(job, shell_write_cb);
- } else {
- // close the input stream, let the process know that no more input is
- // coming
- job_close_in(job);
+ wstream_set_write_cb(&in, shell_write_cb);
}
// invoke busy_start here so event_poll_until wont change the busy state for
// the UI
ui_busy_start();
ui_flush();
- status = job_wait(job, -1);
+ int status = process_wait(proc, -1, NULL);
ui_busy_stop();
// prepare the out parameters if requested
@@ -265,6 +277,9 @@ static int do_os_system(char **argv,
}
}
+ assert(queue_empty(events));
+ queue_free(events);
+
return status;
}
@@ -283,10 +298,10 @@ static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired)
buf->data = xrealloc(buf->data, buf->cap);
}
-static void system_data_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
+static void system_data_cb(Stream *stream, RBuffer *buf, size_t count,
+ void *data, bool eof)
{
- Job *job = data;
- DynamicBuffer *dbuf = job_data(job);
+ DynamicBuffer *dbuf = data;
size_t nread = buf->size;
dynamic_buffer_ensure(dbuf, dbuf->len + nread + 1);
@@ -294,16 +309,25 @@ static void system_data_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
dbuf->len += nread;
}
-static void out_data_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
+static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,
+ bool eof)
{
- RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
- size_t written = write_output(ptr, len, false,
- eof && len <= rbuffer_size(buf));
- if (written) {
- rbuffer_consumed(buf, written);
- } else {
- break;
- }
+ size_t cnt;
+ char *ptr = rbuffer_read_ptr(buf, &cnt);
+
+ if (!cnt) {
+ return;
+ }
+
+ size_t written = write_output(ptr, cnt, false, eof);
+ // No output written, force emptying the Rbuffer if it is full.
+ if (!written && rbuffer_size(buf) == rbuffer_capacity(buf)) {
+ screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ screen_puts_len((char_u *)ptr, (int)cnt, (int)Rows - 1, 0, 0);
+ written = cnt;
+ }
+ if (written) {
+ rbuffer_consumed(buf, written);
}
}
@@ -420,6 +444,7 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
if (!output) {
return 0;
}
+ char replacement_NUL = to_buffer ? NL : 1;
char *start = output;
size_t off = 0;
@@ -427,9 +452,10 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
while (off < remaining) {
if (output[off] == NL) {
// Insert the line
- output[off] = NUL;
if (to_buffer) {
- ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false);
+ output[off] = NUL;
+ ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1,
+ false);
} else {
screen_del_lines(0, 0, 1, (int)Rows, NULL);
screen_puts_len((char_u *)output, (int)off, lastrow, 0, 0);
@@ -443,7 +469,7 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
if (output[off] == NUL) {
// Translate NUL to NL
- output[off] = NL;
+ output[off] = replacement_NUL;
}
off++;
}
@@ -470,8 +496,7 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
return (size_t)(output - start);
}
-static void shell_write_cb(WStream *wstream, void *data, int status)
+static void shell_write_cb(Stream *stream, void *data, int status)
{
- Job *job = data;
- job_close_in(job);
+ stream_close(stream, NULL);
}
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index f824543003..7158721433 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -11,12 +11,13 @@
#include "nvim/memory.h"
#include "nvim/misc1.h"
#include "nvim/misc2.h"
+#include "nvim/event/signal.h"
#include "nvim/os/signal.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
-static uv_signal_t spipe, shup, squit, sterm;
+static SignalWatcher spipe, shup, squit, sterm;
#ifdef SIGPWR
-static uv_signal_t spwr;
+static SignalWatcher spwr;
#endif
static bool rejecting_deadly;
@@ -27,40 +28,40 @@ static bool rejecting_deadly;
void signal_init(void)
{
- uv_signal_init(uv_default_loop(), &spipe);
- uv_signal_init(uv_default_loop(), &shup);
- uv_signal_init(uv_default_loop(), &squit);
- uv_signal_init(uv_default_loop(), &sterm);
- uv_signal_start(&spipe, signal_cb, SIGPIPE);
- uv_signal_start(&shup, signal_cb, SIGHUP);
- uv_signal_start(&squit, signal_cb, SIGQUIT);
- uv_signal_start(&sterm, signal_cb, SIGTERM);
+ signal_watcher_init(&loop, &spipe, NULL);
+ signal_watcher_init(&loop, &shup, NULL);
+ signal_watcher_init(&loop, &squit, NULL);
+ signal_watcher_init(&loop, &sterm, NULL);
+ signal_watcher_start(&spipe, on_signal, SIGPIPE);
+ signal_watcher_start(&shup, on_signal, SIGHUP);
+ signal_watcher_start(&squit, on_signal, SIGQUIT);
+ signal_watcher_start(&sterm, on_signal, SIGTERM);
#ifdef SIGPWR
- uv_signal_init(uv_default_loop(), &spwr);
- uv_signal_start(&spwr, signal_cb, SIGPWR);
+ signal_watcher_init(&loop, &spwr, NULL);
+ signal_watcher_start(&spwr, on_signal, SIGPWR);
#endif
}
void signal_teardown(void)
{
signal_stop();
- uv_close((uv_handle_t *)&spipe, NULL);
- uv_close((uv_handle_t *)&shup, NULL);
- uv_close((uv_handle_t *)&squit, NULL);
- uv_close((uv_handle_t *)&sterm, NULL);
+ signal_watcher_close(&spipe, NULL);
+ signal_watcher_close(&shup, NULL);
+ signal_watcher_close(&squit, NULL);
+ signal_watcher_close(&sterm, NULL);
#ifdef SIGPWR
- uv_close((uv_handle_t *)&spwr, NULL);
+ signal_watcher_close(&spwr, NULL);
#endif
}
void signal_stop(void)
{
- uv_signal_stop(&spipe);
- uv_signal_stop(&shup);
- uv_signal_stop(&squit);
- uv_signal_stop(&sterm);
+ signal_watcher_stop(&spipe);
+ signal_watcher_stop(&shup);
+ signal_watcher_stop(&squit);
+ signal_watcher_stop(&sterm);
#ifdef SIGPWR
- uv_signal_stop(&spwr);
+ signal_watcher_stop(&spwr);
#endif
}
@@ -111,19 +112,9 @@ static void deadly_signal(int signum)
preserve_exit();
}
-static void signal_cb(uv_signal_t *handle, int signum)
+static void on_signal(SignalWatcher *handle, int signum, void *data)
{
assert(signum >= 0);
- event_push((Event) {
- .handler = on_signal_event,
- .data = (void *)(uintptr_t)signum
- }, false);
-}
-
-static void on_signal_event(Event event)
-{
- int signum = (int)(uintptr_t)event.data;
-
switch (signum) {
#ifdef SIGPWR
case SIGPWR:
@@ -147,4 +138,3 @@ static void on_signal_event(Event event)
break;
}
}
-
diff --git a/src/nvim/os/signal.h b/src/nvim/os/signal.h
index 927437b2db..5d8cc6f661 100644
--- a/src/nvim/os/signal.h
+++ b/src/nvim/os/signal.h
@@ -1,8 +1,6 @@
#ifndef NVIM_OS_SIGNAL_H
#define NVIM_OS_SIGNAL_H
-#include "nvim/os/event_defs.h"
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/signal.h.generated.h"
#endif
diff --git a/src/nvim/os/stream.c b/src/nvim/os/stream.c
deleted file mode 100644
index 0c448872c3..0000000000
--- a/src/nvim/os/stream.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// Functions for working with stdio streams (as opposed to RStream/WStream).
-
-#include <stdio.h>
-#include <stdbool.h>
-
-#include <uv.h>
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/stream.c.generated.h"
-#endif
-
-/// Sets the stream associated with `fd` to "blocking" mode.
-///
-/// @return `0` on success, or `-errno` on failure.
-int stream_set_blocking(int fd, bool blocking)
-{
- // Private loop to avoid conflict with existing watcher(s):
- // uv__io_stop: Assertion `loop->watchers[w->fd] == w' failed.
- uv_loop_t loop;
- uv_pipe_t stream;
- uv_loop_init(&loop);
- uv_pipe_init(&loop, &stream, 0);
- uv_pipe_open(&stream, fd);
- int retval = uv_stream_set_blocking((uv_stream_t *)&stream, blocking);
- uv_close((uv_handle_t *)&stream, NULL);
- uv_run(&loop, UV_RUN_NOWAIT); // not necessary, but couldn't hurt.
- uv_loop_close(&loop);
- return retval;
-}
-
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 590dfba797..ee17938afc 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -7,7 +7,7 @@
#include <uv.h>
#include "nvim/os/time.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
#include "nvim/vim.h"
static uv_mutex_t delay_mutex;
@@ -43,7 +43,7 @@ void os_delay(uint64_t milliseconds, bool ignoreinput)
if (milliseconds > INT_MAX) {
milliseconds = INT_MAX;
}
- event_poll_until((int)milliseconds, got_int);
+ LOOP_PROCESS_EVENTS_UNTIL(&loop, NULL, (int)milliseconds, got_int);
} else {
os_microdelay(milliseconds * 1000);
}
diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c
index a57ba41af1..637a86c74f 100644
--- a/src/nvim/os/users.c
+++ b/src/nvim/os/users.c
@@ -41,7 +41,12 @@ int os_get_usernames(garray_T *users)
// Return OK if a name found.
int os_get_user_name(char *s, size_t len)
{
+#ifdef UNIX
return os_get_uname(getuid(), s, len);
+#else
+ // TODO(equalsraf): Windows GetUserName()
+ return os_get_uname(0, s, len);
+#endif
}
// Insert user name for "uid" in s[len].
diff --git a/src/nvim/os/uv_helpers.c b/src/nvim/os/uv_helpers.c
deleted file mode 100644
index 89687bdac7..0000000000
--- a/src/nvim/os/uv_helpers.c
+++ /dev/null
@@ -1,98 +0,0 @@
-#include <assert.h>
-#include <uv.h>
-
-#include "nvim/os/uv_helpers.h"
-#include "nvim/vim.h"
-#include "nvim/memory.h"
-
-/// Common structure that will always be assigned to the `data` field of
-/// libuv handles. It has fields for many types of pointers, and allow a single
-/// handle to contain data from many sources
-typedef struct {
- WStream *wstream;
- RStream *rstream;
- Job *job;
-} HandleData;
-
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/uv_helpers.c.generated.h"
-#endif
-
-/// Gets the RStream instance associated with a libuv handle
-///
-/// @param handle libuv handle
-/// @return the RStream pointer
-RStream *handle_get_rstream(uv_handle_t *handle)
-{
- RStream *rv = init(handle)->rstream;
- assert(rv != NULL);
- return rv;
-}
-
-/// Associates a RStream instance with a libuv handle
-///
-/// @param handle libuv handle
-/// @param rstream the RStream pointer
-void handle_set_rstream(uv_handle_t *handle, RStream *rstream)
-{
- init(handle)->rstream = rstream;
-}
-
-/// Gets the WStream instance associated with a libuv handle
-///
-/// @param handle libuv handle
-/// @return the WStream pointer
-WStream *handle_get_wstream(uv_handle_t *handle)
-{
- WStream *rv = init(handle)->wstream;
- assert(rv != NULL);
- return rv;
-}
-
-/// Associates a WStream instance with a libuv handle
-///
-/// @param handle libuv handle
-/// @param wstream the WStream pointer
-void handle_set_wstream(uv_handle_t *handle, WStream *wstream)
-{
- HandleData *data = init(handle);
- data->wstream = wstream;
-}
-
-/// Gets the Job instance associated with a libuv handle
-///
-/// @param handle libuv handle
-/// @return the Job pointer
-Job *handle_get_job(uv_handle_t *handle)
-{
- Job *rv = init(handle)->job;
- assert(rv != NULL);
- return rv;
-}
-
-/// Associates a Job instance with a libuv handle
-///
-/// @param handle libuv handle
-/// @param job the Job pointer
-void handle_set_job(uv_handle_t *handle, Job *job)
-{
- init(handle)->job = job;
-}
-
-static HandleData *init(uv_handle_t *handle)
-{
- HandleData *rv;
-
- if (handle->data == NULL) {
- rv = xmalloc(sizeof(HandleData));
- rv->rstream = NULL;
- rv->wstream = NULL;
- rv->job = NULL;
- handle->data = rv;
- } else {
- rv = handle->data;
- }
-
- return rv;
-}
diff --git a/src/nvim/os/uv_helpers.h b/src/nvim/os/uv_helpers.h
deleted file mode 100644
index b49656bcb8..0000000000
--- a/src/nvim/os/uv_helpers.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef NVIM_OS_UV_HELPERS_H
-#define NVIM_OS_UV_HELPERS_H
-
-#include <uv.h>
-
-#include "nvim/os/wstream_defs.h"
-#include "nvim/os/rstream_defs.h"
-#include "nvim/os/job_defs.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/uv_helpers.h.generated.h"
-#endif
-#endif // NVIM_OS_UV_HELPERS_H
diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h
index 19d796bd08..a51898c9e7 100644
--- a/src/nvim/os/win_defs.h
+++ b/src/nvim/os/win_defs.h
@@ -21,4 +21,12 @@
// - SYS_VIMRC_FILE
// - SPECIAL_WILDCHAR
+// _access(): https://msdn.microsoft.com/en-us/library/1w06ktdy.aspx
+#ifndef R_OK
+# define R_OK 4
+#endif
+#ifndef W_OK
+# define W_OK 2
+#endif
+
#endif // NVIM_OS_WIN_DEFS_H
diff --git a/src/nvim/os/wstream.c b/src/nvim/os/wstream.c
deleted file mode 100644
index 73896c381d..0000000000
--- a/src/nvim/os/wstream.c
+++ /dev/null
@@ -1,243 +0,0 @@
-#include <assert.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include <uv.h>
-
-#include "nvim/os/uv_helpers.h"
-#include "nvim/os/wstream.h"
-#include "nvim/os/wstream_defs.h"
-#include "nvim/vim.h"
-#include "nvim/memory.h"
-
-#define DEFAULT_MAXMEM 1024 * 1024 * 10
-
-struct wstream {
- uv_stream_t *stream;
- // Memory currently used by pending buffers
- size_t curmem;
- // Maximum memory used by this instance
- size_t maxmem;
- // Number of pending requests
- size_t pending_reqs;
- bool freed, free_handle;
- // (optional) Write callback and data
- wstream_cb cb;
- void *data;
-};
-
-struct wbuffer {
- size_t size, refcount;
- char *data;
- wbuffer_data_finalizer cb;
-};
-
-typedef struct {
- WStream *wstream;
- WBuffer *buffer;
- uv_write_t uv_req;
-} WRequest;
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/wstream.c.generated.h"
-#endif
-
-/// Creates a new WStream instance. A WStream encapsulates all the boilerplate
-/// necessary for writing to a libuv stream.
-///
-/// @param maxmem Maximum amount memory used by this `WStream` instance. If 0,
-/// a default value of 10mb will be used.
-/// @return The newly-allocated `WStream` instance
-WStream * wstream_new(size_t maxmem)
-{
- if (!maxmem) {
- maxmem = DEFAULT_MAXMEM;
- }
-
- WStream *rv = xmalloc(sizeof(WStream));
- rv->maxmem = maxmem;
- rv->stream = NULL;
- rv->curmem = 0;
- rv->pending_reqs = 0;
- rv->freed = false;
- rv->free_handle = false;
- rv->cb = NULL;
-
- return rv;
-}
-
-/// Frees all memory allocated for a WStream instance
-///
-/// @param wstream The `WStream` instance
-void wstream_free(WStream *wstream) {
- if (!wstream->pending_reqs) {
- if (wstream->free_handle) {
- uv_close((uv_handle_t *)wstream->stream, close_cb);
- } else {
- handle_set_wstream((uv_handle_t *)wstream->stream, NULL);
- xfree(wstream);
- }
- } else {
- wstream->freed = true;
- }
-}
-
-/// Sets the underlying `uv_stream_t` instance
-///
-/// @param wstream The `WStream` instance
-/// @param stream The new `uv_stream_t` instance
-void wstream_set_stream(WStream *wstream, uv_stream_t *stream)
-{
- handle_set_wstream((uv_handle_t *)stream, wstream);
- wstream->stream = stream;
-}
-
-/// Sets the underlying file descriptor that will be written to. Only pipes
-/// are supported for now.
-///
-/// @param wstream The `WStream` instance
-/// @param file The file descriptor
-void wstream_set_file(WStream *wstream, uv_file file)
-{
- assert(uv_guess_handle(file) == UV_NAMED_PIPE ||
- uv_guess_handle(file) == UV_TTY);
- wstream->stream = xmalloc(sizeof(uv_pipe_t));
- uv_pipe_init(uv_default_loop(), (uv_pipe_t *)wstream->stream, 0);
- uv_pipe_open((uv_pipe_t *)wstream->stream, file);
- wstream->stream->data = NULL;
- handle_set_wstream((uv_handle_t *)wstream->stream, wstream);
- wstream->free_handle = true;
-}
-
-/// Sets a callback that will be called on completion of a write request,
-/// indicating failure/success.
-///
-/// This affects all requests currently in-flight as well. Overwrites any
-/// possible earlier callback.
-///
-/// @note This callback will not fire if the write request couldn't even be
-/// queued properly (i.e.: when `wstream_write() returns an error`).
-///
-/// @param wstream The `WStream` instance
-/// @param cb The callback
-/// @param data User-provided data that will be passed to `cb`
-void wstream_set_write_cb(WStream *wstream, wstream_cb cb, void *data)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- wstream->cb = cb;
- wstream->data = data;
-}
-
-/// Queues data for writing to the backing file descriptor of a `WStream`
-/// instance. This will fail if the write would cause the WStream use more
-/// memory than specified by `maxmem`.
-///
-/// @param wstream The `WStream` instance
-/// @param buffer The buffer which contains data to be written
-/// @return false if the write failed
-bool wstream_write(WStream *wstream, WBuffer *buffer)
-{
- // This should not be called after a wstream was freed
- assert(!wstream->freed);
-
- if (wstream->curmem > wstream->maxmem) {
- goto err;
- }
-
- wstream->curmem += buffer->size;
-
- WRequest *data = xmalloc(sizeof(WRequest));
- data->wstream = wstream;
- data->buffer = buffer;
- data->uv_req.data = data;
-
- uv_buf_t uvbuf;
- uvbuf.base = buffer->data;
- uvbuf.len = buffer->size;
-
- if (uv_write(&data->uv_req, wstream->stream, &uvbuf, 1, write_cb)) {
- xfree(data);
- goto err;
- }
-
- wstream->pending_reqs++;
- return true;
-
-err:
- wstream_release_wbuffer(buffer);
- return false;
-}
-
-/// Creates a WBuffer object for holding output data. Instances of this
-/// object can be reused across WStream instances, and the memory is freed
-/// automatically when no longer needed(it tracks the number of references
-/// internally)
-///
-/// @param data Data stored by the WBuffer
-/// @param size The size of the data array
-/// @param refcount The number of references for the WBuffer. This will be used
-/// by WStream instances to decide when a WBuffer should be freed.
-/// @param cb Pointer to function that will be responsible for freeing
-/// the buffer data(passing 'free' will work as expected).
-/// @return The allocated WBuffer instance
-WBuffer *wstream_new_buffer(char *data,
- size_t size,
- size_t refcount,
- wbuffer_data_finalizer cb)
-{
- WBuffer *rv = xmalloc(sizeof(WBuffer));
- rv->size = size;
- rv->refcount = refcount;
- rv->cb = cb;
- rv->data = data;
-
- return rv;
-}
-
-static void write_cb(uv_write_t *req, int status)
-{
- WRequest *data = req->data;
-
- data->wstream->curmem -= data->buffer->size;
-
- wstream_release_wbuffer(data->buffer);
-
- if (data->wstream->cb) {
- data->wstream->cb(data->wstream,
- data->wstream->data,
- status);
- }
-
- data->wstream->pending_reqs--;
-
- if (data->wstream->freed && data->wstream->pending_reqs == 0) {
- // Last pending write, free the wstream;
- if (data->wstream->free_handle) {
- uv_close((uv_handle_t *)data->wstream->stream, close_cb);
- } else {
- xfree(data->wstream);
- }
- }
-
- xfree(data);
-}
-
-void wstream_release_wbuffer(WBuffer *buffer)
-{
- if (!--buffer->refcount) {
- if (buffer->cb) {
- buffer->cb(buffer->data);
- }
-
- xfree(buffer);
- }
-}
-
-static void close_cb(uv_handle_t *handle)
-{
- xfree(handle_get_wstream(handle));
- xfree(handle->data);
- xfree(handle);
-}
-
diff --git a/src/nvim/os/wstream.h b/src/nvim/os/wstream.h
deleted file mode 100644
index d0e9bef93a..0000000000
--- a/src/nvim/os/wstream.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef NVIM_OS_WSTREAM_H
-#define NVIM_OS_WSTREAM_H
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <uv.h>
-
-#include "nvim/os/wstream_defs.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "os/wstream.h.generated.h"
-#endif
-#endif // NVIM_OS_WSTREAM_H
diff --git a/src/nvim/os/wstream_defs.h b/src/nvim/os/wstream_defs.h
deleted file mode 100644
index cfa0bf0b60..0000000000
--- a/src/nvim/os/wstream_defs.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef NVIM_OS_WSTREAM_DEFS_H
-#define NVIM_OS_WSTREAM_DEFS_H
-
-typedef struct wbuffer WBuffer;
-typedef struct wstream WStream;
-typedef void (*wbuffer_data_finalizer)(void *data);
-
-/// Type of function called when the WStream has information about a write
-/// request.
-///
-/// @param wstream The `WStream` instance
-/// @param data User-defined data
-/// @param status 0 on success, anything else indicates failure
-typedef void (*wstream_cb)(WStream *wstream,
- void *data,
- int status);
-
-#endif // NVIM_OS_WSTREAM_DEFS_H
-
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index ccd0073db1..122b3a171d 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -47,13 +47,10 @@
#include "nvim/types.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
-#include "nvim/os/event.h"
#include "nvim/os/input.h"
#include "nvim/os/shell.h"
#include "nvim/os/signal.h"
-#include "nvim/os/job.h"
#include "nvim/msgpack_rpc/helpers.h"
-#include "nvim/msgpack_rpc/defs.h"
#ifdef HAVE_STROPTS_H
# include <stropts.h>
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 152154e5f4..72980fcd0e 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -481,6 +481,21 @@ static size_t path_expand(garray_T *gap, const char_u *path, int flags)
return do_path_expand(gap, path, 0, flags, false);
}
+static const char *scandir_next_with_dots(Directory *dir)
+{
+ static int count = 0;
+ if (dir == NULL) { // initialize
+ count = 0;
+ return NULL;
+ }
+
+ count += 1;
+ if (count == 1 || count == 2) {
+ return (count == 1) ? "." : "..";
+ }
+ return os_scandir_next(dir);
+}
+
/// Implementation of path_expand().
///
/// Chars before `path + wildoff` do not get expanded.
@@ -597,11 +612,12 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
*s = NUL;
Directory dir;
- // open the directory for scanning
- if (os_scandir(&dir, *buf == NUL ? "." : (char *)buf)) {
+ if (os_scandir(&dir, *buf == NUL ? "." : (char *)buf)
+ || os_isdir(*buf == NUL ? (char_u *)"." : (char_u *)buf)) {
// Find all matching entries.
char_u *name;
- while((name = (char_u *) os_scandir_next(&dir))) {
+ scandir_next_with_dots(NULL /* initialize */);
+ while((name = (char_u *) scandir_next_with_dots(&dir)) && name != NULL) {
if ((name[0] != '.' || starts_with_dot)
&& ((regmatch.regprog != NULL && vim_regexec(&regmatch, name, 0))
|| ((flags & EW_NOTWILD)
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index dddd347822..e2c4b590d0 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -961,10 +961,10 @@ static void reg_equi_class(int c)
REGMBC(0x107) REGMBC(0x109) REGMBC(0x10b)
REGMBC(0x10d)
return;
- case 'd': CASEMBC(0x10f) CASEMBC(0x111) CASEMBC(0x1d0b)
- CASEMBC(0x1e11)
+ case 'd': CASEMBC(0x10f) CASEMBC(0x111) CASEMBC(0x1e0b)
+ CASEMBC(0x1e0f) CASEMBC(0x1e11)
regmbc('d'); REGMBC(0x10f) REGMBC(0x111)
- REGMBC(0x1e0b) REGMBC(0x01e0f) REGMBC(0x1e11)
+ REGMBC(0x1e0b) REGMBC(0x1e0f) REGMBC(0x1e11)
return;
case 'e': case '\350': case '\351': case '\352': case '\353':
CASEMBC(0x113) CASEMBC(0x115) CASEMBC(0x117) CASEMBC(0x119)
@@ -1104,7 +1104,7 @@ static int get_coll_element(char_u **pp)
int l = 1;
char_u *p = *pp;
- if (p[1] == '.') {
+ if (p[0] != NUL && p[1] == '.') {
if (has_mbyte)
l = (*mb_ptr2len)(p + 2);
if (p[l + 2] == '.' && p[l + 3] == ']') {
@@ -1120,12 +1120,10 @@ static int get_coll_element(char_u **pp)
}
static int reg_cpo_lit; /* 'cpoptions' contains 'l' flag */
-static int reg_cpo_bsl; /* 'cpoptions' contains '\' flag */
static void get_cpo_flags(void)
{
reg_cpo_lit = vim_strchr(p_cpo, CPO_LITERAL) != NULL;
- reg_cpo_bsl = vim_strchr(p_cpo, CPO_BACKSL) != NULL;
}
/*
@@ -1149,15 +1147,15 @@ static char_u *skip_anyof(char_u *p)
if (*p != ']' && *p != NUL)
mb_ptr_adv(p);
} else if (*p == '\\'
- && !reg_cpo_bsl
&& (vim_strchr(REGEXP_INRANGE, p[1]) != NULL
|| (!reg_cpo_lit && vim_strchr(REGEXP_ABBR, p[1]) != NULL)))
p += 2;
else if (*p == '[') {
if (get_char_class(&p) == CLASS_NONE
&& get_equi_class(&p) == 0
- && get_coll_element(&p) == 0)
- ++p; /* It was not a class name */
+ && get_coll_element(&p) == 0
+ && *p != NUL)
+ ++p; /* It is not a class name and not NUL */
} else
++p;
}
@@ -2221,7 +2219,7 @@ collection:
}
/* Handle \o40, \x20 and \u20AC style sequences */
- if (endc == '\\' && !reg_cpo_lit && !reg_cpo_bsl)
+ if (endc == '\\' && !reg_cpo_lit)
endc = coll_get_char();
if (startc > endc)
@@ -2244,10 +2242,8 @@ collection:
* Only "\]", "\^", "\]" and "\\" are special in Vi. Vim
* accepts "\t", "\e", etc., but only when the 'l' flag in
* 'cpoptions' is not included.
- * Posix doesn't recognize backslash at all.
*/
else if (*regparse == '\\'
- && !reg_cpo_bsl
&& (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL
|| (!reg_cpo_lit
&& vim_strchr(REGEXP_ABBR,
@@ -2848,7 +2844,7 @@ static int peekchr(void)
/*
* META contains everything that may be magic sometimes,
* except ^ and $ ("\^" and "\$" are only magic after
- * "\v"). We now fetch the next character and toggle its
+ * "\V"). We now fetch the next character and toggle its
* magicness. Therefore, \ is so meta-magic that it is
* not in META.
*/
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index d9dc09b623..484dfe1e1f 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -270,8 +270,10 @@ typedef struct {
/* When REG_MULTI is TRUE list.multi is used, otherwise list.line. */
union {
struct multipos {
- lpos_T start;
- lpos_T end;
+ linenr_T start_lnum;
+ linenr_T end_lnum;
+ colnr_T start_col;
+ colnr_T end_col;
} multi[NSUBEXP];
struct linepos {
char_u *start;
@@ -716,8 +718,8 @@ static int nfa_recognize_char_class(char_u *start, char_u *end, int extra_newl)
*/
static void nfa_emit_equi_class(int c)
{
-#define EMIT2(c) EMIT(c); EMIT(NFA_CONCAT);
-# define EMITMBC(c) EMIT(c); EMIT(NFA_CONCAT);
+#define EMIT2(c) EMIT(c); EMIT(NFA_CONCAT);
+#define EMITMBC(c) EMIT(c); EMIT(NFA_CONCAT);
if (enc_utf8 || STRCMP(p_enc, "latin1") == 0
|| STRCMP(p_enc, "iso-8859-15") == 0) {
@@ -906,10 +908,10 @@ static void nfa_emit_equi_class(int c)
EMITMBC(0x10b) EMITMBC(0x10d)
return;
- case 'd': CASEMBC(0x10f) CASEMBC(0x111) CASEMBC(0x1d0b)
- CASEMBC(0x1e11)
+ case 'd': CASEMBC(0x10f) CASEMBC(0x111) CASEMBC(0x1e0b)
+ CASEMBC(0x1e0f) CASEMBC(0x1e11)
EMIT2('d'); EMITMBC(0x10f) EMITMBC(0x111) EMITMBC(0x1e0b)
- EMITMBC(0x01e0f) EMITMBC(0x1e11)
+ EMITMBC(0x1e0f) EMITMBC(0x1e11)
return;
case 'e': case 0350: case 0351: case 0352: case 0353:
@@ -1391,7 +1393,7 @@ static int nfa_regatom(void)
* matched an unlimited number of times. NFA_NOPEN is
* added only once at a position, while NFA_SPLIT is
* added multiple times. This is more efficient than
- * not allowsing NFA_SPLIT multiple times, it is used
+ * not allowing NFA_SPLIT multiple times, it is used
* a lot. */
EMIT(NFA_NOPEN);
break;
@@ -1584,10 +1586,8 @@ collection:
* Only "\]", "\^", "\]" and "\\" are special in Vi. Vim
* accepts "\t", "\e", etc., but only when the 'l' flag in
* 'cpoptions' is not included.
- * Posix doesn't recognize backslash at all.
*/
if (*regparse == '\\'
- && !reg_cpo_bsl
&& regparse + 1 <= endp
&& (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL
|| (!reg_cpo_lit
@@ -3433,10 +3433,10 @@ static void log_subexpr(regsub_T *sub)
if (REG_MULTI)
fprintf(log_fd, "*** group %d, start: c=%d, l=%d, end: c=%d, l=%d\n",
j,
- sub->list.multi[j].start.col,
- (int)sub->list.multi[j].start.lnum,
- sub->list.multi[j].end.col,
- (int)sub->list.multi[j].end.lnum);
+ sub->list.multi[j].start_col,
+ (int)sub->list.multi[j].start_lnum,
+ sub->list.multi[j].end_col,
+ (int)sub->list.multi[j].end_lnum);
else {
char *s = (char *)sub->list.line[j].start;
char *e = (char *)sub->list.line[j].end;
@@ -3537,8 +3537,10 @@ static void copy_ze_off(regsub_T *to, regsub_T *from)
{
if (nfa_has_zend) {
if (REG_MULTI) {
- if (from->list.multi[0].end.lnum >= 0)
- to->list.multi[0].end = from->list.multi[0].end;
+ if (from->list.multi[0].end_lnum >= 0){
+ to->list.multi[0].end_lnum = from->list.multi[0].end_lnum;
+ to->list.multi[0].end_col = from->list.multi[0].end_col;
+ }
} else {
if (from->list.line[0].end != NULL)
to->list.line[0].end = from->list.line[0].end;
@@ -3561,27 +3563,27 @@ static int sub_equal(regsub_T *sub1, regsub_T *sub2)
if (REG_MULTI) {
for (i = 0; i < todo; ++i) {
if (i < sub1->in_use)
- s1 = sub1->list.multi[i].start.lnum;
+ s1 = sub1->list.multi[i].start_lnum;
else
s1 = -1;
if (i < sub2->in_use)
- s2 = sub2->list.multi[i].start.lnum;
+ s2 = sub2->list.multi[i].start_lnum;
else
s2 = -1;
if (s1 != s2)
return FALSE;
- if (s1 != -1 && sub1->list.multi[i].start.col
- != sub2->list.multi[i].start.col)
+ if (s1 != -1 && sub1->list.multi[i].start_col
+ != sub2->list.multi[i].start_col)
return FALSE;
if (nfa_has_backref) {
if (i < sub1->in_use) {
- s1 = sub1->list.multi[i].end.lnum;
+ s1 = sub1->list.multi[i].end_lnum;
} else {
s1 = -1;
}
if (i < sub2->in_use) {
- s2 = sub2->list.multi[i].end.lnum;
+ s2 = sub2->list.multi[i].end_lnum;
} else {
s2 = -1;
}
@@ -3589,7 +3591,7 @@ static int sub_equal(regsub_T *sub1, regsub_T *sub2)
return FALSE;
}
if (s1 != -1
- && sub1->list.multi[i].end.col != sub2->list.multi[i].end.col) {
+ && sub1->list.multi[i].end_col != sub2->list.multi[i].end_col) {
return FALSE;
}
}
@@ -3639,7 +3641,7 @@ static void report_state(char *action,
if (sub->in_use <= 0)
col = -1;
else if (REG_MULTI)
- col = sub->list.multi[0].start.col;
+ col = sub->list.multi[0].start_col;
else
col = (int)(sub->list.line[0].start - regline);
nfa_set_code(state->c);
@@ -4025,22 +4027,24 @@ skip_add:
* and restore it when it was in use. Otherwise fill any gap. */
if (REG_MULTI) {
if (subidx < sub->in_use) {
- save_lpos = sub->list.multi[subidx].start;
+ save_lpos.lnum = sub->list.multi[subidx].start_lnum;
+ save_lpos.col = sub->list.multi[subidx].start_col;
save_in_use = -1;
} else {
save_in_use = sub->in_use;
for (i = sub->in_use; i < subidx; ++i) {
- sub->list.multi[i].start.lnum = -1;
- sub->list.multi[i].end.lnum = -1;
+ sub->list.multi[i].start_lnum = -1;
+ sub->list.multi[i].end_lnum = -1;
}
sub->in_use = subidx + 1;
}
if (off == -1) {
- sub->list.multi[subidx].start.lnum = reglnum + 1;
- sub->list.multi[subidx].start.col = 0;
+ sub->list.multi[subidx].start_lnum = reglnum + 1;
+ sub->list.multi[subidx].start_col = 0;
} else {
- sub->list.multi[subidx].start.lnum = reglnum;
- sub->list.multi[subidx].start.col =
+
+ sub->list.multi[subidx].start_lnum = reglnum;
+ sub->list.multi[subidx].start_col =
(colnr_T)(reginput - regline + off);
}
} else {
@@ -4066,8 +4070,10 @@ skip_add:
sub = &subs->norm;
if (save_in_use == -1) {
- if (REG_MULTI)
- sub->list.multi[subidx].start = save_lpos;
+ if (REG_MULTI){
+ sub->list.multi[subidx].start_lnum = save_lpos.lnum;
+ sub->list.multi[subidx].start_col = save_lpos.col;
+ }
else
sub->list.line[subidx].start = save_ptr;
} else
@@ -4076,7 +4082,7 @@ skip_add:
case NFA_MCLOSE:
if (nfa_has_zend && (REG_MULTI
- ? subs->norm.list.multi[0].end.lnum >= 0
+ ? subs->norm.list.multi[0].end_lnum >= 0
: subs->norm.list.line[0].end != NULL)) {
/* Do not overwrite the position set by \ze. */
subs = addstate(l, state->out, subs, pim, off);
@@ -4119,13 +4125,14 @@ skip_add:
if (sub->in_use <= subidx)
sub->in_use = subidx + 1;
if (REG_MULTI) {
- save_lpos = sub->list.multi[subidx].end;
+ save_lpos.lnum = sub->list.multi[subidx].end_lnum;
+ save_lpos.col = sub->list.multi[subidx].end_col;
if (off == -1) {
- sub->list.multi[subidx].end.lnum = reglnum + 1;
- sub->list.multi[subidx].end.col = 0;
+ sub->list.multi[subidx].end_lnum = reglnum + 1;
+ sub->list.multi[subidx].end_col = 0;
} else {
- sub->list.multi[subidx].end.lnum = reglnum;
- sub->list.multi[subidx].end.col =
+ sub->list.multi[subidx].end_lnum = reglnum;
+ sub->list.multi[subidx].end_col =
(colnr_T)(reginput - regline + off);
}
/* avoid compiler warnings */
@@ -4145,8 +4152,10 @@ skip_add:
else
sub = &subs->norm;
- if (REG_MULTI)
- sub->list.multi[subidx].end = save_lpos;
+ if (REG_MULTI){
+ sub->list.multi[subidx].end_lnum = save_lpos.lnum;
+ sub->list.multi[subidx].end_col = save_lpos.col;
+ }
else
sub->list.line[subidx].end = save_ptr;
sub->in_use = save_in_use;
@@ -4321,24 +4330,24 @@ retempty:
}
if (REG_MULTI) {
- if (sub->list.multi[subidx].start.lnum < 0
- || sub->list.multi[subidx].end.lnum < 0)
+ if (sub->list.multi[subidx].start_lnum < 0
+ || sub->list.multi[subidx].end_lnum < 0)
goto retempty;
- if (sub->list.multi[subidx].start.lnum == reglnum
- && sub->list.multi[subidx].end.lnum == reglnum) {
- len = sub->list.multi[subidx].end.col
- - sub->list.multi[subidx].start.col;
- if (cstrncmp(regline + sub->list.multi[subidx].start.col,
+ if (sub->list.multi[subidx].start_lnum == reglnum
+ && sub->list.multi[subidx].end_lnum == reglnum) {
+ len = sub->list.multi[subidx].end_col
+ - sub->list.multi[subidx].start_col;
+ if (cstrncmp(regline + sub->list.multi[subidx].start_col,
reginput, &len) == 0) {
*bytelen = len;
return TRUE;
}
} else {
if (match_with_backref(
- sub->list.multi[subidx].start.lnum,
- sub->list.multi[subidx].start.col,
- sub->list.multi[subidx].end.lnum,
- sub->list.multi[subidx].end.col,
+ sub->list.multi[subidx].start_lnum,
+ sub->list.multi[subidx].start_col,
+ sub->list.multi[subidx].end_lnum,
+ sub->list.multi[subidx].end_col,
bytelen) == RA_MATCH)
return TRUE;
}
@@ -4875,8 +4884,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
* it's the first MOPEN. */
if (toplevel) {
if (REG_MULTI) {
- m->norm.list.multi[0].start.lnum = reglnum;
- m->norm.list.multi[0].start.col = (colnr_T)(reginput - regline);
+ m->norm.list.multi[0].start_lnum = reglnum;
+ m->norm.list.multi[0].start_col = (colnr_T)(reginput - regline);
} else
m->norm.list.line[0].start = reginput;
m->norm.in_use = 1;
@@ -4964,7 +4973,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
if (t->subs.norm.in_use <= 0)
col = -1;
else if (REG_MULTI)
- col = t->subs.norm.list.multi[0].start.col;
+ col = t->subs.norm.list.multi[0].start_col;
else
col = (int)(t->subs.norm.list.line[0].start - regline);
nfa_set_code(t->state->c);
@@ -5216,7 +5225,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
* continue with what follows. */
if (REG_MULTI)
/* TODO: multi-line match */
- bytelen = m->norm.list.multi[0].end.col
+ bytelen = m->norm.list.multi[0].end_col
- (int)(reginput - regline);
else
bytelen = (int)(m->norm.list.line[0].end - reginput);
@@ -6020,7 +6029,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
if (add) {
if (REG_MULTI)
- m->norm.list.multi[0].start.col =
+ m->norm.list.multi[0].start_col =
(colnr_T)(reginput - regline) + clen;
else
m->norm.list.line[0].start = reginput + clen;
@@ -6125,8 +6134,11 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col)
cleanup_subexpr();
if (REG_MULTI) {
for (i = 0; i < subs.norm.in_use; i++) {
- reg_startpos[i] = subs.norm.list.multi[i].start;
- reg_endpos[i] = subs.norm.list.multi[i].end;
+ reg_startpos[i].lnum = subs.norm.list.multi[i].start_lnum;
+ reg_startpos[i].col = subs.norm.list.multi[i].start_col;
+
+ reg_endpos[i].lnum = subs.norm.list.multi[i].end_lnum;
+ reg_endpos[i].col = subs.norm.list.multi[i].end_col;
}
if (reg_startpos[0].lnum < 0) {
@@ -6164,12 +6176,12 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col)
struct multipos *mpos = &subs.synt.list.multi[i];
// Only accept single line matches that are valid.
- if (mpos->start.lnum >= 0
- && mpos->start.lnum == mpos->end.lnum
- && mpos->end.col >= mpos->start.col) {
+ if (mpos->start_lnum >= 0
+ && mpos->start_lnum == mpos->end_lnum
+ && mpos->end_col >= mpos->start_col) {
re_extmatch_out->matches[i] =
- vim_strnsave(reg_getline(mpos->start.lnum) + mpos->start.col,
- mpos->end.col - mpos->start.col);
+ vim_strnsave(reg_getline(mpos->start_lnum) + mpos->start_col,
+ mpos->end_col - mpos->start_col);
}
} else {
struct linepos *lpos = &subs.synt.list.line[i];
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 43cb6f4878..d57b84ad50 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -1951,6 +1951,28 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
}
+ // Show colorcolumn in the fold line, but let cursorcolumn override it.
+ if (wp->w_p_cc_cols) {
+ int i = 0;
+ int j = wp->w_p_cc_cols[i];
+ int old_txtcol = txtcol;
+
+ while (j > -1) {
+ txtcol += j;
+ if (wp->w_p_wrap) {
+ txtcol -= wp->w_skipcol;
+ } else {
+ txtcol -= wp->w_leftcol;
+ }
+ if (txtcol >= 0 && txtcol < wp->w_width) {
+ ScreenAttrs[off + txtcol] =
+ hl_combine_attr(ScreenAttrs[off + txtcol], hl_attr(HLF_MC));
+ }
+ txtcol = old_txtcol;
+ j = wp->w_p_cc_cols[++i];
+ }
+ }
+
/* Show 'cursorcolumn' in the fold line. */
if (wp->w_p_cuc) {
txtcol += wp->w_virtcol;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index e10504973b..f91ac3bb9c 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -2199,7 +2199,6 @@ findpar (
linenr_T curr;
bool did_skip; /* true after separating lines have been skipped */
bool first; /* true on first line */
- int posix = (vim_strchr(p_cpo, CPO_PARA) != NULL);
linenr_T fold_first; /* first line of a closed fold */
linenr_T fold_last; /* last line of a closed fold */
bool fold_skipped; /* true if a closed fold was skipped this
@@ -2220,12 +2219,7 @@ findpar (
fold_skipped = true;
}
- /* POSIX has it's own ideas of what a paragraph boundary is and it
- * doesn't match historical Vi: It also stops at a "{" in the
- * first column and at an empty line. */
- if (!first && did_skip && (startPS(curr, what, both)
- || (posix && what == NUL && *ml_get(curr) ==
- '{')))
+ if (!first && did_skip && startPS(curr, what, both))
break;
if (fold_skipped)
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index acff14bc40..f9ed6faff9 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -2328,8 +2328,16 @@ static void spell_load_lang(char_u *lang)
}
if (r == FAIL) {
- smsg(_("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
- lang, spell_enc(), lang);
+ if (starting) {
+ // Some startup file sets &spell, but the necessary files don't exist:
+ // try to prompt the user at VimEnter. Also set spell again. #3027
+ do_cmdline_cmd(
+ "autocmd VimEnter * call spellfile#LoadFile(&spelllang)|set spell");
+ } else {
+ smsg(
+ _("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
+ lang, spell_enc(), lang);
+ }
} else if (sl.sl_slang != NULL) {
// At least one file was loaded, now load ALL the additions.
STRCPY(fname_enc + STRLEN(fname_enc) - 3, "add.spl");
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 42d0421f0c..b9bc4c6d78 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -67,7 +67,9 @@
#include "nvim/ex_cmds.h"
#include "nvim/window.h"
#include "nvim/fileio.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/time.h"
+#include "nvim/os/input.h"
#include "nvim/api/private/helpers.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -80,7 +82,7 @@
// of data.
#define REFRESH_DELAY 10
-static uv_timer_t refresh_timer;
+static TimeWatcher refresh_timer;
static bool refresh_pending = false;
typedef struct {
@@ -150,7 +152,7 @@ static VTermColor default_vt_bg_rgb;
void terminal_init(void)
{
invalidated_terminals = pmap_new(ptr_t)();
- uv_timer_init(uv_default_loop(), &refresh_timer);
+ time_watcher_init(&loop, &refresh_timer, NULL);
// initialize a rgb->color index map for cterm attributes(VTermScreenCell
// only has RGB information and we need color indexes for terminal UIs)
@@ -175,8 +177,8 @@ void terminal_init(void)
void terminal_teardown(void)
{
- uv_timer_stop(&refresh_timer);
- uv_close((uv_handle_t *)&refresh_timer, NULL);
+ time_watcher_stop(&refresh_timer);
+ time_watcher_close(&refresh_timer, NULL);
pmap_free(ptr_t)(invalidated_terminals);
map_free(int, int)(color_indexes);
}
@@ -323,7 +325,7 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height)
invalidate_terminal(term, -1, -1);
}
-void terminal_enter(bool process_deferred)
+void terminal_enter(void)
{
Terminal *term = curbuf->terminal;
assert(term && "should only be called when curbuf has a terminal");
@@ -352,15 +354,9 @@ void terminal_enter(bool process_deferred)
bool got_bs = false; // True if the last input was <C-\>
while (term->buf == curbuf) {
- if (process_deferred) {
- event_enable_deferred();
- }
-
+ input_enable_events();
c = safe_vgetc();
-
- if (process_deferred) {
- event_disable_deferred();
- }
+ input_disable_events();
switch (c) {
case K_LEFTMOUSE:
@@ -380,7 +376,7 @@ void terminal_enter(bool process_deferred)
break;
case K_EVENT:
- event_process();
+ queue_process_events(loop.events);
break;
case Ctrl_N:
@@ -426,7 +422,13 @@ void terminal_destroy(Terminal *term)
term->buf->terminal = NULL;
}
term->buf = NULL;
- pmap_del(ptr_t)(invalidated_terminals, term);
+ if (pmap_has(ptr_t)(invalidated_terminals, term)) {
+ // flush any pending changes to the buffer
+ block_autocmds();
+ refresh_terminal(term);
+ unblock_autocmds();
+ pmap_del(ptr_t)(invalidated_terminals, term);
+ }
for (size_t i = 0 ; i < term->sb_current; i++) {
xfree(term->sb_buffer[i]);
}
@@ -572,9 +574,10 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
case VTERM_PROP_TITLE: {
Error err;
- dict_set_value(term->buf->b_vars,
- cstr_as_string("term_title"),
- STRING_OBJ(cstr_as_string(val->string)), &err);
+ api_free_object(dict_set_value(term->buf->b_vars,
+ cstr_as_string("term_title"),
+ STRING_OBJ(cstr_as_string(val->string)),
+ &err));
break;
}
@@ -876,53 +879,52 @@ static void invalidate_terminal(Terminal *term, int start_row, int end_row)
pmap_put(ptr_t)(invalidated_terminals, term, NULL);
if (!refresh_pending) {
- uv_timer_start(&refresh_timer, refresh_timer_cb, REFRESH_DELAY, 0);
+ time_watcher_start(&refresh_timer, refresh_timer_cb, REFRESH_DELAY, 0);
refresh_pending = true;
}
}
-// libuv timer callback. This will enqueue on_refresh to be processed as an
-// event.
-static void refresh_timer_cb(uv_timer_t *handle)
+static void refresh_terminal(Terminal *term)
{
- event_push((Event) {.handler = on_refresh}, false);
- refresh_pending = false;
+ // TODO(SplinterOfChaos): Find the condition that makes term->buf invalid.
+ bool valid = true;
+ if (!term->buf || !(valid = buf_valid(term->buf))) {
+ // destroyed by `close_buffer`. Dont do anything else
+ if (!valid) {
+ term->buf = NULL;
+ }
+ return;
+ }
+ bool pending_resize = term->pending_resize;
+ WITH_BUFFER(term->buf, {
+ refresh_size(term);
+ refresh_scrollback(term);
+ refresh_screen(term);
+ redraw_buf_later(term->buf, NOT_VALID);
+ });
+ adjust_topline(term, pending_resize);
}
-
-// Refresh all invalidated terminals
-static void on_refresh(Event event)
+// libuv timer callback. This will enqueue on_refresh to be processed as an
+// event.
+static void refresh_timer_cb(TimeWatcher *watcher, void *data)
{
if (exiting) {
// bad things can happen if we redraw when exiting, and there's no need to
// update the buffer.
- return;
+ goto end;
}
Terminal *term;
void *stub; (void)(stub);
// don't process autocommands while updating terminal buffers
block_autocmds();
map_foreach(invalidated_terminals, term, stub, {
- // TODO(SplinterOfChaos): Find the condition that makes term->buf invalid.
- bool valid = true;
- if (!term->buf || !(valid = buf_valid(term->buf))) {
- // destroyed by `close_buffer`. Dont do anything else
- if (!valid) {
- term->buf = NULL;
- }
- continue;
- }
- bool pending_resize = term->pending_resize;
- WITH_BUFFER(term->buf, {
- refresh_size(term);
- refresh_scrollback(term);
- refresh_screen(term);
- redraw_buf_later(term->buf, NOT_VALID);
- });
- adjust_topline(term, pending_resize);
+ refresh_terminal(term);
});
pmap_clear(ptr_t)(invalidated_terminals);
unblock_autocmds();
redraw(true);
+end:
+ refresh_pending = false;
}
static void refresh_size(Terminal *term)
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index da99c6d1c4..c97ffc2ced 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -12,19 +12,19 @@ SCRIPTS := test_eval.out \
test11.out test12.out test13.out test14.out \
test17.out \
test24.out \
- test26.out test27.out test30.out \
+ test30.out \
test32.out test34.out \
test36.out test37.out test39.out test40.out \
- test42.out test43.out test45.out \
- test46.out test47.out test48.out test49.out \
+ test42.out test45.out \
+ test47.out test48.out test49.out \
test52.out test53.out test55.out \
- test57.out test58.out test59.out \
- test62.out test63.out test64.out \
+ test58.out test59.out \
+ test64.out \
test68.out test69.out \
- test71.out test73.out \
- test79.out test80.out \
+ test73.out \
+ test79.out \
test83.out \
- test86.out test87.out test88.out \
+ test88.out \
test_listlbr.out \
test_breakindent.out \
test_close_count.out \
@@ -144,7 +144,5 @@ test1.out: .gdbinit test1.in
test49.out: test49.vim
-test60.out: test60.vim
-
nolog:
-rm -f test.log
diff --git a/src/nvim/testdir/test57.in b/src/nvim/testdir/test57.in
deleted file mode 100644
index 8d972e4a68..0000000000
--- a/src/nvim/testdir/test57.in
+++ /dev/null
@@ -1,500 +0,0 @@
-Tests for :sort command. vim: set ft=vim :
-
-STARTTEST
-:so small.vim
-:"
-:/^t01:/+1,/^t02/-1sort
-:/^t02:/+1,/^t03/-1sort n
-:/^t03:/+1,/^t04/-1sort x
-:/^t04:/+1,/^t05/-1sort u
-:/^t05:/+1,/^t06/-1sort!
-:/^t06:/+1,/^t07/-1sort! n
-:/^t07:/+1,/^t08/-1sort! u
-:/^t08:/+1,/^t09/-1sort o
-:/^t09:/+1,/^t10/-1sort! x
-:/^t10:/+1,/^t11/-1sort/./
-:/^t11:/+1,/^t12/-1sort/../
-:/^t12:/+1,/^t13/-1sort/../u
-:/^t13:/+1,/^t14/-1sort/./n
-:/^t14:/+1,/^t15/-1sort/./r
-:/^t15:/+1,/^t16/-1sort/../r
-:/^t16:/+1,/^t17/-1sort/./rn
-:/^t17:/+1,/^t18/-1sort/\d/
-:/^t18:/+1,/^t19/-1sort/\d/r
-:/^t19:/+1,/^t20/-1sort/\d/n
-:/^t20:/+1,/^t21/-1sort/\d/rn
-:/^t21:/+1,/^t22/-1sort/\d\d/
-:/^t22:/+1,/^t23/-1sort/\d\d/n
-:/^t23:/+1,/^t24/-1sort/\d\d/x
-:/^t24:/+1,/^t25/-1sort/\d\d/r
-:/^t25:/+1,/^t26/-1sort/\d\d/rn
-:/^t26:/+1,/^t27/-1sort/\d\d/rx
-:/^t27:/+1,/^t28/-1sort no
-:/^t01:/,$wq! test.out
-ENDTEST
-
-t01: alphebetical
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t02: numeric
-abc
-ab
-a321
-a123
-a122
-a
-x-22
-b321
-b123
-
-c123d
--24
- 123b
-c321d
-0
-b322b
-b321
-b321b
-
-
-t03: hexadecimal
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t04: alpha, unique
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t05: alpha, reverse
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t06: numeric, reverse
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t07: unique, reverse
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t08: octal
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t09: reverse, hexadecimal
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t10: alpha, skip first character
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t11: alpha, skip first 2 characters
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t12: alpha, unique, skip first 2 characters
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t13: numeric, skip first character
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t14: alpha, sort on first character
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t15: alpha, sort on first 2 characters
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t16: numeric, sort on first character
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t17: alpha, skip past first digit
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t18: alpha, sort on first digit
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t19: numeric, skip past first digit
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t20: numeric, sort on first digit
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t21: alpha, skip past first 2 digits
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t22: numeric, skip past first 2 digits
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t23: hexadecimal, skip past first 2 digits
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t24: alpha, sort on first 2 digits
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t25: numeric, sort on first 2 digits
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t26: hexadecimal, sort on first 2 digits
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t27: wrong arguments
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t28: done
-
diff --git a/src/nvim/testdir/test57.ok b/src/nvim/testdir/test57.ok
deleted file mode 100644
index aa3d373183..0000000000
--- a/src/nvim/testdir/test57.ok
+++ /dev/null
@@ -1,459 +0,0 @@
-t01: alphebetical
-
-
- 123b
-a
-a122
-a123
-a321
-ab
-abc
-b123
-b321
-b321
-b321b
-b322b
-c123d
-c321d
-t02: numeric
-abc
-ab
-a
-
-
-
--24
-x-22
-0
-a122
-a123
-b123
-c123d
- 123b
-a321
-b321
-c321d
-b321
-b321b
-b322b
-t03: hexadecimal
-
-
-a
-ab
-abc
- 123b
-a122
-a123
-a321
-b123
-b321
-b321
-b321b
-b322b
-c123d
-c321d
-t04: alpha, unique
-
- 123b
-a
-a122
-a123
-a321
-ab
-abc
-b123
-b321
-b321b
-b322b
-c123d
-c321d
-t05: alpha, reverse
-c321d
-c123d
-b322b
-b321b
-b321
-b321
-b123
-abc
-ab
-a321
-a123
-a122
-a
- 123b
-
-
-t06: numeric, reverse
-b322b
-b321b
-b321
-c321d
-b321
-a321
- 123b
-c123d
-b123
-a123
-a122
-
-
-a
-ab
-abc
-t07: unique, reverse
-c321d
-c123d
-b322b
-b321b
-b321
-b123
-abc
-ab
-a321
-a123
-a122
-a
- 123b
-
-t08: octal
-abc
-ab
-a
-
-
-a122
-a123
-b123
-c123d
- 123b
-a321
-b321
-c321d
-b321
-b321b
-b322b
-t09: reverse, hexadecimal
-c321d
-c123d
-b322b
-b321b
-b321
-b321
-b123
-a321
-a123
-a122
- 123b
-abc
-ab
-a
-
-
-t10: alpha, skip first character
-a
-
-
-a122
-a123
-b123
- 123b
-c123d
-a321
-b321
-b321
-b321b
-c321d
-b322b
-ab
-abc
-t11: alpha, skip first 2 characters
-ab
-a
-
-
-a321
-b321
-b321
-b321b
-c321d
-a122
-b322b
-a123
-b123
- 123b
-c123d
-abc
-t12: alpha, unique, skip first 2 characters
-ab
-a
-
-a321
-b321
-b321b
-c321d
-a122
-b322b
-a123
-b123
- 123b
-c123d
-abc
-t13: numeric, skip first character
-abc
-ab
-a
-
-
-a122
-a123
-b123
-c123d
- 123b
-a321
-b321
-c321d
-b321
-b321b
-b322b
-t14: alpha, sort on first character
-
-
- 123b
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-b322b
-b321
-b321b
-c123d
-c321d
-t15: alpha, sort on first 2 characters
-a
-
-
- 123b
-a123
-a122
-a321
-abc
-ab
-b123
-b321
-b322b
-b321
-b321b
-c123d
-c321d
-t16: numeric, sort on first character
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t17: alpha, skip past first digit
-abc
-ab
-a
-
-
-a321
-b321
-b321
-b321b
-c321d
-a122
-b322b
-a123
-b123
- 123b
-c123d
-t18: alpha, sort on first digit
-abc
-ab
-a
-
-
-a123
-a122
-b123
-c123d
- 123b
-a321
-b321
-c321d
-b322b
-b321
-b321b
-t19: numeric, skip past first digit
-abc
-ab
-a
-
-
-a321
-b321
-c321d
-b321
-b321b
-a122
-b322b
-a123
-b123
-c123d
- 123b
-t20: numeric, sort on first digit
-abc
-ab
-a
-
-
-a123
-a122
-b123
-c123d
- 123b
-a321
-b321
-c321d
-b322b
-b321
-b321b
-t21: alpha, skip past first 2 digits
-abc
-ab
-a
-
-
-a321
-b321
-b321
-b321b
-c321d
-a122
-b322b
-a123
-b123
- 123b
-c123d
-t22: numeric, skip past first 2 digits
-abc
-ab
-a
-
-
-a321
-b321
-c321d
-b321
-b321b
-a122
-b322b
-a123
-b123
-c123d
- 123b
-t23: hexadecimal, skip past first 2 digits
-abc
-ab
-a
-
-
-a321
-b321
-b321
-a122
-a123
-b123
-b321b
-c321d
-b322b
- 123b
-c123d
-t24: alpha, sort on first 2 digits
-abc
-ab
-a
-
-
-a123
-a122
-b123
-c123d
- 123b
-a321
-b321
-c321d
-b322b
-b321
-b321b
-t25: numeric, sort on first 2 digits
-abc
-ab
-a
-
-
-a123
-a122
-b123
-c123d
- 123b
-a321
-b321
-c321d
-b322b
-b321
-b321b
-t26: hexadecimal, sort on first 2 digits
-abc
-ab
-a
-
-
-a123
-a122
-b123
-c123d
- 123b
-a321
-b321
-c321d
-b322b
-b321
-b321b
-t27: wrong arguments
-abc
-ab
-a
-a321
-a123
-a122
-b321
-b123
-c123d
- 123b
-c321d
-b322b
-b321
-b321b
-
-
-t28: done
-
diff --git a/src/nvim/testdir/test62.in b/src/nvim/testdir/test62.in
deleted file mode 100644
index c201fe7137..0000000000
--- a/src/nvim/testdir/test62.in
+++ /dev/null
@@ -1,191 +0,0 @@
-Tests for tab pages
-
-STARTTEST
-:so small.vim
-:lang C
-:" Simple test for opening and closing a tab page
-:tabnew
-:let nr = tabpagenr()
-:q
-:call append(line('$'), 'tab page ' . nr)
-:unlet nr
-:"
-:" Open three tab pages and use ":tabdo"
-:0tabnew
-:1tabnew
-:$tabnew
-:tabdo call append(line('$'), 'this is tab page ' . tabpagenr())
-:tabclose! 2
-:tabrewind
-:let line1 = getline('$')
-:undo
-:q
-:tablast
-:let line2 = getline('$')
-:q!
-:call append(line('$'), line1)
-:call append(line('$'), line2)
-:unlet line1 line2
-:"
-:" Test for settabvar() and gettabvar() functions. Open a new tab page and
-:" set 3 variables to a number, string and a list. Verify that the variables
-:" are correctly set.
-:tabnew
-:tabfirst
-:call settabvar(2, 'val_num', 100)
-:call settabvar(2, 'val_str', 'SetTabVar test')
-:call settabvar(2, 'val_list', ['red', 'blue', 'green'])
-:"
-:let test_status = 'gettabvar: fail'
-:if gettabvar(2, 'val_num') == 100 && gettabvar(2, 'val_str') == 'SetTabVar test' && gettabvar(2, 'val_list') == ['red', 'blue', 'green']
-: let test_status = 'gettabvar: pass'
-:endif
-:call append(line('$'), test_status)
-:"
-:tabnext 2
-:let test_status = 'settabvar: fail'
-:if t:val_num == 100 && t:val_str == 'SetTabVar test' && t:val_list == ['red', 'blue', 'green']
-: let test_status = 'settabvar: pass'
-:endif
-:tabclose
-:call append(line('$'), test_status)
-:"
-:if has('gui') || has('clientserver')
-:" Test for ":tab drop exist-file" to keep current window.
-:sp test1
-:tab drop test1
-:let test_status = 'tab drop 1: fail'
-:if tabpagenr('$') == 1 && winnr('$') == 2 && winnr() == 1
-: let test_status = 'tab drop 1: pass'
-:endif
-:close
-:call append(line('$'), test_status)
-:"
-:"
-:" Test for ":tab drop new-file" to keep current window of tabpage 1.
-:split
-:tab drop newfile
-:let test_status = 'tab drop 2: fail'
-:if tabpagenr('$') == 2 && tabpagewinnr(1, '$') == 2 && tabpagewinnr(1) == 1
-: let test_status = 'tab drop 2: pass'
-:endif
-:tabclose
-:q
-:call append(line('$'), test_status)
-:"
-:"
-:" Test for ":tab drop multi-opend-file" to keep current tabpage and window.
-:new test1
-:tabnew
-:new test1
-:tab drop test1
-:let test_status = 'tab drop 3: fail'
-:if tabpagenr() == 2 && tabpagewinnr(2, '$') == 2 && tabpagewinnr(2) == 1
-: let test_status = 'tab drop 3: pass'
-:endif
-:tabclose
-:q
-:call append(line('$'), test_status)
-:else
-:" :drop not supported
-:call append(line('$'), 'tab drop 1: pass')
-:call append(line('$'), 'tab drop 2: pass')
-:call append(line('$'), 'tab drop 3: pass')
-:endif
-:"
-:"
-:for i in range(9) | tabnew | endfor
-1gt
-Go=tabpagenr() 
-:tabmove 5
-i=tabpagenr() 
-:tabmove -2
-i=tabpagenr() 
-:tabmove +4
-i=tabpagenr() 
-:tabmove
-i=tabpagenr() 
-:tabmove -20
-i=tabpagenr() 
-:tabmove +20
-i=tabpagenr() 
-:3tabmove
-i=tabpagenr() 
-:7tabmove 5
-i=tabpagenr() 
-:let a='No error caught.'
-:try
-:tabmove foo
-:catch E474
-:let a='E474 caught.'
-:endtry
-i=a 
-:"
-:" Test autocommands
-:tabonly!
-:let g:r=[]
-:command -nargs=1 -bar C :call add(g:r, '=== ' . <q-args> . ' ===')|<args>
-:function Test()
- let hasau=has('autocmd')
- if hasau
- autocmd TabEnter * :call add(g:r, 'TabEnter')
- autocmd WinEnter * :call add(g:r, 'WinEnter')
- autocmd BufEnter * :call add(g:r, 'BufEnter')
- autocmd TabLeave * :call add(g:r, 'TabLeave')
- autocmd WinLeave * :call add(g:r, 'WinLeave')
- autocmd BufLeave * :call add(g:r, 'BufLeave')
- endif
- let t:a='a'
- C tab split
- if !hasau
- let g:r+=['WinLeave', 'TabLeave', 'WinEnter', 'TabEnter']
- endif
- let t:a='b'
- C tabnew
- if !hasau
- let g:r+=['WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', 'BufLeave', 'BufEnter']
- endif
- let t:a='c'
- call add(g:r, join(map(range(1, tabpagenr('$')), 'gettabvar(v:val, "a")')))
- C call map(range(1, tabpagenr('$')), 'settabvar(v:val, ''a'', v:val*2)')
- call add(g:r, join(map(range(1, tabpagenr('$')), 'gettabvar(v:val, "a")')))
- let w:a='a'
- C vsplit
- if !hasau
- let g:r+=['WinLeave', 'WinEnter']
- endif
- let w:a='a'
- let tabn=tabpagenr()
- let winr=range(1, winnr('$'))
- C tabnext 1
- if !hasau
- let g:r+=['BufLeave', 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', 'BufEnter']
- endif
- call add(g:r, join(map(copy(winr), 'gettabwinvar('.tabn.', v:val, "a")')))
- C call map(copy(winr), 'settabwinvar('.tabn.', v:val, ''a'', v:val*2)')
- call add(g:r, join(map(copy(winr), 'gettabwinvar('.tabn.', v:val, "a")')))
- if hasau
- augroup TabDestructive
- autocmd TabEnter * :C tabnext 2 | C tabclose 3
- augroup END
- C tabnext 3
- let g:r+=[tabpagenr().'/'.tabpagenr('$')]
- autocmd! TabDestructive TabEnter
- C tabnew
- C tabnext 1
- autocmd TabDestructive TabEnter * nested :C tabnext 2 | C tabclose 3
- C tabnext 3
- let g:r+=[tabpagenr().'/'.tabpagenr('$')]
- else
- let g:r+=["=== tabnext 3 ===","BufLeave","WinLeave","TabLeave","WinEnter","TabEnter","=== tabnext 2 ===","=== tabclose 3 ===","2/2","=== tabnew ===","WinLeave","TabLeave","WinEnter","TabEnter","BufLeave","BufEnter","=== tabnext 1 ===","BufLeave","WinLeave","TabLeave","WinEnter","TabEnter","BufEnter","=== tabnext 3 ===","BufLeave","WinLeave","TabLeave","WinEnter","TabEnter","=== tabnext 2 ===","BufLeave","WinLeave","TabLeave","WinEnter","TabEnter","=== tabnext 2 ===","=== tabclose 3 ===","BufEnter","=== tabclose 3 ===","2/2",]
- endif
-endfunction
-:call Test()
-:$ put =g:r
-:"
-:"
-:/^Results/,$w! test.out
-:qa!
-ENDTEST
-
-Results:
diff --git a/src/nvim/testdir/test62.ok b/src/nvim/testdir/test62.ok
deleted file mode 100644
index e35b2b1c67..0000000000
--- a/src/nvim/testdir/test62.ok
+++ /dev/null
@@ -1,88 +0,0 @@
-Results:
-tab page 2
-this is tab page 3
-this is tab page 1
-this is tab page 4
-gettabvar: pass
-settabvar: pass
-tab drop 1: pass
-tab drop 2: pass
-tab drop 3: pass
-1
-6
-4
-8
-10
-1
-10
-4
-6
-E474 caught.
-=== tab split ===
-WinLeave
-TabLeave
-WinEnter
-TabEnter
-=== tabnew ===
-WinLeave
-TabLeave
-WinEnter
-TabEnter
-BufLeave
-BufEnter
-a b c
-=== call map(range(1, tabpagenr('$')), 'settabvar(v:val, ''a'', v:val*2)') ===
-2 4 6
-=== vsplit ===
-WinLeave
-WinEnter
-=== tabnext 1 ===
-BufLeave
-WinLeave
-TabLeave
-WinEnter
-TabEnter
-BufEnter
-a a
-=== call map(copy(winr), 'settabwinvar('.tabn.', v:val, ''a'', v:val*2)') ===
-2 4
-=== tabnext 3 ===
-BufLeave
-WinLeave
-TabLeave
-WinEnter
-TabEnter
-=== tabnext 2 ===
-=== tabclose 3 ===
-2/2
-=== tabnew ===
-WinLeave
-TabLeave
-WinEnter
-TabEnter
-BufLeave
-BufEnter
-=== tabnext 1 ===
-BufLeave
-WinLeave
-TabLeave
-WinEnter
-TabEnter
-BufEnter
-=== tabnext 3 ===
-BufLeave
-WinLeave
-TabLeave
-WinEnter
-TabEnter
-=== tabnext 2 ===
-BufLeave
-WinLeave
-TabLeave
-WinEnter
-TabEnter
-=== tabnext 2 ===
-=== tabclose 3 ===
-BufEnter
-=== tabclose 3 ===
-2/2
diff --git a/src/nvim/testdir/test79.in b/src/nvim/testdir/test79.in
index 8278bd8000..afbf2083d2 100644
--- a/src/nvim/testdir/test79.in
+++ b/src/nvim/testdir/test79.in
Binary files differ
diff --git a/src/nvim/testdir/test79.ok b/src/nvim/testdir/test79.ok
index e22eee0b71..d4e0ae8819 100644
--- a/src/nvim/testdir/test79.ok
+++ b/src/nvim/testdir/test79.ok
Binary files differ
diff --git a/src/nvim/testdir/test80.in b/src/nvim/testdir/test80.in
deleted file mode 100644
index 406fb6dac7..0000000000
--- a/src/nvim/testdir/test80.in
+++ /dev/null
@@ -1,201 +0,0 @@
-Test for *sub-replace-special* and *sub-replace-expression* on substitue().
-Test for submatch() on substitue().
-Test for *:s%* on :substitute.
-
-STARTTEST
-:so small.vim
-ENDTEST
-
-TEST_1:
-
-STARTTEST
-:set magic
-:set cpo&
-:$put =\"\n\nTEST_1:\"
-:$put =substitute('A', 'A', '&&', '')
-:$put =substitute('B', 'B', '\&', '')
-:$put =substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', '')
-:$put =substitute('D', 'D', 'd', '')
-:$put =substitute('E', 'E', '~', '')
-:$put =substitute('F', 'F', '\~', '')
-:$put =substitute('G', 'G', '\ugg', '')
-:$put =substitute('H', 'H', '\Uh\Eh', '')
-:$put =substitute('I', 'I', '\lII', '')
-:$put =substitute('J', 'J', '\LJ\EJ', '')
-:$put =substitute('K', 'K', '\Uk\ek', '')
-:$put =substitute('lLl', 'L', ' ', '')
-:$put =substitute('mMm', 'M', '\r', '')
-:$put =substitute('nNn', 'N', '\ ', '')
-:$put =substitute('oOo', 'O', '\n', '')
-:$put =substitute('pPp', 'P', '\b', '')
-:$put =substitute('qQq', 'Q', '\t', '')
-:$put =substitute('rRr', 'R', '\\', '')
-:$put =substitute('sSs', 'S', '\c', '')
-:$put =substitute('uUu', 'U', \"\n\", '')
-:$put =substitute('vVv', 'V', \"\b\", '')
-:$put =substitute('wWw', 'W', \"\\\", '')
-:$put =substitute('xXx', 'X', \"\r\", '')
-:$put =substitute('Y', 'Y', '\L\uyYy\l\EY', '')
-:$put =substitute('Z', 'Z', '\U\lZzZ\u\Ez', '')
-/^TEST_2
-ENDTEST
-
-TEST_2:
-
-STARTTEST
-:set nomagic
-:set cpo&
-:$put =\"\n\nTEST_2:\"
-:$put =substitute('A', 'A', '&&', '')
-:$put =substitute('B', 'B', '\&', '')
-:$put =substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', '')
-:$put =substitute('D', 'D', 'd', '')
-:$put =substitute('E', 'E', '~', '')
-:$put =substitute('F', 'F', '\~', '')
-:$put =substitute('G', 'G', '\ugg', '')
-:$put =substitute('H', 'H', '\Uh\Eh', '')
-:$put =substitute('I', 'I', '\lII', '')
-:$put =substitute('J', 'J', '\LJ\EJ', '')
-:$put =substitute('K', 'K', '\Uk\ek', '')
-:$put =substitute('lLl', 'L', ' ', '')
-:$put =substitute('mMm', 'M', '\r', '')
-:$put =substitute('nNn', 'N', '\ ', '')
-:$put =substitute('oOo', 'O', '\n', '')
-:$put =substitute('pPp', 'P', '\b', '')
-:$put =substitute('qQq', 'Q', '\t', '')
-:$put =substitute('rRr', 'R', '\\', '')
-:$put =substitute('sSs', 'S', '\c', '')
-:$put =substitute('tTt', 'T', \"\r\", '')
-:$put =substitute('uUu', 'U', \"\n\", '')
-:$put =substitute('vVv', 'V', \"\b\", '')
-:$put =substitute('wWw', 'W', \"\\\", '')
-:$put =substitute('X', 'X', '\L\uxXx\l\EX', '')
-:$put =substitute('Y', 'Y', '\U\lYyY\u\Ey', '')
-/^TEST_3
-ENDTEST
-
-TEST_3:
-
-STARTTEST
-:set magic&
-:set cpo&
-:$put =\"\n\nTEST_3:\"
-:let y = substitute('aAa', 'A', '\="\\"', '') | $put =y
-:let y = substitute('bBb', 'B', '\="\\\\"', '') | $put =y
-:let y = substitute('cCc', 'C', '\=" "', '') | $put =y
-:let y = substitute('dDd', 'D', '\="\\ "', '') | $put =y
-:let y = substitute('eEe', 'E', '\="\\\\ "', '') | $put =y
-:let y = substitute('fFf', 'F', '\="\\r"', '') | $put =y
-:let y = substitute('jJj', 'J', '\="\\n"', '') | $put =y
-:let y = substitute('kKk', 'K', '\="\r"', '') | $put =y
-:let y = substitute('lLl', 'L', '\="\n"', '') | $put =y
-/^TEST_4
-ENDTEST
-
-TEST_4:
-
-STARTTEST
-:set magic&
-:set cpo&
-:$put =\"\n\nTEST_4:\"
-:let y = substitute('aAa', 'A', '\=substitute(submatch(0), ".", "\\", "")', '') | $put =y
-:let y = substitute('bBb', 'B', '\=substitute(submatch(0), ".", "\\\\", "")', '') | $put =y
-:let y = substitute('cCc', 'C', '\=substitute(submatch(0), ".", " ", "")', '') | $put =y
-:let y = substitute('dDd', 'D', '\=substitute(submatch(0), ".", "\\ ", "")', '') | $put =y
-:let y = substitute('eEe', 'E', '\=substitute(submatch(0), ".", "\\\\ ", "")', '') | $put =y
-:let y = substitute('fFf', 'F', '\=substitute(submatch(0), ".", "\\r", "")', '') | $put =y
-:let y = substitute('jJj', 'J', '\=substitute(submatch(0), ".", "\\n", "")', '') | $put =y
-:let y = substitute('kKk', 'K', '\=substitute(submatch(0), ".", "\r", "")', '') | $put =y
-:let y = substitute('lLl', 'L', '\=substitute(submatch(0), ".", "\n", "")', '') | $put =y
-/^TEST_5
-ENDTEST
-
-TEST_5:
-
-STARTTEST
-:set magic&
-:set cpo&
-:$put =\"\n\nTEST_5:\"
-:$put =substitute('A123456789', 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\=submatch(0) . submatch(9) . submatch(8) . submatch(7) . submatch(6) . submatch(5) . submatch(4) . submatch(3) . submatch(2) . submatch(1)', '')
-:$put =substitute('A123456789', 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\=string([submatch(0, 1), submatch(9, 1), submatch(8, 1), submatch(7, 1), submatch(6, 1), submatch(5, 1), submatch(4, 1), submatch(3, 1), submatch(2, 1), submatch(1, 1)])', '')
-/^TEST_6
-ENDTEST
-
-TEST_6:
-
-STARTTEST
-:set magic&
-:$put =\"\n\nTEST_6:\"
-:set cpo+=/
-:$put =substitute('A', 'A', 'a', '')
-:$put =substitute('B', 'B', '%', '')
-:set cpo-=/
-:$put =substitute('C', 'C', 'c', '')
-:$put =substitute('D', 'D', '%', '')
-/^TEST_7
-ENDTEST
-
-TEST_7:
-
-STARTTEST
-:set magic&
-:set cpo&
-:$put =\"\n\nTEST_7:\"
-:$put =substitute('A A', 'A.', '\=submatch(0)', '')
-:$put =substitute(\"B\nB\", 'B.', '\=submatch(0)', '')
-:$put =substitute(\"B\nB\", 'B.', '\=string(submatch(0, 1))', '')
-:$put =substitute('-bb', '\zeb', 'a', 'g')
-:$put =substitute('-bb', '\ze', 'c', 'g')
-/^TEST_8
-ENDTEST
-
-TEST_8:
-
-STARTTEST
-:set magic&
-:set cpo&
-:$put =\"\n\nTEST_8:\"
-:$put =',,X'
-:s/\(^\|,\)\ze\(,\|X\)/\1N/g
-:$put =',,Y'
-:s/\(^\|,\)\ze\(,\|Y\)/\1N/gc
-a:$put =',,Z'
-:s/\(^\|,\)\ze\(,\|Z\)/\1N/gc
-yy/^TEST_9:
-ENDTEST
-
-TEST_9:
-
-STARTTEST
-:set magic&
-:set cpo&
-:$put =\"\n\nTEST_9:\"
-:$put ='xxx'
-:s/x/X/gc
-yyq/^TEST_10:
-ENDTEST
-
-TEST_10:
-
-STARTTEST
-:set magic&
-:set cpo&
-:$put =\"\n\nTEST_10:\"
-:let y = substitute('123', '\zs', 'a', 'g') | $put =y
-:let y = substitute('123', '\zs.', 'a', 'g') | $put =y
-:let y = substitute('123', '.\zs', 'a', 'g') | $put =y
-:let y = substitute('123', '\ze', 'a', 'g') | $put =y
-:let y = substitute('123', '\ze.', 'a', 'g') | $put =y
-:let y = substitute('123', '.\ze', 'a', 'g') | $put =y
-:let y = substitute('123', '1\|\ze', 'a', 'g') | $put =y
-:let y = substitute('123', '1\zs\|[23]', 'a', 'g') | $put =y
-/^TEST_11
-ENDTEST
-
-TEST_11:
-
-STARTTEST
-:/^Results/,$wq! test.out
-ENDTEST
-
-Results of test72:
diff --git a/src/nvim/testdir/test80.ok b/src/nvim/testdir/test80.ok
deleted file mode 100644
index b42f604a07..0000000000
--- a/src/nvim/testdir/test80.ok
+++ /dev/null
@@ -1,131 +0,0 @@
-Results of test72:
-
-
-TEST_1:
-AA
-&
-C123456789987654321
-d
-~
-~
-Gg
-Hh
-iI
-jJ
-Kk
-l l
-m m
-n n
-o
-o
-pp
-q q
-r\r
-scs
-u
-u
-vv
-w\w
-x x
-YyyY
-zZZz
-
-
-TEST_2:
-AA
-&
-C123456789987654321
-d
-~
-~
-Gg
-Hh
-iI
-jJ
-Kk
-l l
-m m
-n n
-o
-o
-pp
-q q
-r\r
-scs
-t t
-u
-u
-vv
-w\w
-XxxX
-yYYy
-
-
-TEST_3:
-a\a
-b\\b
-c c
-d\ d
-e\\ e
-f\rf
-j\nj
-k k
-l
-l
-
-
-TEST_4:
-a\a
-b\b
-c c
-d d
-e\ e
-f f
-j
-j
-k k
-l
-l
-
-
-TEST_5:
-A123456789987654321
-[['A123456789'], ['9'], ['8'], ['7'], ['6'], ['5'], ['4'], ['3'], ['2'], ['1']]
-
-
-TEST_6:
-a
-%
-c
-%
-
-
-TEST_7:
-A A
-B
-B
-['B
-']B
--abab
-c-cbcbc
-
-
-TEST_8:
-N,,NX
-N,,NY
-N,,NZ
-
-
-TEST_9:
-XXx
-
-
-TEST_10:
-a1a2a3a
-aaa
-1a2a3a
-a1a2a3a
-a1a2a3
-aaa
-aa2a3a
-1aaa
diff --git a/src/nvim/testdir/test86.in b/src/nvim/testdir/test86.in
deleted file mode 100644
index 41d9a2fa32..0000000000
--- a/src/nvim/testdir/test86.in
+++ /dev/null
@@ -1,1425 +0,0 @@
-Tests for various python features. vim: set ft=vim :
-
-This test is not run in Neovim(see the has('nvim') check below) because the
-python compatibility layer is not complete.
-
-NOTE: This will cause errors when run under valgrind.
-This would require recompiling Python with:
- ./configure --without-pymalloc
-See http://svn.python.org/view/python/trunk/Misc/README.valgrind?view=markup
-
-STARTTEST
-:so small.vim
-:set encoding=latin1
-:set noswapfile
-:if !has('python') || has('nvim') | e! test.ok | wq! test.out | endif
-:lang C
-:fun Test()
-:py import vim
-:let l = []
-:py l=vim.bindeval('l')
-:py f=vim.bindeval('function("strlen")')
-:" Extending List directly with different types
-:py l.extend([1, "as'd", [1, 2, f, {'a': 1}]])
-:$put =string(l)
-:$put =string(l[-1])
-:try
-: $put =string(l[-4])
-:catch
-: $put =v:exception[:13]
-:endtry
-:" List assignment
-:py l[0]=0
-:$put =string(l)
-:py l[-2]=f
-:$put =string(l)
-:"
-:" Extending Dictionary directly with different types
-:let d = {}
-:fun d.f()
-: return 1
-:endfun
-py << EOF
-d=vim.bindeval('d')
-d['1']='asd'
-d.update(b=[1, 2, f])
-d.update((('-1', {'a': 1}),))
-d.update({'0': -1})
-dk = d.keys()
-dv = d.values()
-di = d.items()
-cmpfun = lambda a, b: cmp(repr(a), repr(b))
-dk.sort(cmpfun)
-dv.sort(cmpfun)
-di.sort(cmpfun)
-EOF
-:$put =pyeval('d[''f''](self={})')
-:$put =pyeval('repr(dk)')
-:$put =substitute(pyeval('repr(dv)'),'0x\x\+','','g')
-:$put =substitute(pyeval('repr(di)'),'0x\x\+','','g')
-:for [key, Val] in sort(items(d))
-: $put =string(key) . ' : ' . string(Val)
-: unlet key Val
-:endfor
-:py del dk
-:py del di
-:py del dv
-:"
-:" removing items with del
-:py del l[2]
-:$put =string(l)
-:let l = range(8)
-:py l=vim.bindeval('l')
-:try
-: py del l[:3]
-: py del l[1:]
-:catch
-: $put =v:exception
-:endtry
-:$put =string(l)
-:"
-:py del d['-1']
-:py del d['f']
-:$put =string(pyeval('d.get(''b'', 1)'))
-:$put =string(pyeval('d.pop(''b'')'))
-:$put =string(pyeval('d.get(''b'', 1)'))
-:$put =string(pyeval('d.pop(''1'', 2)'))
-:$put =string(pyeval('d.pop(''1'', 2)'))
-:$put =pyeval('repr(d.has_key(''0''))')
-:$put =pyeval('repr(d.has_key(''1''))')
-:$put =pyeval('repr(''0'' in d)')
-:$put =pyeval('repr(''1'' in d)')
-:$put =pyeval('repr(list(iter(d)))')
-:$put =string(d)
-:$put =pyeval('repr(d.popitem())')
-:$put =pyeval('repr(d.get(''0''))')
-:$put =pyeval('repr(list(iter(d)))')
-:"
-:" removing items out of range: silently skip items that don't exist
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:" The following two ranges delete nothing as they match empty list:
-:py del l[2:1]
-:$put =string(l)
-:py del l[2:2]
-:$put =string(l)
-:py del l[2:3]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[2:4]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[2:5]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[2:6]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:" The following two ranges delete nothing as they match empty list:
-:py del l[-1:2]
-:$put =string(l)
-:py del l[-2:2]
-:$put =string(l)
-:py del l[-3:2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[-4:2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[-5:2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[-6:2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[::2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[3:0:-2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py del l[2:4:-2]
-:$put =string(l)
-:"
-:" Slice assignment to a list
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py l[0:0]=['a']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py l[1:2]=['b']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py l[2:4]=['c']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py l[4:4]=['d']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py l[-1:2]=['e']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py l[-10:2]=['f']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:py l[2:-10]=['g']
-:$put =string(l)
-:let l = []
-:py l=vim.bindeval('l')
-:py l[0:0]=['h']
-:$put =string(l)
-:let l = range(8)
-:py l=vim.bindeval('l')
-:py l[2:6:2] = [10, 20]
-:$put =string(l)
-:let l = range(8)
-:py l=vim.bindeval('l')
-:py l[6:2:-2] = [10, 20]
-:$put =string(l)
-:let l = range(8)
-:py l=vim.bindeval('l')
-:py l[6:2] = ()
-:$put =string(l)
-:let l = range(8)
-:py l=vim.bindeval('l')
-:py l[6:2:1] = ()
-:$put =string(l)
-:let l = range(8)
-:py l=vim.bindeval('l')
-:py l[2:2:1] = ()
-:$put =string(l)
-:"
-:" Locked variables
-:let l = [0, 1, 2, 3]
-:py l=vim.bindeval('l')
-:lockvar! l
-:py l[2]='i'
-:$put =string(l)
-:unlockvar! l
-:"
-:" Function calls
-py << EOF
-import sys
-def ee(expr, g=globals(), l=locals()):
- try:
- exec(expr, g, l)
- except:
- ei = sys.exc_info()
- msg = sys.exc_info()[0].__name__ + ':' + repr(sys.exc_info()[1].args)
- msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'')
- if expr.find('None') > -1:
- msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
- 'TypeError:("\'NoneType\' object is not iterable",)')
- if expr.find('FailingNumber') > -1:
- msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'')
- msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
- 'TypeError:("\'FailingNumber\' object is not iterable",)')
- if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1:
- msg = msg.replace('(\'', '("').replace('\',)', '",)')
- if expr == 'fd(self=[])':
- # HACK: PyMapping_Check changed meaning
- msg = msg.replace('AttributeError:(\'keys\',)',
- 'TypeError:(\'unable to convert list to vim dictionary\',)')
- vim.current.buffer.append(expr + ':' + msg)
- else:
- vim.current.buffer.append(expr + ':NOT FAILED')
-EOF
-:fun New(...)
-: return ['NewStart']+a:000+['NewEnd']
-:endfun
-:fun DictNew(...) dict
-: return ['DictNewStart']+a:000+['DictNewEnd', self]
-:endfun
-:let l=[function('New'), function('DictNew')]
-:py l=vim.bindeval('l')
-:py l.extend(list(l[0](1, 2, 3)))
-:$put =string(l)
-:py l.extend(list(l[1](1, 2, 3, self={'a': 'b'})))
-:$put =string(l)
-:py l.extend([l[0].name])
-:$put =string(l)
-:py ee('l[1](1, 2, 3)')
-:py f=l[0]
-:delfunction New
-:py ee('f(1, 2, 3)')
-:let l=[0.0]
-:py l=vim.bindeval('l')
-:py l.extend([0.0])
-:$put =string(l)
-:let messages=[]
-:delfunction DictNew
-py <<EOF
-d=vim.bindeval('{}')
-m=vim.bindeval('messages')
-def em(expr, g=globals(), l=locals()):
- try:
- exec(expr, g, l)
- except:
- m.extend([sys.exc_type.__name__])
-
-em('d["abc1"]')
-em('d["abc1"]="\\0"')
-em('d["abc1"]=vim')
-em('d[""]=1')
-em('d["a\\0b"]=1')
-em('d[u"a\\0b"]=1')
-
-em('d.pop("abc1")')
-em('d.popitem()')
-del em
-del m
-EOF
-:$put =messages
-:unlet messages
-:" locked and scope attributes
-:let d={} | let dl={} | lockvar dl
-:for s in split("d dl v: g:")
-: let name=tr(s, ':', 's')
-: execute 'py '.name.'=vim.bindeval("'.s.'")'
-: let toput=s.' : '.join(map(['locked', 'scope'], 'v:val.":".pyeval(name.".".v:val)'), ';')
-: $put =toput
-:endfor
-:silent! let d.abc2=1
-:silent! let dl.abc3=1
-:py d.locked=True
-:py dl.locked=False
-:silent! let d.def=1
-:silent! let dl.def=1
-:put ='d:'.string(d)
-:put ='dl:'.string(dl)
-:unlet d dl
-:
-:let l=[] | let ll=[] | lockvar ll
-:for s in split("l ll")
-: let name=tr(s, ':', 's')
-: execute 'py '.name.'=vim.bindeval("'.s.'")'
-: let toput=s.' : locked:'.pyeval(name.'.locked')
-: $put =toput
-:endfor
-:silent! call extend(l, [0])
-:silent! call extend(ll, [0])
-:py l.locked=True
-:py ll.locked=False
-:silent! call extend(l, [1])
-:silent! call extend(ll, [1])
-:put ='l:'.string(l)
-:put ='ll:'.string(ll)
-:unlet l ll
-:"
-:" pyeval()
-:let l=pyeval('range(3)')
-:$put =string(l)
-:let d=pyeval('{"a": "b", "c": 1, "d": ["e"]}')
-:$put =sort(items(d))
-:let f=pyeval('0.0')
-:$put =string(f)
-:" Invalid values:
-:for e in ['"\0"', '{"\0": 1}', 'undefined_name', 'vim']
-: try
-: let v=pyeval(e)
-: catch
-: let toput=e.":\t".v:exception[:13]
-: $put =toput
-: endtry
-:endfor
-:"
-:" threading
-:let l = [0]
-:py l=vim.bindeval('l')
-py <<EOF
-import threading
-import time
-
-class T(threading.Thread):
- def __init__(self):
- threading.Thread.__init__(self)
- self.t = 0
- self.running = True
-
- def run(self):
- while self.running:
- self.t += 1
- time.sleep(0.1)
-
-t = T()
-del T
-t.start()
-EOF
-:sleep 1
-:py t.running = False
-:py t.join()
-:py l[0] = t.t > 8 # check if the background thread is working
-:py del time
-:py del threading
-:py del t
-:$put =string(l)
-:"
-:" settrace
-:let l = []
-:py l=vim.bindeval('l')
-py <<EOF
-import sys
-
-def traceit(frame, event, arg):
- global l
- if event == "line":
- l.extend([frame.f_lineno])
- return traceit
-
-def trace_main():
- for i in range(5):
- pass
-EOF
-:py sys.settrace(traceit)
-:py trace_main()
-:py sys.settrace(None)
-:py del traceit
-:py del trace_main
-:$put =string(l)
-:"
-:" Slice
-:py ll = vim.bindeval('[0, 1, 2, 3, 4, 5]')
-:py l = ll[:4]
-:$put =string(pyeval('l'))
-:py l = ll[2:]
-:$put =string(pyeval('l'))
-:py l = ll[:-4]
-:$put =string(pyeval('l'))
-:py l = ll[-2:]
-:$put =string(pyeval('l'))
-:py l = ll[2:4]
-:$put =string(pyeval('l'))
-:py l = ll[4:2]
-:$put =string(pyeval('l'))
-:py l = ll[-4:-2]
-:$put =string(pyeval('l'))
-:py l = ll[-2:-4]
-:$put =string(pyeval('l'))
-:py l = ll[:]
-:$put =string(pyeval('l'))
-:py l = ll[0:6]
-:$put =string(pyeval('l'))
-:py l = ll[-10:10]
-:$put =string(pyeval('l'))
-:py l = ll[4:2:-1]
-:$put =string(pyeval('l'))
-:py l = ll[::2]
-:$put =string(pyeval('l'))
-:py l = ll[4:2:1]
-:$put =string(pyeval('l'))
-:py del l
-:"
-:" Vars
-:let g:foo = 'bac'
-:let w:abc3 = 'def'
-:let b:baz = 'bar'
-:let t:bar = 'jkl'
-:try
-: throw "Abc"
-:catch
-: put =pyeval('vim.vvars[''exception'']')
-:endtry
-:put =pyeval('vim.vars[''foo'']')
-:put =pyeval('vim.current.window.vars[''abc3'']')
-:put =pyeval('vim.current.buffer.vars[''baz'']')
-:put =pyeval('vim.current.tabpage.vars[''bar'']')
-:"
-:" Options
-:" paste: boolean, global
-:" previewheight number, global
-:" operatorfunc: string, global
-:" number: boolean, window-local
-:" numberwidth: number, window-local
-:" colorcolumn: string, window-local
-:" statusline: string, window-local/global
-:" autoindent: boolean, buffer-local
-:" shiftwidth: number, buffer-local
-:" omnifunc: string, buffer-local
-:" preserveindent: boolean, buffer-local/global
-:" path: string, buffer-local/global
-:let g:bufs=[bufnr('%')]
-:new
-:let g:bufs+=[bufnr('%')]
-:vnew
-:let g:bufs+=[bufnr('%')]
-:wincmd j
-:vnew
-:let g:bufs+=[bufnr('%')]
-:wincmd l
-:fun RecVars(opt)
-: let gval =string(eval('&g:'.a:opt))
-: let wvals=join(map(range(1, 4), 'v:val.":".string(getwinvar(v:val, "&".a:opt))'))
-: let bvals=join(map(copy(g:bufs), 'v:val.":".string(getbufvar(v:val, "&".a:opt))'))
-: put =' G: '.gval
-: put =' W: '.wvals
-: put =' B: '.wvals
-:endfun
-py << EOF
-def e(s, g=globals(), l=locals()):
- try:
- exec(s, g, l)
- except:
- vim.command('return ' + repr(sys.exc_type.__name__))
-
-def ev(s, g=globals(), l=locals()):
- try:
- return eval(s, g, l)
- except:
- vim.command('let exc=' + repr(sys.exc_type.__name__))
- return 0
-EOF
-:fun E(s)
-: python e(vim.eval('a:s'))
-:endfun
-:fun Ev(s)
-: let r=pyeval('ev(vim.eval("a:s"))')
-: if exists('exc')
-: throw exc
-: endif
-: return r
-:endfun
-:py gopts1=vim.options
-:py wopts1=vim.windows[2].options
-:py wopts2=vim.windows[0].options
-:py wopts3=vim.windows[1].options
-:py bopts1=vim.buffers[vim.bindeval("g:bufs")[2]].options
-:py bopts2=vim.buffers[vim.bindeval("g:bufs")[1]].options
-:py bopts3=vim.buffers[vim.bindeval("g:bufs")[0]].options
-:$put ='wopts iters equal: '.pyeval('list(wopts1) == list(wopts2)')
-:$put ='bopts iters equal: '.pyeval('list(bopts1) == list(bopts2)')
-:py gset=set(iter(gopts1))
-:py wset=set(iter(wopts1))
-:py bset=set(iter(bopts1))
-:set path=.,..,,
-:let lst=[]
-:let lst+=[['paste', 1, 0, 1, 2, 1, 1, 0 ]]
-:let lst+=[['previewheight', 5, 1, 6, 'a', 0, 1, 0 ]]
-:let lst+=[['operatorfunc', 'A', 'B', 'C', 2, 0, 1, 0 ]]
-:let lst+=[['number', 0, 1, 1, 0, 1, 0, 1 ]]
-:let lst+=[['numberwidth', 2, 3, 5, -100, 0, 0, 1 ]]
-:let lst+=[['colorcolumn', '+1', '+2', '+3', 'abc4', 0, 0, 1 ]]
-:let lst+=[['statusline', '1', '2', '4', 0, 0, 1, 1 ]]
-:let lst+=[['autoindent', 0, 1, 1, 2, 1, 0, 2 ]]
-:let lst+=[['shiftwidth', 0, 2, 1, 3, 0, 0, 2 ]]
-:let lst+=[['omnifunc', 'A', 'B', 'C', 1, 0, 0, 2 ]]
-:let lst+=[['preserveindent', 0, 1, 1, 2, 1, 1, 2 ]]
-:let lst+=[['path', '.,,', ',,', '.', 0, 0, 1, 2 ]]
-:for [oname, oval1, oval2, oval3, invval, bool, global, local] in lst
-: py oname=vim.eval('oname')
-: py oval1=vim.bindeval('oval1')
-: py oval2=vim.bindeval('oval2')
-: py oval3=vim.bindeval('oval3')
-: if invval is 0 || invval is 1
-: py invval=bool(vim.bindeval('invval'))
-: else
-: py invval=vim.bindeval('invval')
-: endif
-: if bool
-: py oval1=bool(oval1)
-: py oval2=bool(oval2)
-: py oval3=bool(oval3)
-: endif
-: put ='>>> '.oname
-: $put =' g/w/b:'.pyeval('oname in gset').'/'.pyeval('oname in wset').'/'.pyeval('oname in bset')
-: $put =' g/w/b (in):'.pyeval('oname in gopts1').'/'.pyeval('oname in wopts1').'/'.pyeval('oname in bopts1')
-: for v in ['gopts1', 'wopts1', 'bopts1']
-: try
-: put =' p/'.v.': '.Ev('repr('.v.'['''.oname.'''])')
-: catch
-: put =' p/'.v.'! '.v:exception
-: endtry
-: let r=E(v.'['''.oname.''']=invval')
-: if r isnot 0
-: put =' inv: '.string(invval).'! '.r
-: endif
-: for vv in (v is# 'gopts1' ? [v] : [v, v[:-2].'2', v[:-2].'3'])
-: let val=substitute(vv, '^.opts', 'oval', '')
-: let r=E(vv.'['''.oname.''']='.val)
-: if r isnot 0
-: put =' '.vv.'! '.r
-: endif
-: endfor
-: endfor
-: call RecVars(oname)
-: for v in ['wopts3', 'bopts3']
-: let r=E('del '.v.'["'.oname.'"]')
-: if r isnot 0
-: put =' del '.v.'! '.r
-: endif
-: endfor
-: call RecVars(oname)
-:endfor
-:delfunction RecVars
-:delfunction E
-:delfunction Ev
-:py del ev
-:py del e
-:only
-:for buf in g:bufs[1:]
-: execute 'bwipeout!' buf
-:endfor
-:py del gopts1
-:py del wopts1
-:py del wopts2
-:py del wopts3
-:py del bopts1
-:py del bopts2
-:py del bopts3
-:py del oval1
-:py del oval2
-:py del oval3
-:py del oname
-:py del invval
-:"
-:" Test buffer object
-:vnew
-:put ='First line'
-:put ='Second line'
-:put ='Third line'
-:1 delete _
-:py b=vim.current.buffer
-:wincmd w
-:mark a
-:augroup BUFS
-: autocmd BufFilePost * python cb.append(vim.eval('expand("<abuf>")') + ':BufFilePost:' + vim.eval('bufnr("%")'))
-: autocmd BufFilePre * python cb.append(vim.eval('expand("<abuf>")') + ':BufFilePre:' + vim.eval('bufnr("%")'))
-:augroup END
-py << EOF
-cb = vim.current.buffer
-# Tests BufferAppend and BufferItem
-cb.append(b[0])
-# Tests BufferSlice and BufferAssSlice
-cb.append('abc5') # Will be overwritten
-cb[-1:] = b[:-2]
-# Test BufferLength and BufferAssSlice
-cb.append('def') # Will not be overwritten
-cb[len(cb):] = b[:]
-# Test BufferAssItem and BufferMark
-cb.append('ghi') # Will be overwritten
-cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1]))
-# Test BufferRepr
-cb.append(repr(cb) + repr(b))
-# Modify foreign buffer
-b.append('foo')
-b[0]='bar'
-b[0:0]=['baz']
-vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number)
-# Test assigning to name property
-import os
-old_name = cb.name
-cb.name = 'foo'
-cb.append(cb.name[-11:].replace(os.path.sep, '/'))
-b.name = 'bar'
-cb.append(b.name[-11:].replace(os.path.sep, '/'))
-cb.name = old_name
-cb.append(cb.name[-17:].replace(os.path.sep, '/'))
-del old_name
-# Test CheckBuffer
-for _b in vim.buffers:
- if _b is not cb:
- vim.command('bwipeout! ' + str(_b.number))
-del _b
-cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid)))
-for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc6")', 'b.name = "!"'):
- try:
- exec(expr)
- except vim.error:
- pass
- else:
- # Usually a SEGV here
- # Should not happen in any case
- cb.append('No exception for ' + expr)
-vim.command('cd .')
-del b
-EOF
-:augroup BUFS
-: autocmd!
-:augroup END
-:augroup! BUFS
-:"
-:" Test vim.buffers object
-:set hidden
-:edit a
-:buffer #
-:edit b
-:buffer #
-:edit c
-:buffer #
-py << EOF
-try:
- from __builtin__ import next
-except ImportError:
- next = lambda o: o.next()
-# Check GCing iterator that was not fully exhausted
-i = iter(vim.buffers)
-cb.append('i:' + str(next(i)))
-# and also check creating more then one iterator at a time
-i2 = iter(vim.buffers)
-cb.append('i2:' + str(next(i2)))
-cb.append('i:' + str(next(i)))
-# The following should trigger GC and not cause any problems
-del i
-del i2
-i3 = iter(vim.buffers)
-cb.append('i3:' + str(next(i3)))
-del i3
-
-prevnum = 0
-for b in vim.buffers:
- # Check buffer order
- if prevnum >= b.number:
- cb.append('!!! Buffer numbers not in strictly ascending order')
- # Check indexing: vim.buffers[number].number == number
- cb.append(str(b.number) + ':' + repr(vim.buffers[b.number]) + '=' + repr(b))
- prevnum = b.number
-del prevnum
-
-cb.append(str(len(vim.buffers)))
-
-bnums = list(map(lambda b: b.number, vim.buffers))[1:]
-
-# Test wiping out buffer with existing iterator
-i4 = iter(vim.buffers)
-cb.append('i4:' + str(next(i4)))
-vim.command('bwipeout! ' + str(bnums.pop(0)))
-try:
- next(i4)
-except vim.error:
- pass
-else:
- cb.append('!!!! No vim.error')
-i4 = iter(vim.buffers)
-vim.command('bwipeout! ' + str(bnums.pop(-1)))
-vim.command('bwipeout! ' + str(bnums.pop(-1)))
-cb.append('i4:' + str(next(i4)))
-try:
- next(i4)
-except StopIteration:
- cb.append('StopIteration')
-del i4
-del bnums
-EOF
-:"
-:" Test vim.{tabpage,window}list and vim.{tabpage,window} objects
-:tabnew 0
-:tabnew 1
-:vnew a.1
-:tabnew 2
-:vnew a.2
-:vnew b.2
-:vnew c.2
-py << EOF
-cb.append('Number of tabs: ' + str(len(vim.tabpages)))
-cb.append('Current tab pages:')
-def W(w):
- if repr(w).find('(unknown)') != -1:
- return '<window object (unknown)>'
- else:
- return repr(w)
-
-start = len(cb)
-
-def Cursor(w):
- if w.buffer is cb:
- return repr((start - w.cursor[0], w.cursor[1]))
- else:
- return repr(w.cursor)
-
-for t in vim.tabpages:
- cb.append(' ' + repr(t) + '(' + str(t.number) + ')' + ': ' + str(len(t.windows)) + ' windows, current is ' + W(t.window))
- cb.append(' Windows:')
- for w in t.windows:
- cb.append(' ' + W(w) + '(' + str(w.number) + ')' + ': displays buffer ' + repr(w.buffer) + '; cursor is at ' + Cursor(w))
- # Other values depend on the size of the terminal, so they are checked partly:
- for attr in ('height', 'row', 'width', 'col'):
- try:
- aval = getattr(w, attr)
- if type(aval) is not long:
- raise TypeError
- if aval < 0:
- raise ValueError
- except Exception:
- cb.append('!!!!!! Error while getting attribute ' + attr + ': ' + sys.exc_type.__name__)
- del aval
- del attr
- w.cursor = (len(w.buffer), 0)
-del W
-del Cursor
-cb.append('Number of windows in current tab page: ' + str(len(vim.windows)))
-if list(vim.windows) != list(vim.current.tabpage.windows):
- cb.append('!!!!!! Windows differ')
-EOF
-:"
-:" Test vim.current
-py << EOF
-def H(o):
- return repr(o)
-cb.append('Current tab page: ' + repr(vim.current.tabpage))
-cb.append('Current window: ' + repr(vim.current.window) + ': ' + H(vim.current.window) + ' is ' + H(vim.current.tabpage.window))
-cb.append('Current buffer: ' + repr(vim.current.buffer) + ': ' + H(vim.current.buffer) + ' is ' + H(vim.current.window.buffer)+ ' is ' + H(vim.current.tabpage.window.buffer))
-del H
-# Assigning: fails
-try:
- vim.current.window = vim.tabpages[0].window
-except ValueError:
- cb.append('ValueError at assigning foreign tab window')
-
-for attr in ('window', 'tabpage', 'buffer'):
- try:
- setattr(vim.current, attr, None)
- except TypeError:
- cb.append('Type error at assigning None to vim.current.' + attr)
-del attr
-
-# Assigning: success
-vim.current.tabpage = vim.tabpages[-2]
-vim.current.buffer = cb
-vim.current.window = vim.windows[0]
-vim.current.window.cursor = (len(vim.current.buffer), 0)
-cb.append('Current tab page: ' + repr(vim.current.tabpage))
-cb.append('Current window: ' + repr(vim.current.window))
-cb.append('Current buffer: ' + repr(vim.current.buffer))
-cb.append('Current line: ' + repr(vim.current.line))
-ws = list(vim.windows)
-ts = list(vim.tabpages)
-for b in vim.buffers:
- if b is not cb:
- vim.command('bwipeout! ' + str(b.number))
-del b
-cb.append('w.valid: ' + repr([w.valid for w in ws]))
-cb.append('t.valid: ' + repr([t.valid for t in ts]))
-del w
-del t
-del ts
-del ws
-EOF
-:tabonly!
-:only!
-:"
-:" Test types
-py << EOF
-for expr, attr in (
- ('vim.vars', 'Dictionary'),
- ('vim.options', 'Options'),
- ('vim.bindeval("{}")', 'Dictionary'),
- ('vim.bindeval("[]")', 'List'),
- ('vim.bindeval("function(\'tr\')")', 'Function'),
- ('vim.current.buffer', 'Buffer'),
- ('vim.current.range', 'Range'),
- ('vim.current.window', 'Window'),
- ('vim.current.tabpage', 'TabPage'),
-):
- cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr)))
-del expr
-del attr
-EOF
-:"
-:" Test __dir__() method
-py << EOF
-for name, o in (
- ('current', vim.current),
- ('buffer', vim.current.buffer),
- ('window', vim.current.window),
- ('tabpage', vim.current.tabpage),
- ('range', vim.current.range),
- ('dictionary', vim.bindeval('{}')),
- ('list', vim.bindeval('[]')),
- ('function', vim.bindeval('function("tr")')),
- ('output', sys.stdout),
- ):
- cb.append(name + ':' + ','.join(dir(o)))
-del name
-del o
-EOF
-:"
-:" Test vim.*.__new__
-:$put =string(pyeval('vim.Dictionary({})'))
-:$put =string(pyeval('vim.Dictionary(a=1)'))
-:$put =string(pyeval('vim.Dictionary(((''a'', 1),))'))
-:$put =string(pyeval('vim.List()'))
-:$put =string(pyeval('vim.List(iter(''abc7''))'))
-:$put =string(pyeval('vim.Function(''tr'')'))
-:"
-:" Test stdout/stderr
-:redir => messages
-:py sys.stdout.write('abc8') ; sys.stdout.write('def')
-:py sys.stderr.write('abc9') ; sys.stderr.write('def')
-:py sys.stdout.writelines(iter('abcA'))
-:py sys.stderr.writelines(iter('abcB'))
-:redir END
-:$put =string(substitute(messages, '\d\+', '', 'g'))
-:" Test subclassing
-:fun Put(...)
-: $put =string(a:000)
-: return a:000
-:endfun
-py << EOF
-class DupDict(vim.Dictionary):
- def __setitem__(self, key, value):
- super(DupDict, self).__setitem__(key, value)
- super(DupDict, self).__setitem__('dup_' + key, value)
-dd = DupDict()
-dd['a'] = 'b'
-
-class DupList(vim.List):
- def __getitem__(self, idx):
- return [super(DupList, self).__getitem__(idx)] * 2
-
-dl = DupList()
-dl2 = DupList(iter('abcC'))
-dl.extend(dl2[0])
-
-class DupFun(vim.Function):
- def __call__(self, arg):
- return super(DupFun, self).__call__(arg, arg)
-
-df = DupFun('Put')
-EOF
-:$put =string(sort(keys(pyeval('dd'))))
-:$put =string(pyeval('dl'))
-:$put =string(pyeval('dl2'))
-:$put =string(pyeval('df(2)'))
-:$put =string(pyeval('dl') is# pyeval('dl'))
-:$put =string(pyeval('dd') is# pyeval('dd'))
-:$put =string(pyeval('df'))
-:delfunction Put
-py << EOF
-del DupDict
-del DupList
-del DupFun
-del dd
-del dl
-del dl2
-del df
-EOF
-:"
-:" Test chdir
-py << EOF
-import os
-fnamemodify = vim.Function('fnamemodify')
-cb.append(fnamemodify('.', ':p:h:t'))
-cb.append(vim.eval('@%'))
-os.chdir('..')
-path = fnamemodify('.', ':p:h:t')
-if path != 'src':
- # Running tests from a shadow directory, so move up another level
- # This will result in @% looking like shadow/testdir/test86.in, hence the
- # extra fnamemodify
- os.chdir('..')
- cb.append(fnamemodify('.', ':p:h:t'))
- cb.append(fnamemodify(vim.eval('@%'), ':s?^%s.??' % path).replace(os.path.sep, '/'))
- os.chdir(path)
- del path
-else:
- cb.append(fnamemodify('.', ':p:h:t'))
- cb.append(vim.eval('@%').replace(os.path.sep, '/'))
-os.chdir('testdir')
-cb.append(fnamemodify('.', ':p:h:t'))
-cb.append(vim.eval('@%'))
-del fnamemodify
-EOF
-:"
-:" Test errors
-:fun F() dict
-:endfun
-:fun D()
-:endfun
-py << EOF
-d = vim.Dictionary()
-ned = vim.Dictionary(foo='bar', baz='abcD')
-dl = vim.Dictionary(a=1)
-dl.locked = True
-l = vim.List()
-ll = vim.List('abcE')
-ll.locked = True
-nel = vim.List('abcO')
-f = vim.Function('string')
-fd = vim.Function('F')
-fdel = vim.Function('D')
-vim.command('delfunction D')
-
-def subexpr_test(expr, name, subexprs):
- cb.append('>>> Testing %s using %s' % (name, expr))
- for subexpr in subexprs:
- ee(expr % subexpr)
- cb.append('<<< Finished')
-
-def stringtochars_test(expr):
- return subexpr_test(expr, 'StringToChars', (
- '1', # Fail type checks
- 'u"\\0"', # Fail PyString_AsStringAndSize(bytes, , NULL) check
- '"\\0"', # Fail PyString_AsStringAndSize(object, , NULL) check
- ))
-
-class Mapping(object):
- def __init__(self, d):
- self.d = d
-
- def __getitem__(self, key):
- return self.d[key]
-
- def keys(self):
- return self.d.keys()
-
- def items(self):
- return self.d.items()
-
-def convertfrompyobject_test(expr, recurse=True):
- # pydict_to_tv
- stringtochars_test(expr % '{%s : 1}')
- if recurse:
- convertfrompyobject_test(expr % '{"abcF" : %s}', False)
- # pymap_to_tv
- stringtochars_test(expr % 'Mapping({%s : 1})')
- if recurse:
- convertfrompyobject_test(expr % 'Mapping({"abcG" : %s})', False)
- # pyseq_to_tv
- iter_test(expr)
- return subexpr_test(expr, 'ConvertFromPyObject', (
- 'None', # Not conversible
- '{"": 1}', # Empty key not allowed
- '{u"": 1}', # Same, but with unicode object
- 'FailingMapping()', #
- 'FailingMappingKey()', #
- 'FailingNumber()', #
- ))
-
-def convertfrompymapping_test(expr):
- convertfrompyobject_test(expr)
- return subexpr_test(expr, 'ConvertFromPyMapping', (
- '[]',
- ))
-
-def iter_test(expr):
- return subexpr_test(expr, '*Iter*', (
- 'FailingIter()',
- 'FailingIterNext()',
- ))
-
-def number_test(expr, natural=False, unsigned=False):
- if natural:
- unsigned = True
- return subexpr_test(expr, 'NumberToLong', (
- '[]',
- 'None',
- ) + (unsigned and ('-1',) or ())
- + (natural and ('0',) or ()))
-
-class FailingTrue(object):
- def __nonzero__(self):
- raise NotImplementedError('bool')
-
-class FailingIter(object):
- def __iter__(self):
- raise NotImplementedError('iter')
-
-class FailingIterNext(object):
- def __iter__(self):
- return self
-
- def next(self):
- raise NotImplementedError('next')
-
-class FailingIterNextN(object):
- def __init__(self, n):
- self.n = n
-
- def __iter__(self):
- return self
-
- def next(self):
- if self.n:
- self.n -= 1
- return 1
- else:
- raise NotImplementedError('next N')
-
-class FailingMappingKey(object):
- def __getitem__(self, item):
- raise NotImplementedError('getitem:mappingkey')
-
- def keys(self):
- return list("abcH")
-
-class FailingMapping(object):
- def __getitem__(self):
- raise NotImplementedError('getitem:mapping')
-
- def keys(self):
- raise NotImplementedError('keys')
-
-class FailingList(list):
- def __getitem__(self, idx):
- if i == 2:
- raise NotImplementedError('getitem:list')
- else:
- return super(FailingList, self).__getitem__(idx)
-
-class NoArgsCall(object):
- def __call__(self):
- pass
-
-class FailingCall(object):
- def __call__(self, path):
- raise NotImplementedError('call')
-
-class FailingNumber(object):
- def __int__(self):
- raise NotImplementedError('int')
-
-cb.append("> Output")
-cb.append(">> OutputSetattr")
-ee('del sys.stdout.softspace')
-number_test('sys.stdout.softspace = %s', unsigned=True)
-number_test('sys.stderr.softspace = %s', unsigned=True)
-ee('sys.stdout.attr = None')
-cb.append(">> OutputWrite")
-ee('sys.stdout.write(None)')
-cb.append(">> OutputWriteLines")
-ee('sys.stdout.writelines(None)')
-ee('sys.stdout.writelines([1])')
-iter_test('sys.stdout.writelines(%s)')
-cb.append("> VimCommand")
-stringtochars_test('vim.command(%s)')
-ee('vim.command("", 2)')
-#! Not checked: vim->python exceptions translating: checked later
-cb.append("> VimToPython")
-#! Not checked: everything: needs errors in internal python functions
-cb.append("> VimEval")
-stringtochars_test('vim.eval(%s)')
-ee('vim.eval("", FailingTrue())')
-#! Not checked: everything: needs errors in internal python functions
-cb.append("> VimEvalPy")
-stringtochars_test('vim.bindeval(%s)')
-ee('vim.eval("", 2)')
-#! Not checked: vim->python exceptions translating: checked later
-cb.append("> VimStrwidth")
-stringtochars_test('vim.strwidth(%s)')
-cb.append("> VimForeachRTP")
-ee('vim.foreach_rtp(None)')
-ee('vim.foreach_rtp(NoArgsCall())')
-ee('vim.foreach_rtp(FailingCall())')
-ee('vim.foreach_rtp(int, 2)')
-cb.append('> import')
-old_rtp = vim.options['rtp']
-vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
-ee('import xxx_no_such_module_xxx')
-ee('import failing_import')
-ee('import failing')
-vim.options['rtp'] = old_rtp
-del old_rtp
-cb.append("> Options")
-cb.append(">> OptionsItem")
-ee('vim.options["abcQ"]')
-ee('vim.options[""]')
-stringtochars_test('vim.options[%s]')
-cb.append(">> OptionsContains")
-stringtochars_test('%s in vim.options')
-cb.append("> Dictionary")
-cb.append(">> DictionaryConstructor")
-ee('vim.Dictionary("abcI")')
-##! Not checked: py_dict_alloc failure
-cb.append(">> DictionarySetattr")
-ee('del d.locked')
-ee('d.locked = FailingTrue()')
-ee('vim.vvars.locked = False')
-ee('d.scope = True')
-ee('d.xxx = True')
-cb.append(">> _DictionaryItem")
-ee('d.get("a", 2, 3)')
-stringtochars_test('d.get(%s)')
-ee('d.pop("a")')
-ee('dl.pop("a")')
-cb.append(">> DictionaryContains")
-ee('"" in d')
-ee('0 in d')
-cb.append(">> DictionaryIterNext")
-ee('for i in ned: ned["a"] = 1')
-del i
-cb.append(">> DictionaryAssItem")
-ee('dl["b"] = 1')
-stringtochars_test('d[%s] = 1')
-convertfrompyobject_test('d["a"] = %s')
-cb.append(">> DictionaryUpdate")
-cb.append(">>> kwargs")
-cb.append(">>> iter")
-ee('d.update(FailingMapping())')
-ee('d.update([FailingIterNext()])')
-ee('d.update([FailingIterNextN(1)])')
-iter_test('d.update(%s)')
-convertfrompyobject_test('d.update(%s)')
-stringtochars_test('d.update(((%s, 0),))')
-convertfrompyobject_test('d.update((("a", %s),))')
-cb.append(">> DictionaryPopItem")
-ee('d.popitem(1, 2)')
-cb.append(">> DictionaryHasKey")
-ee('d.has_key()')
-cb.append("> List")
-cb.append(">> ListConstructor")
-ee('vim.List(1, 2)')
-ee('vim.List(a=1)')
-iter_test('vim.List(%s)')
-convertfrompyobject_test('vim.List([%s])')
-cb.append(">> ListItem")
-ee('l[1000]')
-cb.append(">> ListAssItem")
-ee('ll[1] = 2')
-ee('l[1000] = 3')
-cb.append(">> ListAssSlice")
-ee('ll[1:100] = "abcJ"')
-iter_test('l[:] = %s')
-ee('nel[1:10:2] = "abcK"')
-cb.append(repr(tuple(nel)))
-ee('nel[1:10:2] = "a"')
-cb.append(repr(tuple(nel)))
-ee('nel[1:1:-1] = "a"')
-cb.append(repr(tuple(nel)))
-ee('nel[:] = FailingIterNextN(2)')
-cb.append(repr(tuple(nel)))
-convertfrompyobject_test('l[:] = [%s]')
-cb.append(">> ListConcatInPlace")
-iter_test('l.extend(%s)')
-convertfrompyobject_test('l.extend([%s])')
-cb.append(">> ListSetattr")
-ee('del l.locked')
-ee('l.locked = FailingTrue()')
-ee('l.xxx = True')
-cb.append("> Function")
-cb.append(">> FunctionConstructor")
-ee('vim.Function("123")')
-ee('vim.Function("xxx_non_existent_function_xxx")')
-ee('vim.Function("xxx#non#existent#function#xxx")')
-cb.append(">> FunctionCall")
-convertfrompyobject_test('f(%s)')
-convertfrompymapping_test('fd(self=%s)')
-cb.append("> TabPage")
-cb.append(">> TabPageAttr")
-ee('vim.current.tabpage.xxx')
-cb.append("> TabList")
-cb.append(">> TabListItem")
-ee('vim.tabpages[1000]')
-cb.append("> Window")
-cb.append(">> WindowAttr")
-ee('vim.current.window.xxx')
-cb.append(">> WindowSetattr")
-ee('vim.current.window.buffer = 0')
-ee('vim.current.window.cursor = (100000000, 100000000)')
-ee('vim.current.window.cursor = True')
-number_test('vim.current.window.height = %s', unsigned=True)
-number_test('vim.current.window.width = %s', unsigned=True)
-ee('vim.current.window.xxxxxx = True')
-cb.append("> WinList")
-cb.append(">> WinListItem")
-ee('vim.windows[1000]')
-cb.append("> Buffer")
-cb.append(">> StringToLine (indirect)")
-ee('vim.current.buffer[0] = u"\\na"')
-ee('vim.current.buffer[0] = "\\na"')
-cb.append(">> SetBufferLine (indirect)")
-ee('vim.current.buffer[0] = True')
-cb.append(">> SetBufferLineList (indirect)")
-ee('vim.current.buffer[:] = True')
-ee('vim.current.buffer[:] = ["\\na", "bc"]')
-cb.append(">> InsertBufferLines (indirect)")
-ee('vim.current.buffer.append(None)')
-ee('vim.current.buffer.append(["\\na", "bc"])')
-ee('vim.current.buffer.append("\\nbc")')
-cb.append(">> RBItem")
-ee('vim.current.buffer[100000000]')
-cb.append(">> RBAsItem")
-ee('vim.current.buffer[100000000] = ""')
-cb.append(">> BufferAttr")
-ee('vim.current.buffer.xxx')
-cb.append(">> BufferSetattr")
-ee('vim.current.buffer.name = True')
-ee('vim.current.buffer.xxx = True')
-cb.append(">> BufferMark")
-ee('vim.current.buffer.mark(0)')
-ee('vim.current.buffer.mark("abcM")')
-ee('vim.current.buffer.mark("!")')
-cb.append(">> BufferRange")
-ee('vim.current.buffer.range(1, 2, 3)')
-cb.append("> BufMap")
-cb.append(">> BufMapItem")
-ee('vim.buffers[100000000]')
-number_test('vim.buffers[%s]', natural=True)
-cb.append("> Current")
-cb.append(">> CurrentGetattr")
-ee('vim.current.xxx')
-cb.append(">> CurrentSetattr")
-ee('vim.current.line = True')
-ee('vim.current.buffer = True')
-ee('vim.current.window = True')
-ee('vim.current.tabpage = True')
-ee('vim.current.xxx = True')
-del d
-del ned
-del dl
-del l
-del ll
-del nel
-del f
-del fd
-del fdel
-del subexpr_test
-del stringtochars_test
-del Mapping
-del convertfrompyobject_test
-del convertfrompymapping_test
-del iter_test
-del number_test
-del FailingTrue
-del FailingIter
-del FailingIterNext
-del FailingIterNextN
-del FailingMapping
-del FailingMappingKey
-del FailingList
-del NoArgsCall
-del FailingCall
-del FailingNumber
-EOF
-:delfunction F
-:"
-:" Test import
-py << EOF
-sys.path.insert(0, os.path.join(os.getcwd(), 'python_before'))
-sys.path.append(os.path.join(os.getcwd(), 'python_after'))
-vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
-l = []
-def callback(path):
- l.append(path[-len('/testdir'):].replace(os.path.sep, '/'))
-vim.foreach_rtp(callback)
-cb.append(repr(l))
-del l
-def callback(path):
- return path[-len('/testdir'):].replace(os.path.sep, '/')
-cb.append(repr(vim.foreach_rtp(callback)))
-del callback
-from module import dir as d
-from modulex import ddir
-cb.append(d + ',' + ddir)
-import before
-cb.append(before.dir)
-import after
-cb.append(after.dir)
-import topmodule as tm
-import topmodule.submodule as tms
-import topmodule.submodule.subsubmodule.subsubsubmodule as tmsss
-cb.append(tm.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/__init__.py'):])
-cb.append(tms.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/__init__.py'):])
-cb.append(tmsss.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/subsubmodule/subsubsubmodule.py'):])
-del before
-del after
-del d
-del ddir
-del tm
-del tms
-del tmsss
-EOF
-:"
-:" Test exceptions
-:fun Exe(e)
-: execute a:e
-:endfun
-py << EOF
-Exe = vim.bindeval('function("Exe")')
-ee('vim.command("throw \'abcN\'")')
-ee('Exe("throw \'def\'")')
-ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
-ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
-ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
-ee('vim.eval("xxx_unknown_function_xxx()")')
-ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
-del Exe
-EOF
-:delfunction Exe
-:"
-:" Regression: interrupting vim.command propagates to next vim.command
-py << EOF
-def test_keyboard_interrupt():
- try:
- vim.command('while 1 | endwhile')
- except KeyboardInterrupt:
- cb.append('Caught KeyboardInterrupt')
- except Exception:
- cb.append('!!!!!!!! Caught exception: ' + repr(sys.exc_info))
- else:
- cb.append('!!!!!!!! No exception')
- try:
- vim.command('$ put =\'Running :put\'')
- except KeyboardInterrupt:
- cb.append('!!!!!!!! Caught KeyboardInterrupt')
- except Exception:
- cb.append('!!!!!!!! Caught exception: ' + repr(sys.exc_info))
- else:
- cb.append('No exception')
-EOF
-:debuggreedy
-:call inputsave()
-:call feedkeys("s\ns\ns\ns\nq\n")
-:redir => output
-:debug silent! py test_keyboard_interrupt()
-:redir END
-:0 debuggreedy
-:call inputrestore()
-:silent $put =output
-:unlet output
-:py del test_keyboard_interrupt
-:"
-:" Cleanup
-py << EOF
-del cb
-del ee
-del sys
-del os
-del vim
-EOF
-:endfun
-:"
-:fun RunTest()
-:let checkrefs = !empty($PYTHONDUMPREFS)
-:let start = getline(1, '$')
-:for i in range(checkrefs ? 10 : 1)
-: if i != 0
-: %d _
-: call setline(1, start)
-: endif
-: call Test()
-: if i == 0
-: let result = getline(1, '$')
-: endif
-:endfor
-:if checkrefs
-: %d _
-: call setline(1, result)
-:endif
-:endfun
-:"
-:call RunTest()
-:delfunction RunTest
-:delfunction Test
-:call garbagecollect(1)
-:"
-:/^start:/,$wq! test.out
-:" vim: et ts=4 isk-=\:
-:call getchar()
-ENDTEST
-
-start:
diff --git a/src/nvim/testdir/test86.ok b/src/nvim/testdir/test86.ok
deleted file mode 100644
index 257a5ee4cd..0000000000
--- a/src/nvim/testdir/test86.ok
+++ /dev/null
@@ -1,1266 +0,0 @@
-start:
-[1, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
-[1, 2, function('strlen'), {'a': 1}]
-Vim(put):E684:
-[0, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
-[0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]]
-1
-['-1', '0', '1', 'b', 'f']
-['asd', -1L, <vim.Function '1'>, <vim.dictionary object at >, <vim.list object at >]
-[('-1', <vim.dictionary object at >), ('0', -1L), ('1', 'asd'), ('b', <vim.list object at >), ('f', <vim.Function '1'>)]
-'-1' : {'a': 1}
-'0' : -1
-'1' : 'asd'
-'b' : [1, 2, function('strlen')]
-'f' : function('1')
-[0, function('strlen')]
-[3]
-[1, 2, function('strlen')]
-[1, 2, function('strlen')]
-1
-'asd'
-2
-True
-False
-True
-False
-['0']
-{'0': -1}
-('0', -1L)
-None
-[]
-[0, 1, 2, 3]
-[0, 1, 2, 3]
-[0, 1, 3]
-[0, 1]
-[0, 1]
-[0, 1]
-[0, 1, 2, 3]
-[0, 1, 2, 3]
-[0, 2, 3]
-[2, 3]
-[2, 3]
-[2, 3]
-[1, 3]
-[0, 2]
-[0, 1, 2, 3]
-['a', 0, 1, 2, 3]
-[0, 'b', 2, 3]
-[0, 1, 'c']
-[0, 1, 2, 3, 'd']
-[0, 1, 2, 'e', 3]
-['f', 2, 3]
-[0, 1, 'g', 2, 3]
-['h']
-[0, 1, 10, 3, 20, 5, 6, 7]
-[0, 1, 2, 3, 20, 5, 10, 7]
-[0, 1, 2, 3, 4, 5, 6, 7]
-[0, 1, 2, 3, 4, 5, 6, 7]
-[0, 1, 2, 3, 4, 5, 6, 7]
-[0, 1, 2, 3]
-[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
-[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
-[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
-l[1](1, 2, 3):error:('Vim:E725: Calling dict function without Dictionary: DictNew',)
-f(1, 2, 3):error:('Vim:E117: Unknown function: New',)
-[0.0, 0.0]
-KeyError
-TypeError
-TypeError
-ValueError
-TypeError
-TypeError
-KeyError
-KeyError
-d : locked:0;scope:0
-dl : locked:1;scope:0
-v: : locked:2;scope:1
-g: : locked:0;scope:2
-d:{'abc2': 1}
-dl:{'def': 1}
-l : locked:0
-ll : locked:1
-l:[0]
-ll:[1]
-[0, 1, 2]
-['a', 'b']
-['c', 1]
-['d', ['e']]
-0.0
-"\0": Vim(let):E859:
-{"\0": 1}: Vim(let):E859:
-undefined_name: Vim(let):Trace
-vim: Vim(let):E859:
-[1]
-[1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1]
-[0, 1, 2, 3]
-[2, 3, 4, 5]
-[0, 1]
-[4, 5]
-[2, 3]
-[]
-[2, 3]
-[]
-[0, 1, 2, 3, 4, 5]
-[0, 1, 2, 3, 4, 5]
-[0, 1, 2, 3, 4, 5]
-[4, 3]
-[0, 2, 4]
-[]
-Abc
-bac
-def
-bar
-jkl
-wopts iters equal: 1
-bopts iters equal: 1
->>> paste
- g/w/b:1/0/0
- g/w/b (in):1/0/0
- p/gopts1: False
- p/wopts1! KeyError
- inv: 2! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1! KeyError
- inv: 2! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 1
- W: 1:1 2:1 3:1 4:1
- B: 1:1 2:1 3:1 4:1
- del wopts3! KeyError
- del bopts3! KeyError
- G: 1
- W: 1:1 2:1 3:1 4:1
- B: 1:1 2:1 3:1 4:1
->>> previewheight
- g/w/b:1/0/0
- g/w/b (in):1/0/0
- p/gopts1: 12
- inv: 'a'! TypeError
- p/wopts1! KeyError
- inv: 'a'! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1! KeyError
- inv: 'a'! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 5
- W: 1:5 2:5 3:5 4:5
- B: 1:5 2:5 3:5 4:5
- del wopts3! KeyError
- del bopts3! KeyError
- G: 5
- W: 1:5 2:5 3:5 4:5
- B: 1:5 2:5 3:5 4:5
->>> operatorfunc
- g/w/b:1/0/0
- g/w/b (in):1/0/0
- p/gopts1: ''
- inv: 2! TypeError
- p/wopts1! KeyError
- inv: 2! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1! KeyError
- inv: 2! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 'A'
- W: 1:'A' 2:'A' 3:'A' 4:'A'
- B: 1:'A' 2:'A' 3:'A' 4:'A'
- del wopts3! KeyError
- del bopts3! KeyError
- G: 'A'
- W: 1:'A' 2:'A' 3:'A' 4:'A'
- B: 1:'A' 2:'A' 3:'A' 4:'A'
->>> number
- g/w/b:0/1/0
- g/w/b (in):0/1/0
- p/gopts1! KeyError
- inv: 0! KeyError
- gopts1! KeyError
- p/wopts1: False
- p/bopts1! KeyError
- inv: 0! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 0
- W: 1:1 2:1 3:0 4:0
- B: 1:1 2:1 3:0 4:0
- del wopts3! ValueError
- del bopts3! KeyError
- G: 0
- W: 1:1 2:1 3:0 4:0
- B: 1:1 2:1 3:0 4:0
->>> numberwidth
- g/w/b:0/1/0
- g/w/b (in):0/1/0
- p/gopts1! KeyError
- inv: -100! KeyError
- gopts1! KeyError
- p/wopts1: 8
- inv: -100! error
- p/bopts1! KeyError
- inv: -100! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 8
- W: 1:3 2:5 3:2 4:8
- B: 1:3 2:5 3:2 4:8
- del wopts3! ValueError
- del bopts3! KeyError
- G: 8
- W: 1:3 2:5 3:2 4:8
- B: 1:3 2:5 3:2 4:8
->>> colorcolumn
- g/w/b:0/1/0
- g/w/b (in):0/1/0
- p/gopts1! KeyError
- inv: 'abc4'! KeyError
- gopts1! KeyError
- p/wopts1: ''
- inv: 'abc4'! error
- p/bopts1! KeyError
- inv: 'abc4'! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: ''
- W: 1:'+2' 2:'+3' 3:'+1' 4:''
- B: 1:'+2' 2:'+3' 3:'+1' 4:''
- del wopts3! ValueError
- del bopts3! KeyError
- G: ''
- W: 1:'+2' 2:'+3' 3:'+1' 4:''
- B: 1:'+2' 2:'+3' 3:'+1' 4:''
->>> statusline
- g/w/b:1/1/0
- g/w/b (in):1/1/0
- p/gopts1: ''
- inv: 0! TypeError
- p/wopts1: None
- inv: 0! TypeError
- p/bopts1! KeyError
- inv: 0! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: '1'
- W: 1:'2' 2:'4' 3:'1' 4:'1'
- B: 1:'2' 2:'4' 3:'1' 4:'1'
- del bopts3! KeyError
- G: '1'
- W: 1:'2' 2:'1' 3:'1' 4:'1'
- B: 1:'2' 2:'1' 3:'1' 4:'1'
->>> autoindent
- g/w/b:0/0/1
- g/w/b (in):0/0/1
- p/gopts1! KeyError
- inv: 2! KeyError
- gopts1! KeyError
- p/wopts1! KeyError
- inv: 2! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: False
- G: 0
- W: 1:0 2:1 3:0 4:1
- B: 1:0 2:1 3:0 4:1
- del wopts3! KeyError
- del bopts3! ValueError
- G: 0
- W: 1:0 2:1 3:0 4:1
- B: 1:0 2:1 3:0 4:1
->>> shiftwidth
- g/w/b:0/0/1
- g/w/b (in):0/0/1
- p/gopts1! KeyError
- inv: 3! KeyError
- gopts1! KeyError
- p/wopts1! KeyError
- inv: 3! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: 8
- G: 8
- W: 1:0 2:2 3:8 4:1
- B: 1:0 2:2 3:8 4:1
- del wopts3! KeyError
- del bopts3! ValueError
- G: 8
- W: 1:0 2:2 3:8 4:1
- B: 1:0 2:2 3:8 4:1
->>> omnifunc
- g/w/b:0/0/1
- g/w/b (in):0/0/1
- p/gopts1! KeyError
- inv: 1! KeyError
- gopts1! KeyError
- p/wopts1! KeyError
- inv: 1! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: ''
- inv: 1! TypeError
- G: ''
- W: 1:'A' 2:'B' 3:'' 4:'C'
- B: 1:'A' 2:'B' 3:'' 4:'C'
- del wopts3! KeyError
- del bopts3! ValueError
- G: ''
- W: 1:'A' 2:'B' 3:'' 4:'C'
- B: 1:'A' 2:'B' 3:'' 4:'C'
->>> preserveindent
- g/w/b:0/0/1
- g/w/b (in):0/0/1
- p/gopts1! KeyError
- inv: 2! KeyError
- gopts1! KeyError
- p/wopts1! KeyError
- inv: 2! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: False
- G: 0
- W: 1:0 2:1 3:0 4:1
- B: 1:0 2:1 3:0 4:1
- del wopts3! KeyError
- del bopts3! ValueError
- G: 0
- W: 1:0 2:1 3:0 4:1
- B: 1:0 2:1 3:0 4:1
->>> path
- g/w/b:1/0/1
- g/w/b (in):1/0/1
- p/gopts1: '.,..,,'
- inv: 0! TypeError
- p/wopts1! KeyError
- inv: 0! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: None
- inv: 0! TypeError
- G: '.,,'
- W: 1:'.,,' 2:',,' 3:'.,,' 4:'.'
- B: 1:'.,,' 2:',,' 3:'.,,' 4:'.'
- del wopts3! KeyError
- G: '.,,'
- W: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,'
- B: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,'
-First line
-First line
-def
-First line
-Second line
-Third line
-(7, 2)
-<buffer test86.in><buffer >
-baz
-bar
-Second line
-Third line
-foo
-1:BufFilePre:1
-1:BufFilePost:1
-testdir/foo
-5:BufFilePre:5
-5:BufFilePost:5
-testdir/bar
-1:BufFilePre:1
-1:BufFilePost:1
-testdir/test86.in
-valid: b:False, cb:True
-i:<buffer test86.in>
-i2:<buffer test86.in>
-i:<buffer a>
-i3:<buffer test86.in>
-1:<buffer test86.in>=<buffer test86.in>
-8:<buffer a>=<buffer a>
-9:<buffer b>=<buffer b>
-10:<buffer c>=<buffer c>
-4
-i4:<buffer test86.in>
-i4:<buffer test86.in>
-StopIteration
-Number of tabs: 4
-Current tab pages:
- <tabpage 0>(1): 1 windows, current is <window object (unknown)>
- Windows:
- <window object (unknown)>(1): displays buffer <buffer test86.in>; cursor is at (37, 0)
- <tabpage 1>(2): 1 windows, current is <window object (unknown)>
- Windows:
- <window object (unknown)>(1): displays buffer <buffer 0>; cursor is at (1, 0)
- <tabpage 2>(3): 2 windows, current is <window object (unknown)>
- Windows:
- <window object (unknown)>(1): displays buffer <buffer a.1>; cursor is at (1, 0)
- <window object (unknown)>(2): displays buffer <buffer 1>; cursor is at (1, 0)
- <tabpage 3>(4): 4 windows, current is <window 0>
- Windows:
- <window 0>(1): displays buffer <buffer c.2>; cursor is at (1, 0)
- <window 1>(2): displays buffer <buffer b.2>; cursor is at (1, 0)
- <window 2>(3): displays buffer <buffer a.2>; cursor is at (1, 0)
- <window 3>(4): displays buffer <buffer 2>; cursor is at (1, 0)
-Number of windows in current tab page: 4
-Current tab page: <tabpage 3>
-Current window: <window 0>: <window 0> is <window 0>
-Current buffer: <buffer c.2>: <buffer c.2> is <buffer c.2> is <buffer c.2>
-ValueError at assigning foreign tab window
-Type error at assigning None to vim.current.window
-Type error at assigning None to vim.current.tabpage
-Type error at assigning None to vim.current.buffer
-Current tab page: <tabpage 2>
-Current window: <window 0>
-Current buffer: <buffer test86.in>
-Current line: 'Type error at assigning None to vim.current.buffer'
-w.valid: [True, False]
-t.valid: [True, False, True, False]
-vim.vars:Dictionary:True
-vim.options:Options:True
-vim.bindeval("{}"):Dictionary:True
-vim.bindeval("[]"):List:True
-vim.bindeval("function('tr')"):Function:True
-vim.current.buffer:Buffer:True
-vim.current.range:Range:True
-vim.current.window:Window:True
-vim.current.tabpage:TabPage:True
-current:__dir__,__members__,buffer,line,range,tabpage,window
-buffer:__dir__,__members__,append,mark,name,number,options,range,valid,vars
-window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars
-tabpage:__dir__,__members__,number,valid,vars,window,windows
-range:__dir__,__members__,append,end,start
-dictionary:__dir__,__members__,get,has_key,items,keys,locked,pop,popitem,scope,update,values
-list:__dir__,__members__,extend,locked
-function:__dir__,__members__,softspace
-output:__dir__,__members__,flush,softspace,write,writelines
-{}
-{'a': 1}
-{'a': 1}
-[]
-['a', 'b', 'c', '7']
-function('tr')
-'
-abcdef
-line :
-abcdef
-abcA
-line :
-abcB'
-['a', 'dup_a']
-['a', 'a']
-['a', 'b', 'c', 'C']
-[2, 2]
-[2, 2]
-1
-1
-function('Put')
-testdir
-test86.in
-src
-testdir/test86.in
-testdir
-test86.in
-> Output
->> OutputSetattr
-del sys.stdout.softspace:AttributeError:("can't delete OutputObject attributes",)
->>> Testing NumberToLong using sys.stdout.softspace = %s
-sys.stdout.softspace = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
-sys.stdout.softspace = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
-sys.stdout.softspace = -1:ValueError:('number must be greater or equal to zero',)
-<<< Finished
->>> Testing NumberToLong using sys.stderr.softspace = %s
-sys.stderr.softspace = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
-sys.stderr.softspace = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
-sys.stderr.softspace = -1:ValueError:('number must be greater or equal to zero',)
-<<< Finished
-sys.stdout.attr = None:AttributeError:('invalid attribute: attr',)
->> OutputWrite
-sys.stdout.write(None):TypeError:('coercing to Unicode: need string or buffer, NoneType found',)
->> OutputWriteLines
-sys.stdout.writelines(None):TypeError:("'NoneType' object is not iterable",)
-sys.stdout.writelines([1]):TypeError:('coercing to Unicode: need string or buffer, int found',)
->>> Testing *Iter* using sys.stdout.writelines(%s)
-sys.stdout.writelines(FailingIter()):NotImplementedError:('iter',)
-sys.stdout.writelines(FailingIterNext()):NotImplementedError:('next',)
-<<< Finished
-> VimCommand
->>> Testing StringToChars using vim.command(%s)
-vim.command(1):TypeError:('expected str() or unicode() instance, but got int',)
-vim.command(u"\0"):TypeError:('expected string without null bytes',)
-vim.command("\0"):TypeError:('expected string without null bytes',)
-<<< Finished
-vim.command("", 2):TypeError:('command() takes exactly one argument (2 given)',)
-> VimToPython
-> VimEval
->>> Testing StringToChars using vim.eval(%s)
-vim.eval(1):TypeError:('expected str() or unicode() instance, but got int',)
-vim.eval(u"\0"):TypeError:('expected string without null bytes',)
-vim.eval("\0"):TypeError:('expected string without null bytes',)
-<<< Finished
-vim.eval("", FailingTrue()):TypeError:('function takes exactly 1 argument (2 given)',)
-> VimEvalPy
->>> Testing StringToChars using vim.bindeval(%s)
-vim.bindeval(1):TypeError:('expected str() or unicode() instance, but got int',)
-vim.bindeval(u"\0"):TypeError:('expected string without null bytes',)
-vim.bindeval("\0"):TypeError:('expected string without null bytes',)
-<<< Finished
-vim.eval("", 2):TypeError:('function takes exactly 1 argument (2 given)',)
-> VimStrwidth
->>> Testing StringToChars using vim.strwidth(%s)
-vim.strwidth(1):TypeError:('expected str() or unicode() instance, but got int',)
-vim.strwidth(u"\0"):TypeError:('expected string without null bytes',)
-vim.strwidth("\0"):TypeError:('expected string without null bytes',)
-<<< Finished
-> VimForeachRTP
-vim.foreach_rtp(None):TypeError:("'NoneType' object is not callable",)
-vim.foreach_rtp(NoArgsCall()):TypeError:('__call__() takes exactly 1 argument (2 given)',)
-vim.foreach_rtp(FailingCall()):NotImplementedError:('call',)
-vim.foreach_rtp(int, 2):TypeError:('foreach_rtp() takes exactly one argument (2 given)',)
-> import
-import xxx_no_such_module_xxx:ImportError:('No module named xxx_no_such_module_xxx',)
-import failing_import:ImportError:('No module named failing_import',)
-import failing:NotImplementedError:()
-> Options
->> OptionsItem
-vim.options["abcQ"]:KeyError:('abcQ',)
-vim.options[""]:ValueError:('empty keys are not allowed',)
->>> Testing StringToChars using vim.options[%s]
-vim.options[1]:TypeError:('expected str() or unicode() instance, but got int',)
-vim.options[u"\0"]:TypeError:('expected string without null bytes',)
-vim.options["\0"]:TypeError:('expected string without null bytes',)
-<<< Finished
->> OptionsContains
->>> Testing StringToChars using %s in vim.options
-1 in vim.options:TypeError:('expected str() or unicode() instance, but got int',)
-u"\0" in vim.options:TypeError:('expected string without null bytes',)
-"\0" in vim.options:TypeError:('expected string without null bytes',)
-<<< Finished
-> Dictionary
->> DictionaryConstructor
-vim.Dictionary("abcI"):ValueError:('expected sequence element of size 2, but got sequence of size 1',)
->> DictionarySetattr
-del d.locked:AttributeError:('cannot delete vim.Dictionary attributes',)
-d.locked = FailingTrue():NotImplementedError:('bool',)
-vim.vvars.locked = False:TypeError:('cannot modify fixed dictionary',)
-d.scope = True:AttributeError:('cannot set attribute scope',)
-d.xxx = True:AttributeError:('cannot set attribute xxx',)
->> _DictionaryItem
-d.get("a", 2, 3):TypeError:('function takes at most 2 arguments (3 given)',)
->>> Testing StringToChars using d.get(%s)
-d.get(1):TypeError:('expected str() or unicode() instance, but got int',)
-d.get(u"\0"):TypeError:('expected string without null bytes',)
-d.get("\0"):TypeError:('expected string without null bytes',)
-<<< Finished
-d.pop("a"):KeyError:('a',)
-dl.pop("a"):error:('dictionary is locked',)
->> DictionaryContains
-"" in d:ValueError:('empty keys are not allowed',)
-0 in d:TypeError:('expected str() or unicode() instance, but got int',)
->> DictionaryIterNext
-for i in ned: ned["a"] = 1:RuntimeError:('hashtab changed during iteration',)
->> DictionaryAssItem
-dl["b"] = 1:error:('dictionary is locked',)
->>> Testing StringToChars using d[%s] = 1
-d[1] = 1:TypeError:('expected str() or unicode() instance, but got int',)
-d[u"\0"] = 1:TypeError:('expected string without null bytes',)
-d["\0"] = 1:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d["a"] = {%s : 1}
-d["a"] = {1 : 1}:TypeError:('expected str() or unicode() instance, but got int',)
-d["a"] = {u"\0" : 1}:TypeError:('expected string without null bytes',)
-d["a"] = {"\0" : 1}:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d["a"] = {"abcF" : {%s : 1}}
-d["a"] = {"abcF" : {1 : 1}}:TypeError:('expected str() or unicode() instance, but got int',)
-d["a"] = {"abcF" : {u"\0" : 1}}:TypeError:('expected string without null bytes',)
-d["a"] = {"abcF" : {"\0" : 1}}:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d["a"] = {"abcF" : Mapping({%s : 1})}
-d["a"] = {"abcF" : Mapping({1 : 1})}:TypeError:('expected str() or unicode() instance, but got int',)
-d["a"] = {"abcF" : Mapping({u"\0" : 1})}:TypeError:('expected string without null bytes',)
-d["a"] = {"abcF" : Mapping({"\0" : 1})}:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using d["a"] = {"abcF" : %s}
-d["a"] = {"abcF" : FailingIter()}:TypeError:('unable to convert FailingIter to vim structure',)
-d["a"] = {"abcF" : FailingIterNext()}:NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d["a"] = {"abcF" : %s}
-d["a"] = {"abcF" : None}:TypeError:('unable to convert NoneType to vim structure',)
-d["a"] = {"abcF" : {"": 1}}:ValueError:('empty keys are not allowed',)
-d["a"] = {"abcF" : {u"": 1}}:ValueError:('empty keys are not allowed',)
-d["a"] = {"abcF" : FailingMapping()}:NotImplementedError:('keys',)
-d["a"] = {"abcF" : FailingMappingKey()}:NotImplementedError:('getitem:mappingkey',)
-d["a"] = {"abcF" : FailingNumber()}:TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using d["a"] = Mapping({%s : 1})
-d["a"] = Mapping({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',)
-d["a"] = Mapping({u"\0" : 1}):TypeError:('expected string without null bytes',)
-d["a"] = Mapping({"\0" : 1}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d["a"] = Mapping({"abcG" : {%s : 1}})
-d["a"] = Mapping({"abcG" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',)
-d["a"] = Mapping({"abcG" : {u"\0" : 1}}):TypeError:('expected string without null bytes',)
-d["a"] = Mapping({"abcG" : {"\0" : 1}}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d["a"] = Mapping({"abcG" : Mapping({%s : 1})})
-d["a"] = Mapping({"abcG" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',)
-d["a"] = Mapping({"abcG" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',)
-d["a"] = Mapping({"abcG" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using d["a"] = Mapping({"abcG" : %s})
-d["a"] = Mapping({"abcG" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',)
-d["a"] = Mapping({"abcG" : FailingIterNext()}):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d["a"] = Mapping({"abcG" : %s})
-d["a"] = Mapping({"abcG" : None}):TypeError:('unable to convert NoneType to vim structure',)
-d["a"] = Mapping({"abcG" : {"": 1}}):ValueError:('empty keys are not allowed',)
-d["a"] = Mapping({"abcG" : {u"": 1}}):ValueError:('empty keys are not allowed',)
-d["a"] = Mapping({"abcG" : FailingMapping()}):NotImplementedError:('keys',)
-d["a"] = Mapping({"abcG" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',)
-d["a"] = Mapping({"abcG" : FailingNumber()}):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing *Iter* using d["a"] = %s
-d["a"] = FailingIter():TypeError:('unable to convert FailingIter to vim structure',)
-d["a"] = FailingIterNext():NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d["a"] = %s
-d["a"] = None:TypeError:('unable to convert NoneType to vim structure',)
-d["a"] = {"": 1}:ValueError:('empty keys are not allowed',)
-d["a"] = {u"": 1}:ValueError:('empty keys are not allowed',)
-d["a"] = FailingMapping():NotImplementedError:('keys',)
-d["a"] = FailingMappingKey():NotImplementedError:('getitem:mappingkey',)
-d["a"] = FailingNumber():TypeError:('long() argument must be a string or a number',)
-<<< Finished
->> DictionaryUpdate
->>> kwargs
->>> iter
-d.update(FailingMapping()):NotImplementedError:('keys',)
-d.update([FailingIterNext()]):NotImplementedError:('next',)
-d.update([FailingIterNextN(1)]):NotImplementedError:('next N',)
->>> Testing *Iter* using d.update(%s)
-d.update(FailingIter()):NotImplementedError:('iter',)
-d.update(FailingIterNext()):NotImplementedError:('next',)
-<<< Finished
->>> Testing StringToChars using d.update({%s : 1})
-d.update({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',)
-d.update({u"\0" : 1}):TypeError:('expected string without null bytes',)
-d.update({"\0" : 1}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update({"abcF" : {%s : 1}})
-d.update({"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',)
-d.update({"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',)
-d.update({"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update({"abcF" : Mapping({%s : 1})})
-d.update({"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',)
-d.update({"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',)
-d.update({"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using d.update({"abcF" : %s})
-d.update({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',)
-d.update({"abcF" : FailingIterNext()}):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d.update({"abcF" : %s})
-d.update({"abcF" : None}):TypeError:('unable to convert NoneType to vim structure',)
-d.update({"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',)
-d.update({"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',)
-d.update({"abcF" : FailingMapping()}):NotImplementedError:('keys',)
-d.update({"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',)
-d.update({"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using d.update(Mapping({%s : 1}))
-d.update(Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',)
-d.update(Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',)
-d.update(Mapping({"\0" : 1})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update(Mapping({"abcG" : {%s : 1}}))
-d.update(Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',)
-d.update(Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',)
-d.update(Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update(Mapping({"abcG" : Mapping({%s : 1})}))
-d.update(Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',)
-d.update(Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',)
-d.update(Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using d.update(Mapping({"abcG" : %s}))
-d.update(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',)
-d.update(Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d.update(Mapping({"abcG" : %s}))
-d.update(Mapping({"abcG" : None})):TypeError:('unable to convert NoneType to vim structure',)
-d.update(Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',)
-d.update(Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',)
-d.update(Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',)
-d.update(Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',)
-d.update(Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing *Iter* using d.update(%s)
-d.update(FailingIter()):NotImplementedError:('iter',)
-d.update(FailingIterNext()):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d.update(%s)
-d.update(None):TypeError:("'NoneType' object is not iterable",)
-d.update({"": 1}):ValueError:('empty keys are not allowed',)
-d.update({u"": 1}):ValueError:('empty keys are not allowed',)
-d.update(FailingMapping()):NotImplementedError:('keys',)
-d.update(FailingMappingKey()):NotImplementedError:('getitem:mappingkey',)
-d.update(FailingNumber()):TypeError:("'FailingNumber' object is not iterable",)
-<<< Finished
->>> Testing StringToChars using d.update(((%s, 0),))
-d.update(((1, 0),)):TypeError:('expected str() or unicode() instance, but got int',)
-d.update(((u"\0", 0),)):TypeError:('expected string without null bytes',)
-d.update((("\0", 0),)):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update((("a", {%s : 1}),))
-d.update((("a", {1 : 1}),)):TypeError:('expected str() or unicode() instance, but got int',)
-d.update((("a", {u"\0" : 1}),)):TypeError:('expected string without null bytes',)
-d.update((("a", {"\0" : 1}),)):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update((("a", {"abcF" : {%s : 1}}),))
-d.update((("a", {"abcF" : {1 : 1}}),)):TypeError:('expected str() or unicode() instance, but got int',)
-d.update((("a", {"abcF" : {u"\0" : 1}}),)):TypeError:('expected string without null bytes',)
-d.update((("a", {"abcF" : {"\0" : 1}}),)):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update((("a", {"abcF" : Mapping({%s : 1})}),))
-d.update((("a", {"abcF" : Mapping({1 : 1})}),)):TypeError:('expected str() or unicode() instance, but got int',)
-d.update((("a", {"abcF" : Mapping({u"\0" : 1})}),)):TypeError:('expected string without null bytes',)
-d.update((("a", {"abcF" : Mapping({"\0" : 1})}),)):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using d.update((("a", {"abcF" : %s}),))
-d.update((("a", {"abcF" : FailingIter()}),)):TypeError:('unable to convert FailingIter to vim structure',)
-d.update((("a", {"abcF" : FailingIterNext()}),)):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d.update((("a", {"abcF" : %s}),))
-d.update((("a", {"abcF" : None}),)):TypeError:('unable to convert NoneType to vim structure',)
-d.update((("a", {"abcF" : {"": 1}}),)):ValueError:('empty keys are not allowed',)
-d.update((("a", {"abcF" : {u"": 1}}),)):ValueError:('empty keys are not allowed',)
-d.update((("a", {"abcF" : FailingMapping()}),)):NotImplementedError:('keys',)
-d.update((("a", {"abcF" : FailingMappingKey()}),)):NotImplementedError:('getitem:mappingkey',)
-d.update((("a", {"abcF" : FailingNumber()}),)):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using d.update((("a", Mapping({%s : 1})),))
-d.update((("a", Mapping({1 : 1})),)):TypeError:('expected str() or unicode() instance, but got int',)
-d.update((("a", Mapping({u"\0" : 1})),)):TypeError:('expected string without null bytes',)
-d.update((("a", Mapping({"\0" : 1})),)):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update((("a", Mapping({"abcG" : {%s : 1}})),))
-d.update((("a", Mapping({"abcG" : {1 : 1}})),)):TypeError:('expected str() or unicode() instance, but got int',)
-d.update((("a", Mapping({"abcG" : {u"\0" : 1}})),)):TypeError:('expected string without null bytes',)
-d.update((("a", Mapping({"abcG" : {"\0" : 1}})),)):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using d.update((("a", Mapping({"abcG" : Mapping({%s : 1})})),))
-d.update((("a", Mapping({"abcG" : Mapping({1 : 1})})),)):TypeError:('expected str() or unicode() instance, but got int',)
-d.update((("a", Mapping({"abcG" : Mapping({u"\0" : 1})})),)):TypeError:('expected string without null bytes',)
-d.update((("a", Mapping({"abcG" : Mapping({"\0" : 1})})),)):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using d.update((("a", Mapping({"abcG" : %s})),))
-d.update((("a", Mapping({"abcG" : FailingIter()})),)):TypeError:('unable to convert FailingIter to vim structure',)
-d.update((("a", Mapping({"abcG" : FailingIterNext()})),)):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d.update((("a", Mapping({"abcG" : %s})),))
-d.update((("a", Mapping({"abcG" : None})),)):TypeError:('unable to convert NoneType to vim structure',)
-d.update((("a", Mapping({"abcG" : {"": 1}})),)):ValueError:('empty keys are not allowed',)
-d.update((("a", Mapping({"abcG" : {u"": 1}})),)):ValueError:('empty keys are not allowed',)
-d.update((("a", Mapping({"abcG" : FailingMapping()})),)):NotImplementedError:('keys',)
-d.update((("a", Mapping({"abcG" : FailingMappingKey()})),)):NotImplementedError:('getitem:mappingkey',)
-d.update((("a", Mapping({"abcG" : FailingNumber()})),)):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing *Iter* using d.update((("a", %s),))
-d.update((("a", FailingIter()),)):TypeError:('unable to convert FailingIter to vim structure',)
-d.update((("a", FailingIterNext()),)):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using d.update((("a", %s),))
-d.update((("a", None),)):TypeError:('unable to convert NoneType to vim structure',)
-d.update((("a", {"": 1}),)):ValueError:('empty keys are not allowed',)
-d.update((("a", {u"": 1}),)):ValueError:('empty keys are not allowed',)
-d.update((("a", FailingMapping()),)):NotImplementedError:('keys',)
-d.update((("a", FailingMappingKey()),)):NotImplementedError:('getitem:mappingkey',)
-d.update((("a", FailingNumber()),)):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->> DictionaryPopItem
-d.popitem(1, 2):TypeError:('popitem() takes no arguments (2 given)',)
->> DictionaryHasKey
-d.has_key():TypeError:('has_key() takes exactly one argument (0 given)',)
-> List
->> ListConstructor
-vim.List(1, 2):TypeError:('function takes at most 1 argument (2 given)',)
-vim.List(a=1):TypeError:('list constructor does not accept keyword arguments',)
->>> Testing *Iter* using vim.List(%s)
-vim.List(FailingIter()):NotImplementedError:('iter',)
-vim.List(FailingIterNext()):NotImplementedError:('next',)
-<<< Finished
->>> Testing StringToChars using vim.List([{%s : 1}])
-vim.List([{1 : 1}]):TypeError:('expected str() or unicode() instance, but got int',)
-vim.List([{u"\0" : 1}]):TypeError:('expected string without null bytes',)
-vim.List([{"\0" : 1}]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using vim.List([{"abcF" : {%s : 1}}])
-vim.List([{"abcF" : {1 : 1}}]):TypeError:('expected str() or unicode() instance, but got int',)
-vim.List([{"abcF" : {u"\0" : 1}}]):TypeError:('expected string without null bytes',)
-vim.List([{"abcF" : {"\0" : 1}}]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using vim.List([{"abcF" : Mapping({%s : 1})}])
-vim.List([{"abcF" : Mapping({1 : 1})}]):TypeError:('expected str() or unicode() instance, but got int',)
-vim.List([{"abcF" : Mapping({u"\0" : 1})}]):TypeError:('expected string without null bytes',)
-vim.List([{"abcF" : Mapping({"\0" : 1})}]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using vim.List([{"abcF" : %s}])
-vim.List([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to vim structure',)
-vim.List([{"abcF" : FailingIterNext()}]):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using vim.List([{"abcF" : %s}])
-vim.List([{"abcF" : None}]):TypeError:('unable to convert NoneType to vim structure',)
-vim.List([{"abcF" : {"": 1}}]):ValueError:('empty keys are not allowed',)
-vim.List([{"abcF" : {u"": 1}}]):ValueError:('empty keys are not allowed',)
-vim.List([{"abcF" : FailingMapping()}]):NotImplementedError:('keys',)
-vim.List([{"abcF" : FailingMappingKey()}]):NotImplementedError:('getitem:mappingkey',)
-vim.List([{"abcF" : FailingNumber()}]):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using vim.List([Mapping({%s : 1})])
-vim.List([Mapping({1 : 1})]):TypeError:('expected str() or unicode() instance, but got int',)
-vim.List([Mapping({u"\0" : 1})]):TypeError:('expected string without null bytes',)
-vim.List([Mapping({"\0" : 1})]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using vim.List([Mapping({"abcG" : {%s : 1}})])
-vim.List([Mapping({"abcG" : {1 : 1}})]):TypeError:('expected str() or unicode() instance, but got int',)
-vim.List([Mapping({"abcG" : {u"\0" : 1}})]):TypeError:('expected string without null bytes',)
-vim.List([Mapping({"abcG" : {"\0" : 1}})]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using vim.List([Mapping({"abcG" : Mapping({%s : 1})})])
-vim.List([Mapping({"abcG" : Mapping({1 : 1})})]):TypeError:('expected str() or unicode() instance, but got int',)
-vim.List([Mapping({"abcG" : Mapping({u"\0" : 1})})]):TypeError:('expected string without null bytes',)
-vim.List([Mapping({"abcG" : Mapping({"\0" : 1})})]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using vim.List([Mapping({"abcG" : %s})])
-vim.List([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to vim structure',)
-vim.List([Mapping({"abcG" : FailingIterNext()})]):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using vim.List([Mapping({"abcG" : %s})])
-vim.List([Mapping({"abcG" : None})]):TypeError:('unable to convert NoneType to vim structure',)
-vim.List([Mapping({"abcG" : {"": 1}})]):ValueError:('empty keys are not allowed',)
-vim.List([Mapping({"abcG" : {u"": 1}})]):ValueError:('empty keys are not allowed',)
-vim.List([Mapping({"abcG" : FailingMapping()})]):NotImplementedError:('keys',)
-vim.List([Mapping({"abcG" : FailingMappingKey()})]):NotImplementedError:('getitem:mappingkey',)
-vim.List([Mapping({"abcG" : FailingNumber()})]):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing *Iter* using vim.List([%s])
-vim.List([FailingIter()]):TypeError:('unable to convert FailingIter to vim structure',)
-vim.List([FailingIterNext()]):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using vim.List([%s])
-vim.List([None]):TypeError:('unable to convert NoneType to vim structure',)
-vim.List([{"": 1}]):ValueError:('empty keys are not allowed',)
-vim.List([{u"": 1}]):ValueError:('empty keys are not allowed',)
-vim.List([FailingMapping()]):NotImplementedError:('keys',)
-vim.List([FailingMappingKey()]):NotImplementedError:('getitem:mappingkey',)
-vim.List([FailingNumber()]):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->> ListItem
-l[1000]:IndexError:('list index out of range',)
->> ListAssItem
-ll[1] = 2:error:('list is locked',)
-l[1000] = 3:IndexError:('list index out of range',)
->> ListAssSlice
-ll[1:100] = "abcJ":error:('list is locked',)
->>> Testing *Iter* using l[:] = %s
-l[:] = FailingIter():NotImplementedError:('iter',)
-l[:] = FailingIterNext():NotImplementedError:('next',)
-<<< Finished
-nel[1:10:2] = "abcK":ValueError:('attempt to assign sequence of size greater then 2 to extended slice',)
-('a', 'b', 'c', 'O')
-nel[1:10:2] = "a":ValueError:('attempt to assign sequence of size 1 to extended slice of size 2',)
-('a', 'b', 'c', 'O')
-nel[1:1:-1] = "a":ValueError:('attempt to assign sequence of size greater then 0 to extended slice',)
-('a', 'b', 'c', 'O')
-nel[:] = FailingIterNextN(2):NotImplementedError:('next N',)
-('a', 'b', 'c', 'O')
->>> Testing StringToChars using l[:] = [{%s : 1}]
-l[:] = [{1 : 1}]:TypeError:('expected str() or unicode() instance, but got int',)
-l[:] = [{u"\0" : 1}]:TypeError:('expected string without null bytes',)
-l[:] = [{"\0" : 1}]:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using l[:] = [{"abcF" : {%s : 1}}]
-l[:] = [{"abcF" : {1 : 1}}]:TypeError:('expected str() or unicode() instance, but got int',)
-l[:] = [{"abcF" : {u"\0" : 1}}]:TypeError:('expected string without null bytes',)
-l[:] = [{"abcF" : {"\0" : 1}}]:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using l[:] = [{"abcF" : Mapping({%s : 1})}]
-l[:] = [{"abcF" : Mapping({1 : 1})}]:TypeError:('expected str() or unicode() instance, but got int',)
-l[:] = [{"abcF" : Mapping({u"\0" : 1})}]:TypeError:('expected string without null bytes',)
-l[:] = [{"abcF" : Mapping({"\0" : 1})}]:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using l[:] = [{"abcF" : %s}]
-l[:] = [{"abcF" : FailingIter()}]:TypeError:('unable to convert FailingIter to vim structure',)
-l[:] = [{"abcF" : FailingIterNext()}]:NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using l[:] = [{"abcF" : %s}]
-l[:] = [{"abcF" : None}]:TypeError:('unable to convert NoneType to vim structure',)
-l[:] = [{"abcF" : {"": 1}}]:ValueError:('empty keys are not allowed',)
-l[:] = [{"abcF" : {u"": 1}}]:ValueError:('empty keys are not allowed',)
-l[:] = [{"abcF" : FailingMapping()}]:NotImplementedError:('keys',)
-l[:] = [{"abcF" : FailingMappingKey()}]:NotImplementedError:('getitem:mappingkey',)
-l[:] = [{"abcF" : FailingNumber()}]:TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using l[:] = [Mapping({%s : 1})]
-l[:] = [Mapping({1 : 1})]:TypeError:('expected str() or unicode() instance, but got int',)
-l[:] = [Mapping({u"\0" : 1})]:TypeError:('expected string without null bytes',)
-l[:] = [Mapping({"\0" : 1})]:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using l[:] = [Mapping({"abcG" : {%s : 1}})]
-l[:] = [Mapping({"abcG" : {1 : 1}})]:TypeError:('expected str() or unicode() instance, but got int',)
-l[:] = [Mapping({"abcG" : {u"\0" : 1}})]:TypeError:('expected string without null bytes',)
-l[:] = [Mapping({"abcG" : {"\0" : 1}})]:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using l[:] = [Mapping({"abcG" : Mapping({%s : 1})})]
-l[:] = [Mapping({"abcG" : Mapping({1 : 1})})]:TypeError:('expected str() or unicode() instance, but got int',)
-l[:] = [Mapping({"abcG" : Mapping({u"\0" : 1})})]:TypeError:('expected string without null bytes',)
-l[:] = [Mapping({"abcG" : Mapping({"\0" : 1})})]:TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using l[:] = [Mapping({"abcG" : %s})]
-l[:] = [Mapping({"abcG" : FailingIter()})]:TypeError:('unable to convert FailingIter to vim structure',)
-l[:] = [Mapping({"abcG" : FailingIterNext()})]:NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using l[:] = [Mapping({"abcG" : %s})]
-l[:] = [Mapping({"abcG" : None})]:TypeError:('unable to convert NoneType to vim structure',)
-l[:] = [Mapping({"abcG" : {"": 1}})]:ValueError:('empty keys are not allowed',)
-l[:] = [Mapping({"abcG" : {u"": 1}})]:ValueError:('empty keys are not allowed',)
-l[:] = [Mapping({"abcG" : FailingMapping()})]:NotImplementedError:('keys',)
-l[:] = [Mapping({"abcG" : FailingMappingKey()})]:NotImplementedError:('getitem:mappingkey',)
-l[:] = [Mapping({"abcG" : FailingNumber()})]:TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing *Iter* using l[:] = [%s]
-l[:] = [FailingIter()]:TypeError:('unable to convert FailingIter to vim structure',)
-l[:] = [FailingIterNext()]:NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using l[:] = [%s]
-l[:] = [None]:TypeError:('unable to convert NoneType to vim structure',)
-l[:] = [{"": 1}]:ValueError:('empty keys are not allowed',)
-l[:] = [{u"": 1}]:ValueError:('empty keys are not allowed',)
-l[:] = [FailingMapping()]:NotImplementedError:('keys',)
-l[:] = [FailingMappingKey()]:NotImplementedError:('getitem:mappingkey',)
-l[:] = [FailingNumber()]:TypeError:('long() argument must be a string or a number',)
-<<< Finished
->> ListConcatInPlace
->>> Testing *Iter* using l.extend(%s)
-l.extend(FailingIter()):NotImplementedError:('iter',)
-l.extend(FailingIterNext()):NotImplementedError:('next',)
-<<< Finished
->>> Testing StringToChars using l.extend([{%s : 1}])
-l.extend([{1 : 1}]):TypeError:('expected str() or unicode() instance, but got int',)
-l.extend([{u"\0" : 1}]):TypeError:('expected string without null bytes',)
-l.extend([{"\0" : 1}]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using l.extend([{"abcF" : {%s : 1}}])
-l.extend([{"abcF" : {1 : 1}}]):TypeError:('expected str() or unicode() instance, but got int',)
-l.extend([{"abcF" : {u"\0" : 1}}]):TypeError:('expected string without null bytes',)
-l.extend([{"abcF" : {"\0" : 1}}]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using l.extend([{"abcF" : Mapping({%s : 1})}])
-l.extend([{"abcF" : Mapping({1 : 1})}]):TypeError:('expected str() or unicode() instance, but got int',)
-l.extend([{"abcF" : Mapping({u"\0" : 1})}]):TypeError:('expected string without null bytes',)
-l.extend([{"abcF" : Mapping({"\0" : 1})}]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using l.extend([{"abcF" : %s}])
-l.extend([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to vim structure',)
-l.extend([{"abcF" : FailingIterNext()}]):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using l.extend([{"abcF" : %s}])
-l.extend([{"abcF" : None}]):TypeError:('unable to convert NoneType to vim structure',)
-l.extend([{"abcF" : {"": 1}}]):ValueError:('empty keys are not allowed',)
-l.extend([{"abcF" : {u"": 1}}]):ValueError:('empty keys are not allowed',)
-l.extend([{"abcF" : FailingMapping()}]):NotImplementedError:('keys',)
-l.extend([{"abcF" : FailingMappingKey()}]):NotImplementedError:('getitem:mappingkey',)
-l.extend([{"abcF" : FailingNumber()}]):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using l.extend([Mapping({%s : 1})])
-l.extend([Mapping({1 : 1})]):TypeError:('expected str() or unicode() instance, but got int',)
-l.extend([Mapping({u"\0" : 1})]):TypeError:('expected string without null bytes',)
-l.extend([Mapping({"\0" : 1})]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using l.extend([Mapping({"abcG" : {%s : 1}})])
-l.extend([Mapping({"abcG" : {1 : 1}})]):TypeError:('expected str() or unicode() instance, but got int',)
-l.extend([Mapping({"abcG" : {u"\0" : 1}})]):TypeError:('expected string without null bytes',)
-l.extend([Mapping({"abcG" : {"\0" : 1}})]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using l.extend([Mapping({"abcG" : Mapping({%s : 1})})])
-l.extend([Mapping({"abcG" : Mapping({1 : 1})})]):TypeError:('expected str() or unicode() instance, but got int',)
-l.extend([Mapping({"abcG" : Mapping({u"\0" : 1})})]):TypeError:('expected string without null bytes',)
-l.extend([Mapping({"abcG" : Mapping({"\0" : 1})})]):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using l.extend([Mapping({"abcG" : %s})])
-l.extend([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to vim structure',)
-l.extend([Mapping({"abcG" : FailingIterNext()})]):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using l.extend([Mapping({"abcG" : %s})])
-l.extend([Mapping({"abcG" : None})]):TypeError:('unable to convert NoneType to vim structure',)
-l.extend([Mapping({"abcG" : {"": 1}})]):ValueError:('empty keys are not allowed',)
-l.extend([Mapping({"abcG" : {u"": 1}})]):ValueError:('empty keys are not allowed',)
-l.extend([Mapping({"abcG" : FailingMapping()})]):NotImplementedError:('keys',)
-l.extend([Mapping({"abcG" : FailingMappingKey()})]):NotImplementedError:('getitem:mappingkey',)
-l.extend([Mapping({"abcG" : FailingNumber()})]):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing *Iter* using l.extend([%s])
-l.extend([FailingIter()]):TypeError:('unable to convert FailingIter to vim structure',)
-l.extend([FailingIterNext()]):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using l.extend([%s])
-l.extend([None]):TypeError:('unable to convert NoneType to vim structure',)
-l.extend([{"": 1}]):ValueError:('empty keys are not allowed',)
-l.extend([{u"": 1}]):ValueError:('empty keys are not allowed',)
-l.extend([FailingMapping()]):NotImplementedError:('keys',)
-l.extend([FailingMappingKey()]):NotImplementedError:('getitem:mappingkey',)
-l.extend([FailingNumber()]):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->> ListSetattr
-del l.locked:AttributeError:('cannot delete vim.List attributes',)
-l.locked = FailingTrue():NotImplementedError:('bool',)
-l.xxx = True:AttributeError:('cannot set attribute xxx',)
-> Function
->> FunctionConstructor
-vim.Function("123"):ValueError:('unnamed function 123 does not exist',)
-vim.Function("xxx_non_existent_function_xxx"):ValueError:('function xxx_non_existent_function_xxx does not exist',)
-vim.Function("xxx#non#existent#function#xxx"):NOT FAILED
->> FunctionCall
->>> Testing StringToChars using f({%s : 1})
-f({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',)
-f({u"\0" : 1}):TypeError:('expected string without null bytes',)
-f({"\0" : 1}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using f({"abcF" : {%s : 1}})
-f({"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',)
-f({"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',)
-f({"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using f({"abcF" : Mapping({%s : 1})})
-f({"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',)
-f({"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',)
-f({"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using f({"abcF" : %s})
-f({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',)
-f({"abcF" : FailingIterNext()}):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using f({"abcF" : %s})
-f({"abcF" : None}):TypeError:('unable to convert NoneType to vim structure',)
-f({"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',)
-f({"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',)
-f({"abcF" : FailingMapping()}):NotImplementedError:('keys',)
-f({"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',)
-f({"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using f(Mapping({%s : 1}))
-f(Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',)
-f(Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',)
-f(Mapping({"\0" : 1})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using f(Mapping({"abcG" : {%s : 1}}))
-f(Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',)
-f(Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',)
-f(Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using f(Mapping({"abcG" : Mapping({%s : 1})}))
-f(Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',)
-f(Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',)
-f(Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using f(Mapping({"abcG" : %s}))
-f(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',)
-f(Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using f(Mapping({"abcG" : %s}))
-f(Mapping({"abcG" : None})):TypeError:('unable to convert NoneType to vim structure',)
-f(Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',)
-f(Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',)
-f(Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',)
-f(Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',)
-f(Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing *Iter* using f(%s)
-f(FailingIter()):TypeError:('unable to convert FailingIter to vim structure',)
-f(FailingIterNext()):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using f(%s)
-f(None):TypeError:('unable to convert NoneType to vim structure',)
-f({"": 1}):ValueError:('empty keys are not allowed',)
-f({u"": 1}):ValueError:('empty keys are not allowed',)
-f(FailingMapping()):NotImplementedError:('keys',)
-f(FailingMappingKey()):NotImplementedError:('getitem:mappingkey',)
-f(FailingNumber()):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using fd(self={%s : 1})
-fd(self={1 : 1}):TypeError:('expected str() or unicode() instance, but got int',)
-fd(self={u"\0" : 1}):TypeError:('expected string without null bytes',)
-fd(self={"\0" : 1}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using fd(self={"abcF" : {%s : 1}})
-fd(self={"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',)
-fd(self={"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',)
-fd(self={"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using fd(self={"abcF" : Mapping({%s : 1})})
-fd(self={"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',)
-fd(self={"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',)
-fd(self={"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using fd(self={"abcF" : %s})
-fd(self={"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',)
-fd(self={"abcF" : FailingIterNext()}):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using fd(self={"abcF" : %s})
-fd(self={"abcF" : None}):TypeError:('unable to convert NoneType to vim structure',)
-fd(self={"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',)
-fd(self={"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',)
-fd(self={"abcF" : FailingMapping()}):NotImplementedError:('keys',)
-fd(self={"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',)
-fd(self={"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing StringToChars using fd(self=Mapping({%s : 1}))
-fd(self=Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',)
-fd(self=Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',)
-fd(self=Mapping({"\0" : 1})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using fd(self=Mapping({"abcG" : {%s : 1}}))
-fd(self=Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',)
-fd(self=Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',)
-fd(self=Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing StringToChars using fd(self=Mapping({"abcG" : Mapping({%s : 1})}))
-fd(self=Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',)
-fd(self=Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',)
-fd(self=Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',)
-<<< Finished
->>> Testing *Iter* using fd(self=Mapping({"abcG" : %s}))
-fd(self=Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',)
-fd(self=Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',)
-<<< Finished
->>> Testing ConvertFromPyObject using fd(self=Mapping({"abcG" : %s}))
-fd(self=Mapping({"abcG" : None})):TypeError:('unable to convert NoneType to vim structure',)
-fd(self=Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',)
-fd(self=Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',)
-fd(self=Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',)
-fd(self=Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',)
-fd(self=Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',)
-<<< Finished
->>> Testing *Iter* using fd(self=%s)
-fd(self=FailingIter()):TypeError:('unable to convert FailingIter to vim dictionary',)
-fd(self=FailingIterNext()):TypeError:('unable to convert FailingIterNext to vim dictionary',)
-<<< Finished
->>> Testing ConvertFromPyObject using fd(self=%s)
-fd(self=None):TypeError:('unable to convert NoneType to vim dictionary',)
-fd(self={"": 1}):ValueError:('empty keys are not allowed',)
-fd(self={u"": 1}):ValueError:('empty keys are not allowed',)
-fd(self=FailingMapping()):NotImplementedError:('keys',)
-fd(self=FailingMappingKey()):NotImplementedError:('getitem:mappingkey',)
-fd(self=FailingNumber()):TypeError:('unable to convert FailingNumber to vim dictionary',)
-<<< Finished
->>> Testing ConvertFromPyMapping using fd(self=%s)
-fd(self=[]):TypeError:('unable to convert list to vim dictionary',)
-<<< Finished
-> TabPage
->> TabPageAttr
-vim.current.tabpage.xxx:AttributeError:('xxx',)
-> TabList
->> TabListItem
-vim.tabpages[1000]:IndexError:('no such tab page',)
-> Window
->> WindowAttr
-vim.current.window.xxx:AttributeError:('xxx',)
->> WindowSetattr
-vim.current.window.buffer = 0:TypeError:('readonly attribute: buffer',)
-vim.current.window.cursor = (100000000, 100000000):error:('cursor position outside buffer',)
-vim.current.window.cursor = True:TypeError:('argument must be 2-item sequence, not bool',)
->>> Testing NumberToLong using vim.current.window.height = %s
-vim.current.window.height = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
-vim.current.window.height = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
-vim.current.window.height = -1:ValueError:('number must be greater or equal to zero',)
-<<< Finished
->>> Testing NumberToLong using vim.current.window.width = %s
-vim.current.window.width = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
-vim.current.window.width = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
-vim.current.window.width = -1:ValueError:('number must be greater or equal to zero',)
-<<< Finished
-vim.current.window.xxxxxx = True:AttributeError:('xxxxxx',)
-> WinList
->> WinListItem
-vim.windows[1000]:IndexError:('no such window',)
-> Buffer
->> StringToLine (indirect)
-vim.current.buffer[0] = u"\na":error:('string cannot contain newlines',)
-vim.current.buffer[0] = "\na":error:('string cannot contain newlines',)
->> SetBufferLine (indirect)
-vim.current.buffer[0] = True:TypeError:('bad argument type for built-in operation',)
->> SetBufferLineList (indirect)
-vim.current.buffer[:] = True:TypeError:('bad argument type for built-in operation',)
-vim.current.buffer[:] = ["\na", "bc"]:error:('string cannot contain newlines',)
->> InsertBufferLines (indirect)
-vim.current.buffer.append(None):TypeError:('bad argument type for built-in operation',)
-vim.current.buffer.append(["\na", "bc"]):error:('string cannot contain newlines',)
-vim.current.buffer.append("\nbc"):error:('string cannot contain newlines',)
->> RBItem
-vim.current.buffer[100000000]:IndexError:('line number out of range',)
->> RBAsItem
-vim.current.buffer[100000000] = "":IndexError:('line number out of range',)
->> BufferAttr
-vim.current.buffer.xxx:AttributeError:('xxx',)
->> BufferSetattr
-vim.current.buffer.name = True:TypeError:('expected str() or unicode() instance, but got bool',)
-vim.current.buffer.xxx = True:AttributeError:('xxx',)
->> BufferMark
-vim.current.buffer.mark(0):TypeError:('expected str() or unicode() instance, but got int',)
-vim.current.buffer.mark("abcM"):ValueError:('mark name must be a single character',)
-vim.current.buffer.mark("!"):error:('invalid mark name',)
->> BufferRange
-vim.current.buffer.range(1, 2, 3):TypeError:('function takes exactly 2 arguments (3 given)',)
-> BufMap
->> BufMapItem
-vim.buffers[100000000]:KeyError:(100000000,)
->>> Testing NumberToLong using vim.buffers[%s]
-vim.buffers[[]]:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
-vim.buffers[None]:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
-vim.buffers[-1]:ValueError:('number must be greater then zero',)
-vim.buffers[0]:ValueError:('number must be greater then zero',)
-<<< Finished
-> Current
->> CurrentGetattr
-vim.current.xxx:AttributeError:('xxx',)
->> CurrentSetattr
-vim.current.line = True:TypeError:('bad argument type for built-in operation',)
-vim.current.buffer = True:TypeError:('expected vim.Buffer object, but got bool',)
-vim.current.window = True:TypeError:('expected vim.Window object, but got bool',)
-vim.current.tabpage = True:TypeError:('expected vim.TabPage object, but got bool',)
-vim.current.xxx = True:AttributeError:('xxx',)
-['/testdir']
-'/testdir'
-2,xx
-before
-after
-pythonx/topmodule/__init__.py
-pythonx/topmodule/submodule/__init__.py
-pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py
-vim.command("throw 'abcN'"):error:('abcN',)
-Exe("throw 'def'"):error:('def',)
-vim.eval("Exe('throw ''ghi''')"):error:('ghi',)
-vim.eval("Exe('echoerr ''jkl''')"):error:('Vim(echoerr):jkl',)
-vim.eval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)
-vim.eval("xxx_unknown_function_xxx()"):error:('Vim:E117: Unknown function: xxx_unknown_function_xxx',)
-vim.bindeval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)
-Caught KeyboardInterrupt
-Running :put
-No exception
-
diff --git a/src/nvim/testdir/test87.in b/src/nvim/testdir/test87.in
deleted file mode 100644
index 58f9ac6418..0000000000
--- a/src/nvim/testdir/test87.in
+++ /dev/null
@@ -1,1402 +0,0 @@
-Tests for various python features. vim: set ft=vim :
-
-This test is not run in Neovim(see the has('nvim') check below) because the
-python3 compatibility layer is not complete.
-
-STARTTEST
-:so small.vim
-:set noswapfile
-:if !has('python3') || has('nvim') | e! test.ok | wq! test.out | endif
-:lang C
-:fun Test()
-:py3 import vim
-:let l = []
-:py3 l=vim.bindeval('l')
-:py3 f=vim.bindeval('function("strlen")')
-:" Extending List directly with different types
-:py3 l+=[1, "as'd", [1, 2, f, {'a': 1}]]
-:$put =string(l)
-:$put =string(l[-1])
-:try
-: $put =string(l[-4])
-:catch
-: $put =v:exception[:13]
-:endtry
-:" List assignment
-:py3 l[0]=0
-:$put =string(l)
-:py3 l[-2]=f
-:$put =string(l)
-:"
-:" Extending Dictionary directly with different types
-:let d = {}
-:fun d.f()
-: return 1
-:endfun
-py3 << EOF
-d=vim.bindeval('d')
-d['1']='asd'
-d.update(b=[1, 2, f])
-d.update((('-1', {'a': 1}),))
-d.update({'0': -1})
-dk = d.keys()
-dv = d.values()
-di = d.items()
-dk.sort(key=repr)
-dv.sort(key=repr)
-di.sort(key=repr)
-EOF
-:$put =py3eval('d[''f''](self={})')
-:$put =py3eval('repr(dk)')
-:$put =substitute(py3eval('repr(dv)'),'0x\x\+','','g')
-:$put =substitute(py3eval('repr(di)'),'0x\x\+','','g')
-:for [key, Val] in sort(items(d))
-: $put =string(key) . ' : ' . string(Val)
-: unlet key Val
-:endfor
-:py3 del dk
-:py3 del di
-:py3 del dv
-:"
-:" removing items with del
-:py3 del l[2]
-:$put =string(l)
-:let l = range(8)
-:py3 l=vim.bindeval('l')
-:try
-: py3 del l[:3]
-: py3 del l[1:]
-:catch
-: $put =v:exception
-:endtry
-:$put =string(l)
-:"
-:py3 del d['-1']
-:py3 del d['f']
-:$put =string(py3eval('d.get(''b'', 1)'))
-:$put =string(py3eval('d.pop(''b'')'))
-:$put =string(py3eval('d.get(''b'', 1)'))
-:$put =string(py3eval('d.pop(''1'', 2)'))
-:$put =string(py3eval('d.pop(''1'', 2)'))
-:$put =py3eval('repr(d.has_key(''0''))')
-:$put =py3eval('repr(d.has_key(''1''))')
-:$put =py3eval('repr(''0'' in d)')
-:$put =py3eval('repr(''1'' in d)')
-:$put =py3eval('repr(list(iter(d)))')
-:$put =string(d)
-:$put =py3eval('repr(d.popitem())')
-:$put =py3eval('repr(d.get(''0''))')
-:$put =py3eval('repr(list(iter(d)))')
-:"
-:" removing items out of range: silently skip items that don't exist
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:" The following two ranges delete nothing as they match empty list:
-:py3 del l[2:1]
-:$put =string(l)
-:py3 del l[2:2]
-:$put =string(l)
-:py3 del l[2:3]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[2:4]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[2:5]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[2:6]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:" The following two ranges delete nothing as they match empty list:
-:py3 del l[-1:2]
-:$put =string(l)
-:py3 del l[-2:2]
-:$put =string(l)
-:py3 del l[-3:2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[-4:2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[-5:2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[-6:2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[::2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[3:0:-2]
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 del l[2:4:-2]
-:$put =string(l)
-:"
-:" Slice assignment to a list
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 l[0:0]=['a']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 l[1:2]=['b']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 l[2:4]=['c']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 l[4:4]=['d']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 l[-1:2]=['e']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 l[-10:2]=['f']
-:$put =string(l)
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:py3 l[2:-10]=['g']
-:$put =string(l)
-:let l = []
-:py3 l=vim.bindeval('l')
-:py3 l[0:0]=['h']
-:$put =string(l)
-:let l = range(8)
-:py3 l=vim.bindeval('l')
-:py3 l[2:6:2] = [10, 20]
-:$put =string(l)
-:let l = range(8)
-:py3 l=vim.bindeval('l')
-:py3 l[6:2:-2] = [10, 20]
-:$put =string(l)
-:let l = range(8)
-:py3 l=vim.bindeval('l')
-:py3 l[6:2] = ()
-:$put =string(l)
-:let l = range(8)
-:py3 l=vim.bindeval('l')
-:py3 l[6:2:1] = ()
-:$put =string(l)
-:let l = range(8)
-:py3 l=vim.bindeval('l')
-:py3 l[2:2:1] = ()
-:$put =string(l)
-:"
-:" Locked variables
-:let l = [0, 1, 2, 3]
-:py3 l=vim.bindeval('l')
-:lockvar! l
-:py3 l[2]='i'
-:$put =string(l)
-:unlockvar! l
-:"
-:" Function calls
-py3 << EOF
-import sys
-import re
-
-py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional argument but (\d+) were given$')
-
-def ee(expr, g=globals(), l=locals()):
- cb = vim.current.buffer
- try:
- try:
- exec(expr, g, l)
- except Exception as e:
- if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."):
- cb.append(expr + ':' + repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))))
- elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0:
- cb.append(expr + ':' + repr((e.__class__, ImportError(str(e).replace("'", '')))))
- elif sys.version_info >= (3, 3) and e.__class__ is TypeError:
- m = py33_type_error_pattern.search(str(e))
- if m:
- msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2))
- cb.append(expr + ':' + repr((e.__class__, TypeError(msg))))
- else:
- cb.append(expr + ':' + repr((e.__class__, e)))
- else:
- cb.append(expr + ':' + repr((e.__class__, e)))
- else:
- cb.append(expr + ':NOT FAILED')
- except Exception as e:
- cb.append(expr + '::' + repr((e.__class__, e)))
-EOF
-:fun New(...)
-: return ['NewStart']+a:000+['NewEnd']
-:endfun
-:fun DictNew(...) dict
-: return ['DictNewStart']+a:000+['DictNewEnd', self]
-:endfun
-:let l=[function('New'), function('DictNew')]
-:py3 l=vim.bindeval('l')
-:py3 l.extend(list(l[0](1, 2, 3)))
-:$put =string(l)
-:py3 l.extend(list(l[1](1, 2, 3, self={'a': 'b'})))
-:$put =string(l)
-:py3 l+=[l[0].name]
-:$put =string(l)
-:py3 ee('l[1](1, 2, 3)')
-:py3 f=l[0]
-:delfunction New
-:py3 ee('f(1, 2, 3)')
-:let l=[0.0]
-:py3 l=vim.bindeval('l')
-:py3 l.extend([0.0])
-:$put =string(l)
-:let messages=[]
-:delfunction DictNew
-py3 <<EOF
-d=vim.bindeval('{}')
-m=vim.bindeval('messages')
-def em(expr, g=globals(), l=locals()):
- try:
- exec(expr, g, l)
- except Exception as e:
- m.extend([e.__class__.__name__])
-
-em('d["abc1"]')
-em('d["abc1"]="\\0"')
-em('d["abc1"]=vim')
-em('d[""]=1')
-em('d["a\\0b"]=1')
-em('d[b"a\\0b"]=1')
-
-em('d.pop("abc1")')
-em('d.popitem()')
-del em
-del m
-EOF
-:$put =messages
-:unlet messages
-:" locked and scope attributes
-:let d={} | let dl={} | lockvar dl
-:for s in split("d dl v: g:")
-: let name=tr(s, ':', 's')
-: execute 'py3 '.name.'=vim.bindeval("'.s.'")'
-: let toput=s.' : '.join(map(['locked', 'scope'], 'v:val.":".py3eval(name.".".v:val)'), ';')
-: $put =toput
-:endfor
-:silent! let d.abc2=1
-:silent! let dl.abc3=1
-:py3 d.locked=True
-:py3 dl.locked=False
-:silent! let d.def=1
-:silent! let dl.def=1
-:put ='d:'.string(d)
-:put ='dl:'.string(dl)
-:unlet d dl
-:
-:let l=[] | let ll=[] | lockvar ll
-:for s in split("l ll")
-: let name=tr(s, ':', 's')
-: execute 'py3 '.name.'=vim.bindeval("'.s.'")'
-: let toput=s.' : locked:'.py3eval(name.'.locked')
-: $put =toput
-:endfor
-:silent! call extend(l, [0])
-:silent! call extend(ll, [0])
-:py3 l.locked=True
-:py3 ll.locked=False
-:silent! call extend(l, [1])
-:silent! call extend(ll, [1])
-:put ='l:'.string(l)
-:put ='ll:'.string(ll)
-:unlet l ll
-:"
-:" py3eval()
-:let l=py3eval('[0, 1, 2]')
-:$put =string(l)
-:let d=py3eval('{"a": "b", "c": 1, "d": ["e"]}')
-:$put =sort(items(d))
-:let f=py3eval('0.0')
-:$put =string(f)
-:" Invalid values:
-:for e in ['"\0"', '{"\0": 1}', 'undefined_name', 'vim']
-: try
-: let v=py3eval(e)
-: catch
-: let toput=e.":\t".v:exception[:13]
-: $put =toput
-: endtry
-:endfor
-:"
-:" threading
-:let l = [0]
-:py3 l=vim.bindeval('l')
-py3 <<EOF
-import threading
-import time
-
-class T(threading.Thread):
- def __init__(self):
- threading.Thread.__init__(self)
- self.t = 0
- self.running = True
-
- def run(self):
- while self.running:
- self.t += 1
- time.sleep(0.1)
-
-t = T()
-del T
-t.start()
-EOF
-:sleep 1
-:py3 t.running = False
-:py3 t.join()
-:py3 l[0] = t.t > 8 # check if the background thread is working
-:py3 del time
-:py3 del threading
-:py3 del t
-:$put =string(l)
-:"
-:" settrace
-:let l = []
-:py3 l=vim.bindeval('l')
-py3 <<EOF
-import sys
-
-def traceit(frame, event, arg):
- global l
- if event == "line":
- l += [frame.f_lineno]
- return traceit
-
-def trace_main():
- for i in range(5):
- pass
-EOF
-:py3 sys.settrace(traceit)
-:py3 trace_main()
-:py3 sys.settrace(None)
-:py3 del traceit
-:py3 del trace_main
-:$put =string(l)
-:"
-:" Slice
-:py3 ll = vim.bindeval('[0, 1, 2, 3, 4, 5]')
-:py3 l = ll[:4]
-:$put =string(py3eval('l'))
-:py3 l = ll[2:]
-:$put =string(py3eval('l'))
-:py3 l = ll[:-4]
-:$put =string(py3eval('l'))
-:py3 l = ll[-2:]
-:$put =string(py3eval('l'))
-:py3 l = ll[2:4]
-:$put =string(py3eval('l'))
-:py3 l = ll[4:2]
-:$put =string(py3eval('l'))
-:py3 l = ll[-4:-2]
-:$put =string(py3eval('l'))
-:py3 l = ll[-2:-4]
-:$put =string(py3eval('l'))
-:py3 l = ll[:]
-:$put =string(py3eval('l'))
-:py3 l = ll[0:6]
-:$put =string(py3eval('l'))
-:py3 l = ll[-10:10]
-:$put =string(py3eval('l'))
-:py3 l = ll[4:2:-1]
-:$put =string(py3eval('l'))
-:py3 l = ll[::2]
-:$put =string(py3eval('l'))
-:py3 l = ll[4:2:1]
-:$put =string(py3eval('l'))
-:py3 del l
-:"
-:" Vars
-:let g:foo = 'bac'
-:let w:abc3 = 'def'
-:let b:baz = 'bar'
-:let t:bar = 'jkl'
-:try
-: throw "Abc"
-:catch
-: put =py3eval('vim.vvars[''exception'']')
-:endtry
-:put =py3eval('vim.vars[''foo'']')
-:put =py3eval('vim.current.window.vars[''abc3'']')
-:put =py3eval('vim.current.buffer.vars[''baz'']')
-:put =py3eval('vim.current.tabpage.vars[''bar'']')
-:"
-:" Options
-:" paste: boolean, global
-:" previewheight number, global
-:" operatorfunc: string, global
-:" number: boolean, window-local
-:" numberwidth: number, window-local
-:" colorcolumn: string, window-local
-:" statusline: string, window-local/global
-:" autoindent: boolean, buffer-local
-:" shiftwidth: number, buffer-local
-:" omnifunc: string, buffer-local
-:" preserveindent: boolean, buffer-local/global
-:" path: string, buffer-local/global
-:let g:bufs=[bufnr('%')]
-:new
-:let g:bufs+=[bufnr('%')]
-:vnew
-:let g:bufs+=[bufnr('%')]
-:wincmd j
-:vnew
-:let g:bufs+=[bufnr('%')]
-:wincmd l
-:fun RecVars(opt)
-: let gval =string(eval('&g:'.a:opt))
-: let wvals=join(map(range(1, 4), 'v:val.":".string(getwinvar(v:val, "&".a:opt))'))
-: let bvals=join(map(copy(g:bufs), 'v:val.":".string(getbufvar(v:val, "&".a:opt))'))
-: put =' G: '.gval
-: put =' W: '.wvals
-: put =' B: '.wvals
-:endfun
-py3 << EOF
-def e(s, g=globals(), l=locals()):
- try:
- exec(s, g, l)
- except Exception as e:
- vim.command('return ' + repr(e.__class__.__name__))
-
-def ev(s, g=globals(), l=locals()):
- try:
- return eval(s, g, l)
- except Exception as e:
- vim.command('let exc=' + repr(e.__class__.__name__))
- return 0
-EOF
-:fun E(s)
-: python3 e(vim.eval('a:s'))
-:endfun
-:fun Ev(s)
-: let r=py3eval('ev(vim.eval("a:s"))')
-: if exists('exc')
-: throw exc
-: endif
-: return r
-:endfun
-:py3 gopts1=vim.options
-:py3 wopts1=vim.windows[2].options
-:py3 wopts2=vim.windows[0].options
-:py3 wopts3=vim.windows[1].options
-:py3 bopts1=vim.buffers[vim.bindeval("g:bufs")[2]].options
-:py3 bopts2=vim.buffers[vim.bindeval("g:bufs")[1]].options
-:py3 bopts3=vim.buffers[vim.bindeval("g:bufs")[0]].options
-:$put ='wopts iters equal: '.py3eval('list(wopts1) == list(wopts2)')
-:$put ='bopts iters equal: '.py3eval('list(bopts1) == list(bopts2)')
-:py3 gset=set(iter(gopts1))
-:py3 wset=set(iter(wopts1))
-:py3 bset=set(iter(bopts1))
-:set path=.,..,,
-:let lst=[]
-:let lst+=[['paste', 1, 0, 1, 2, 1, 1, 0 ]]
-:let lst+=[['previewheight', 5, 1, 6, 'a', 0, 1, 0 ]]
-:let lst+=[['operatorfunc', 'A', 'B', 'C', 2, 0, 1, 0 ]]
-:let lst+=[['number', 0, 1, 1, 0, 1, 0, 1 ]]
-:let lst+=[['numberwidth', 2, 3, 5, -100, 0, 0, 1 ]]
-:let lst+=[['colorcolumn', '+1', '+2', '+3', 'abc4', 0, 0, 1 ]]
-:let lst+=[['statusline', '1', '2', '4', 0, 0, 1, 1 ]]
-:let lst+=[['autoindent', 0, 1, 1, 2, 1, 0, 2 ]]
-:let lst+=[['shiftwidth', 0, 2, 1, 3, 0, 0, 2 ]]
-:let lst+=[['omnifunc', 'A', 'B', 'C', 1, 0, 0, 2 ]]
-:let lst+=[['preserveindent', 0, 1, 1, 2, 1, 1, 2 ]]
-:let lst+=[['path', '.,,', ',,', '.', 0, 0, 1, 2 ]]
-:for [oname, oval1, oval2, oval3, invval, bool, global, local] in lst
-: py3 oname=vim.eval('oname')
-: py3 oval1=vim.bindeval('oval1')
-: py3 oval2=vim.bindeval('oval2')
-: py3 oval3=vim.bindeval('oval3')
-: if invval is 0 || invval is 1
-: py3 invval=bool(vim.bindeval('invval'))
-: else
-: py3 invval=vim.bindeval('invval')
-: endif
-: if bool
-: py3 oval1=bool(oval1)
-: py3 oval2=bool(oval2)
-: py3 oval3=bool(oval3)
-: endif
-: put ='>>> '.oname
-: $put =' g/w/b:'.py3eval('oname in gset').'/'.py3eval('oname in wset').'/'.py3eval('oname in bset')
-: $put =' g/w/b (in):'.py3eval('oname in gopts1').'/'.py3eval('oname in wopts1').'/'.py3eval('oname in bopts1')
-: for v in ['gopts1', 'wopts1', 'bopts1']
-: try
-: put =' p/'.v.': '.Ev('repr('.v.'['''.oname.'''])')
-: catch
-: put =' p/'.v.'! '.v:exception
-: endtry
-: let r=E(v.'['''.oname.''']=invval')
-: if r isnot 0
-: put =' inv: '.string(invval).'! '.r
-: endif
-: for vv in (v is# 'gopts1' ? [v] : [v, v[:-2].'2', v[:-2].'3'])
-: let val=substitute(vv, '^.opts', 'oval', '')
-: let r=E(vv.'['''.oname.''']='.val)
-: if r isnot 0
-: put =' '.vv.'! '.r
-: endif
-: endfor
-: endfor
-: call RecVars(oname)
-: for v in ['wopts3', 'bopts3']
-: let r=E('del '.v.'["'.oname.'"]')
-: if r isnot 0
-: put =' del '.v.'! '.r
-: endif
-: endfor
-: call RecVars(oname)
-:endfor
-:delfunction RecVars
-:delfunction E
-:delfunction Ev
-:py3 del ev
-:py3 del e
-:only
-:for buf in g:bufs[1:]
-: execute 'bwipeout!' buf
-:endfor
-:py3 del gopts1
-:py3 del wopts1
-:py3 del wopts2
-:py3 del wopts3
-:py3 del bopts1
-:py3 del bopts2
-:py3 del bopts3
-:py3 del oval1
-:py3 del oval2
-:py3 del oval3
-:py3 del oname
-:py3 del invval
-:"
-:" Test buffer object
-:vnew
-:put ='First line'
-:put ='Second line'
-:put ='Third line'
-:1 delete _
-:py3 b=vim.current.buffer
-:wincmd w
-:mark a
-:augroup BUFS
-: autocmd BufFilePost * python3 cb.append(vim.eval('expand("<abuf>")') + ':BufFilePost:' + vim.eval('bufnr("%")'))
-: autocmd BufFilePre * python3 cb.append(vim.eval('expand("<abuf>")') + ':BufFilePre:' + vim.eval('bufnr("%")'))
-:augroup END
-py3 << EOF
-cb = vim.current.buffer
-# Tests BufferAppend and BufferItem
-cb.append(b[0])
-# Tests BufferSlice and BufferAssSlice
-cb.append('abc5') # Will be overwritten
-cb[-1:] = b[:-2]
-# Test BufferLength and BufferAssSlice
-cb.append('def') # Will not be overwritten
-cb[len(cb):] = b[:]
-# Test BufferAssItem and BufferMark
-cb.append('ghi') # Will be overwritten
-cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1]))
-# Test BufferRepr
-cb.append(repr(cb) + repr(b))
-# Modify foreign buffer
-b.append('foo')
-b[0]='bar'
-b[0:0]=['baz']
-vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number)
-# Test assigning to name property
-import os
-old_name = cb.name
-cb.name = 'foo'
-cb.append(cb.name[-11:].replace(os.path.sep, '/'))
-b.name = 'bar'
-cb.append(b.name[-11:].replace(os.path.sep, '/'))
-cb.name = old_name
-cb.append(cb.name[-17:].replace(os.path.sep, '/'))
-del old_name
-# Test CheckBuffer
-for _b in vim.buffers:
- if _b is not cb:
- vim.command('bwipeout! ' + str(_b.number))
-del _b
-cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid)))
-for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc6")'):
- try:
- exec(expr)
- except vim.error:
- pass
- else:
- # Usually a SEGV here
- # Should not happen in any case
- cb.append('No exception for ' + expr)
-vim.command('cd .')
-del b
-EOF
-:"
-:" Test vim.buffers object
-:set hidden
-:edit a
-:buffer #
-:edit b
-:buffer #
-:edit c
-:buffer #
-py3 << EOF
-# Check GCing iterator that was not fully exhausted
-i = iter(vim.buffers)
-cb.append('i:' + str(next(i)))
-# and also check creating more then one iterator at a time
-i2 = iter(vim.buffers)
-cb.append('i2:' + str(next(i2)))
-cb.append('i:' + str(next(i)))
-# The following should trigger GC and not cause any problems
-del i
-del i2
-i3 = iter(vim.buffers)
-cb.append('i3:' + str(next(i3)))
-del i3
-
-prevnum = 0
-for b in vim.buffers:
- # Check buffer order
- if prevnum >= b.number:
- cb.append('!!! Buffer numbers not in strictly ascending order')
- # Check indexing: vim.buffers[number].number == number
- cb.append(str(b.number) + ':' + repr(vim.buffers[b.number]) + '=' + repr(b))
- prevnum = b.number
-del prevnum
-
-cb.append(str(len(vim.buffers)))
-
-bnums = list(map(lambda b: b.number, vim.buffers))[1:]
-
-# Test wiping out buffer with existing iterator
-i4 = iter(vim.buffers)
-cb.append('i4:' + str(next(i4)))
-vim.command('bwipeout! ' + str(bnums.pop(0)))
-try:
- next(i4)
-except vim.error:
- pass
-else:
- cb.append('!!!! No vim.error')
-i4 = iter(vim.buffers)
-vim.command('bwipeout! ' + str(bnums.pop(-1)))
-vim.command('bwipeout! ' + str(bnums.pop(-1)))
-cb.append('i4:' + str(next(i4)))
-try:
- next(i4)
-except StopIteration:
- cb.append('StopIteration')
-del i4
-del bnums
-EOF
-:"
-:" Test vim.{tabpage,window}list and vim.{tabpage,window} objects
-:tabnew 0
-:tabnew 1
-:vnew a.1
-:tabnew 2
-:vnew a.2
-:vnew b.2
-:vnew c.2
-py3 << EOF
-cb.append('Number of tabs: ' + str(len(vim.tabpages)))
-cb.append('Current tab pages:')
-
-def W(w):
- if '(unknown)' in repr(w):
- return '<window object (unknown)>'
- else:
- return repr(w)
-
-def Cursor(w, start=len(cb)):
- if w.buffer is cb:
- return repr((start - w.cursor[0], w.cursor[1]))
- else:
- return repr(w.cursor)
-
-for t in vim.tabpages:
- cb.append(' ' + repr(t) + '(' + str(t.number) + ')' + ': ' + str(len(t.windows)) + ' windows, current is ' + W(t.window))
- cb.append(' Windows:')
- for w in t.windows:
- cb.append(' ' + W(w) + '(' + str(w.number) + ')' + ': displays buffer ' + repr(w.buffer) + '; cursor is at ' + Cursor(w))
- # Other values depend on the size of the terminal, so they are checked partly:
- for attr in ('height', 'row', 'width', 'col'):
- try:
- aval = getattr(w, attr)
- if type(aval) is not int:
- raise TypeError
- if aval < 0:
- raise ValueError
- except Exception as e:
- cb.append('!!!!!! Error while getting attribute ' + attr + ': ' + e.__class__.__name__)
- del aval
- del attr
- w.cursor = (len(w.buffer), 0)
-del W
-del Cursor
-cb.append('Number of windows in current tab page: ' + str(len(vim.windows)))
-if list(vim.windows) != list(vim.current.tabpage.windows):
- cb.append('!!!!!! Windows differ')
-EOF
-:"
-:" Test vim.current
-py3 << EOF
-def H(o):
- return repr(o)
-cb.append('Current tab page: ' + repr(vim.current.tabpage))
-cb.append('Current window: ' + repr(vim.current.window) + ': ' + H(vim.current.window) + ' is ' + H(vim.current.tabpage.window))
-cb.append('Current buffer: ' + repr(vim.current.buffer) + ': ' + H(vim.current.buffer) + ' is ' + H(vim.current.window.buffer)+ ' is ' + H(vim.current.tabpage.window.buffer))
-del H
-# Assigning: fails
-try:
- vim.current.window = vim.tabpages[0].window
-except ValueError:
- cb.append('ValueError at assigning foreign tab window')
-
-for attr in ('window', 'tabpage', 'buffer'):
- try:
- setattr(vim.current, attr, None)
- except TypeError:
- cb.append('Type error at assigning None to vim.current.' + attr)
-del attr
-
-# Assigning: success
-vim.current.tabpage = vim.tabpages[-2]
-vim.current.buffer = cb
-vim.current.window = vim.windows[0]
-vim.current.window.cursor = (len(vim.current.buffer), 0)
-cb.append('Current tab page: ' + repr(vim.current.tabpage))
-cb.append('Current window: ' + repr(vim.current.window))
-cb.append('Current buffer: ' + repr(vim.current.buffer))
-cb.append('Current line: ' + repr(vim.current.line))
-ws = list(vim.windows)
-ts = list(vim.tabpages)
-for b in vim.buffers:
- if b is not cb:
- vim.command('bwipeout! ' + str(b.number))
-del b
-cb.append('w.valid: ' + repr([w.valid for w in ws]))
-cb.append('t.valid: ' + repr([t.valid for t in ts]))
-del w
-del t
-del ts
-del ws
-EOF
-:tabonly!
-:only!
-:"
-:" Test types
-py3 << EOF
-for expr, attr in (
- ('vim.vars', 'Dictionary'),
- ('vim.options', 'Options'),
- ('vim.bindeval("{}")', 'Dictionary'),
- ('vim.bindeval("[]")', 'List'),
- ('vim.bindeval("function(\'tr\')")', 'Function'),
- ('vim.current.buffer', 'Buffer'),
- ('vim.current.range', 'Range'),
- ('vim.current.window', 'Window'),
- ('vim.current.tabpage', 'TabPage'),
-):
- cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr)))
-del expr
-del attr
-EOF
-:"
-:" Test __dir__() method
-py3 << EOF
-for name, o in (
- ('current', vim.current),
- ('buffer', vim.current.buffer),
- ('window', vim.current.window),
- ('tabpage', vim.current.tabpage),
- ('range', vim.current.range),
- ('dictionary', vim.bindeval('{}')),
- ('list', vim.bindeval('[]')),
- ('function', vim.bindeval('function("tr")')),
- ('output', sys.stdout),
- ):
- cb.append(name + ':' + ','.join(dir(o)))
-del name
-del o
-EOF
-:"
-:" Test vim.*.__new__
-:$put =string(py3eval('vim.Dictionary({})'))
-:$put =string(py3eval('vim.Dictionary(a=1)'))
-:$put =string(py3eval('vim.Dictionary(((''a'', 1),))'))
-:$put =string(py3eval('vim.List()'))
-:$put =string(py3eval('vim.List(iter(''abc7''))'))
-:$put =string(py3eval('vim.Function(''tr'')'))
-:"
-:" Test stdout/stderr
-:redir => messages
-:py3 sys.stdout.write('abc8') ; sys.stdout.write('def')
-:py3 sys.stderr.write('abc9') ; sys.stderr.write('def')
-:py3 sys.stdout.writelines(iter('abcA'))
-:py3 sys.stderr.writelines(iter('abcB'))
-:redir END
-:$put =string(substitute(messages, '\d\+', '', 'g'))
-:" Test subclassing
-:fun Put(...)
-: $put =string(a:000)
-: return a:000
-:endfun
-py3 << EOF
-class DupDict(vim.Dictionary):
- def __setitem__(self, key, value):
- super(DupDict, self).__setitem__(key, value)
- super(DupDict, self).__setitem__('dup_' + key, value)
-dd = DupDict()
-dd['a'] = 'b'
-
-class DupList(vim.List):
- def __getitem__(self, idx):
- return [super(DupList, self).__getitem__(idx)] * 2
-
-dl = DupList()
-dl2 = DupList(iter('abcC'))
-dl.extend(dl2[0])
-
-class DupFun(vim.Function):
- def __call__(self, arg):
- return super(DupFun, self).__call__(arg, arg)
-
-df = DupFun('Put')
-EOF
-:$put =string(sort(keys(py3eval('dd'))))
-:$put =string(py3eval('dl'))
-:$put =string(py3eval('dl2'))
-:$put =string(py3eval('df(2)'))
-:$put =string(py3eval('dl') is# py3eval('dl'))
-:$put =string(py3eval('dd') is# py3eval('dd'))
-:$put =string(py3eval('df'))
-:delfunction Put
-py3 << EOF
-del DupDict
-del DupList
-del DupFun
-del dd
-del dl
-del dl2
-del df
-EOF
-:"
-:" Test chdir
-py3 << EOF
-import os
-fnamemodify = vim.Function('fnamemodify')
-cb.append(str(fnamemodify('.', ':p:h:t')))
-cb.append(vim.eval('@%'))
-os.chdir('..')
-cb.append(str(fnamemodify('.', ':p:h:t')))
-cb.append(vim.eval('@%').replace(os.path.sep, '/'))
-os.chdir('testdir')
-cb.append(str(fnamemodify('.', ':p:h:t')))
-cb.append(vim.eval('@%'))
-del fnamemodify
-EOF
-:"
-:" Test errors
-:fun F() dict
-:endfun
-:fun D()
-:endfun
-py3 << EOF
-d = vim.Dictionary()
-ned = vim.Dictionary(foo='bar', baz='abcD')
-dl = vim.Dictionary(a=1)
-dl.locked = True
-l = vim.List()
-ll = vim.List('abcE')
-ll.locked = True
-nel = vim.List('abcO')
-f = vim.Function('string')
-fd = vim.Function('F')
-fdel = vim.Function('D')
-vim.command('delfunction D')
-
-def subexpr_test(expr, name, subexprs):
- cb.append('>>> Testing %s using %s' % (name, expr))
- for subexpr in subexprs:
- ee(expr % subexpr)
- cb.append('<<< Finished')
-
-def stringtochars_test(expr):
- return subexpr_test(expr, 'StringToChars', (
- '1', # Fail type checks
- 'b"\\0"', # Fail PyString_AsStringAndSize(object, , NULL) check
- '"\\0"', # Fail PyString_AsStringAndSize(bytes, , NULL) check
- ))
-
-class Mapping(object):
- def __init__(self, d):
- self.d = d
-
- def __getitem__(self, key):
- return self.d[key]
-
- def keys(self):
- return self.d.keys()
-
- def items(self):
- return self.d.items()
-
-def convertfrompyobject_test(expr, recurse=True):
- # pydict_to_tv
- stringtochars_test(expr % '{%s : 1}')
- if recurse:
- convertfrompyobject_test(expr % '{"abcF" : %s}', False)
- # pymap_to_tv
- stringtochars_test(expr % 'Mapping({%s : 1})')
- if recurse:
- convertfrompyobject_test(expr % 'Mapping({"abcG" : %s})', False)
- # pyseq_to_tv
- iter_test(expr)
- return subexpr_test(expr, 'ConvertFromPyObject', (
- 'None', # Not conversible
- '{b"": 1}', # Empty key not allowed
- '{"": 1}', # Same, but with unicode object
- 'FailingMapping()', #
- 'FailingMappingKey()', #
- 'FailingNumber()', #
- ))
-
-def convertfrompymapping_test(expr):
- convertfrompyobject_test(expr)
- return subexpr_test(expr, 'ConvertFromPyMapping', (
- '[]',
- ))
-
-def iter_test(expr):
- return subexpr_test(expr, '*Iter*', (
- 'FailingIter()',
- 'FailingIterNext()',
- ))
-
-def number_test(expr, natural=False, unsigned=False):
- if natural:
- unsigned = True
- return subexpr_test(expr, 'NumberToLong', (
- '[]',
- 'None',
- ) + (('-1',) if unsigned else ())
- + (('0',) if natural else ()))
-
-class FailingTrue(object):
- def __bool__(self):
- raise NotImplementedError('bool')
-
-class FailingIter(object):
- def __iter__(self):
- raise NotImplementedError('iter')
-
-class FailingIterNext(object):
- def __iter__(self):
- return self
-
- def __next__(self):
- raise NotImplementedError('next')
-
-class FailingIterNextN(object):
- def __init__(self, n):
- self.n = n
-
- def __iter__(self):
- return self
-
- def __next__(self):
- if self.n:
- self.n -= 1
- return 1
- else:
- raise NotImplementedError('next N')
-
-class FailingMappingKey(object):
- def __getitem__(self, item):
- raise NotImplementedError('getitem:mappingkey')
-
- def keys(self):
- return list("abcH")
-
-class FailingMapping(object):
- def __getitem__(self):
- raise NotImplementedError('getitem:mapping')
-
- def keys(self):
- raise NotImplementedError('keys')
-
-class FailingList(list):
- def __getitem__(self, idx):
- if i == 2:
- raise NotImplementedError('getitem:list')
- else:
- return super(FailingList, self).__getitem__(idx)
-
-class NoArgsCall(object):
- def __call__(self):
- pass
-
-class FailingCall(object):
- def __call__(self, path):
- raise NotImplementedError('call')
-
-class FailingNumber(object):
- def __int__(self):
- raise NotImplementedError('int')
-
-cb.append("> Output")
-cb.append(">> OutputSetattr")
-ee('del sys.stdout.softspace')
-number_test('sys.stdout.softspace = %s', unsigned=True)
-number_test('sys.stderr.softspace = %s', unsigned=True)
-ee('sys.stdout.attr = None')
-cb.append(">> OutputWrite")
-ee('sys.stdout.write(None)')
-cb.append(">> OutputWriteLines")
-ee('sys.stdout.writelines(None)')
-ee('sys.stdout.writelines([1])')
-iter_test('sys.stdout.writelines(%s)')
-cb.append("> VimCommand")
-stringtochars_test('vim.command(%s)')
-ee('vim.command("", 2)')
-#! Not checked: vim->python exceptions translating: checked later
-cb.append("> VimToPython")
-#! Not checked: everything: needs errors in internal python functions
-cb.append("> VimEval")
-stringtochars_test('vim.eval(%s)')
-ee('vim.eval("", FailingTrue())')
-#! Not checked: everything: needs errors in internal python functions
-cb.append("> VimEvalPy")
-stringtochars_test('vim.bindeval(%s)')
-ee('vim.eval("", 2)')
-#! Not checked: vim->python exceptions translating: checked later
-cb.append("> VimStrwidth")
-stringtochars_test('vim.strwidth(%s)')
-cb.append("> VimForeachRTP")
-ee('vim.foreach_rtp(None)')
-ee('vim.foreach_rtp(NoArgsCall())')
-ee('vim.foreach_rtp(FailingCall())')
-ee('vim.foreach_rtp(int, 2)')
-cb.append('> import')
-old_rtp = vim.options['rtp']
-vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
-ee('import xxx_no_such_module_xxx')
-ee('import failing_import')
-ee('import failing')
-vim.options['rtp'] = old_rtp
-del old_rtp
-cb.append("> Options")
-cb.append(">> OptionsItem")
-ee('vim.options["abcQ"]')
-ee('vim.options[""]')
-stringtochars_test('vim.options[%s]')
-cb.append(">> OptionsContains")
-stringtochars_test('%s in vim.options')
-cb.append("> Dictionary")
-cb.append(">> DictionaryConstructor")
-ee('vim.Dictionary("abcI")')
-##! Not checked: py_dict_alloc failure
-cb.append(">> DictionarySetattr")
-ee('del d.locked')
-ee('d.locked = FailingTrue()')
-ee('vim.vvars.locked = False')
-ee('d.scope = True')
-ee('d.xxx = True')
-cb.append(">> _DictionaryItem")
-ee('d.get("a", 2, 3)')
-stringtochars_test('d.get(%s)')
-ee('d.pop("a")')
-ee('dl.pop("a")')
-cb.append(">> DictionaryContains")
-ee('"" in d')
-ee('0 in d')
-cb.append(">> DictionaryIterNext")
-ee('for i in ned: ned["a"] = 1')
-del i
-cb.append(">> DictionaryAssItem")
-ee('dl["b"] = 1')
-stringtochars_test('d[%s] = 1')
-convertfrompyobject_test('d["a"] = %s')
-cb.append(">> DictionaryUpdate")
-cb.append(">>> kwargs")
-cb.append(">>> iter")
-ee('d.update(FailingMapping())')
-ee('d.update([FailingIterNext()])')
-ee('d.update([FailingIterNextN(1)])')
-iter_test('d.update(%s)')
-convertfrompyobject_test('d.update(%s)')
-stringtochars_test('d.update(((%s, 0),))')
-convertfrompyobject_test('d.update((("a", %s),))')
-cb.append(">> DictionaryPopItem")
-ee('d.popitem(1, 2)')
-cb.append(">> DictionaryHasKey")
-ee('d.has_key()')
-cb.append("> List")
-cb.append(">> ListConstructor")
-ee('vim.List(1, 2)')
-ee('vim.List(a=1)')
-iter_test('vim.List(%s)')
-convertfrompyobject_test('vim.List([%s])')
-cb.append(">> ListItem")
-ee('l[1000]')
-cb.append(">> ListAssItem")
-ee('ll[1] = 2')
-ee('l[1000] = 3')
-cb.append(">> ListAssSlice")
-ee('ll[1:100] = "abcJ"')
-iter_test('l[:] = %s')
-ee('nel[1:10:2] = "abcK"')
-cb.append(repr(tuple(nel)))
-ee('nel[1:10:2] = "a"')
-cb.append(repr(tuple(nel)))
-ee('nel[1:1:-1] = "a"')
-cb.append(repr(tuple(nel)))
-ee('nel[:] = FailingIterNextN(2)')
-cb.append(repr(tuple(nel)))
-convertfrompyobject_test('l[:] = [%s]')
-cb.append(">> ListConcatInPlace")
-iter_test('l.extend(%s)')
-convertfrompyobject_test('l.extend([%s])')
-cb.append(">> ListSetattr")
-ee('del l.locked')
-ee('l.locked = FailingTrue()')
-ee('l.xxx = True')
-cb.append("> Function")
-cb.append(">> FunctionConstructor")
-ee('vim.Function("123")')
-ee('vim.Function("xxx_non_existent_function_xxx")')
-ee('vim.Function("xxx#non#existent#function#xxx")')
-cb.append(">> FunctionCall")
-convertfrompyobject_test('f(%s)')
-convertfrompymapping_test('fd(self=%s)')
-cb.append("> TabPage")
-cb.append(">> TabPageAttr")
-ee('vim.current.tabpage.xxx')
-cb.append("> TabList")
-cb.append(">> TabListItem")
-ee('vim.tabpages[1000]')
-cb.append("> Window")
-cb.append(">> WindowAttr")
-ee('vim.current.window.xxx')
-cb.append(">> WindowSetattr")
-ee('vim.current.window.buffer = 0')
-ee('vim.current.window.cursor = (100000000, 100000000)')
-ee('vim.current.window.cursor = True')
-number_test('vim.current.window.height = %s', unsigned=True)
-number_test('vim.current.window.width = %s', unsigned=True)
-ee('vim.current.window.xxxxxx = True')
-cb.append("> WinList")
-cb.append(">> WinListItem")
-ee('vim.windows[1000]')
-cb.append("> Buffer")
-cb.append(">> StringToLine (indirect)")
-ee('vim.current.buffer[0] = "\\na"')
-ee('vim.current.buffer[0] = b"\\na"')
-cb.append(">> SetBufferLine (indirect)")
-ee('vim.current.buffer[0] = True')
-cb.append(">> SetBufferLineList (indirect)")
-ee('vim.current.buffer[:] = True')
-ee('vim.current.buffer[:] = ["\\na", "bc"]')
-cb.append(">> InsertBufferLines (indirect)")
-ee('vim.current.buffer.append(None)')
-ee('vim.current.buffer.append(["\\na", "bc"])')
-ee('vim.current.buffer.append("\\nbc")')
-cb.append(">> RBItem")
-ee('vim.current.buffer[100000000]')
-cb.append(">> RBAsItem")
-ee('vim.current.buffer[100000000] = ""')
-cb.append(">> BufferAttr")
-ee('vim.current.buffer.xxx')
-cb.append(">> BufferSetattr")
-ee('vim.current.buffer.name = True')
-ee('vim.current.buffer.xxx = True')
-cb.append(">> BufferMark")
-ee('vim.current.buffer.mark(0)')
-ee('vim.current.buffer.mark("abcM")')
-ee('vim.current.buffer.mark("!")')
-cb.append(">> BufferRange")
-ee('vim.current.buffer.range(1, 2, 3)')
-cb.append("> BufMap")
-cb.append(">> BufMapItem")
-ee('vim.buffers[100000000]')
-number_test('vim.buffers[%s]', natural=True)
-cb.append("> Current")
-cb.append(">> CurrentGetattr")
-ee('vim.current.xxx')
-cb.append(">> CurrentSetattr")
-ee('vim.current.line = True')
-ee('vim.current.buffer = True')
-ee('vim.current.window = True')
-ee('vim.current.tabpage = True')
-ee('vim.current.xxx = True')
-del d
-del ned
-del dl
-del l
-del ll
-del nel
-del f
-del fd
-del fdel
-del subexpr_test
-del stringtochars_test
-del Mapping
-del convertfrompyobject_test
-del convertfrompymapping_test
-del iter_test
-del number_test
-del FailingTrue
-del FailingIter
-del FailingIterNext
-del FailingIterNextN
-del FailingMapping
-del FailingMappingKey
-del FailingList
-del NoArgsCall
-del FailingCall
-del FailingNumber
-EOF
-:delfunction F
-:"
-:" Test import
-py3 << EOF
-sys.path.insert(0, os.path.join(os.getcwd(), 'python_before'))
-sys.path.append(os.path.join(os.getcwd(), 'python_after'))
-vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
-l = []
-def callback(path):
- l.append(os.path.relpath(path))
-vim.foreach_rtp(callback)
-cb.append(repr(l))
-del l
-def callback(path):
- return os.path.relpath(path)
-cb.append(repr(vim.foreach_rtp(callback)))
-del callback
-from module import dir as d
-from modulex import ddir
-cb.append(d + ',' + ddir)
-import before
-cb.append(before.dir)
-import after
-cb.append(after.dir)
-import topmodule as tm
-import topmodule.submodule as tms
-import topmodule.submodule.subsubmodule.subsubsubmodule as tmsss
-cb.append(tm.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/__init__.py'):])
-cb.append(tms.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/__init__.py'):])
-cb.append(tmsss.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/subsubmodule/subsubsubmodule.py'):])
-del before
-del after
-del d
-del ddir
-del tm
-del tms
-del tmsss
-EOF
-:"
-:" Test exceptions
-:fun Exe(e)
-: execute a:e
-:endfun
-py3 << EOF
-Exe = vim.bindeval('function("Exe")')
-ee('vim.command("throw \'abcN\'")')
-ee('Exe("throw \'def\'")')
-ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
-ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
-ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
-ee('vim.eval("xxx_unknown_function_xxx()")')
-ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
-del Exe
-EOF
-:delfunction Exe
-:"
-:" Regression: interrupting vim.command propagates to next vim.command
-py3 << EOF
-def test_keyboard_interrupt():
- try:
- vim.command('while 1 | endwhile')
- except KeyboardInterrupt:
- cb.append('Caught KeyboardInterrupt')
- except Exception as e:
- cb.append('!!!!!!!! Caught exception: ' + repr(e))
- else:
- cb.append('!!!!!!!! No exception')
- try:
- vim.command('$ put =\'Running :put\'')
- except KeyboardInterrupt:
- cb.append('!!!!!!!! Caught KeyboardInterrupt')
- except Exception as e:
- cb.append('!!!!!!!! Caught exception: ' + repr(e))
- else:
- cb.append('No exception')
-EOF
-:debuggreedy
-:call inputsave()
-:call feedkeys("s\ns\ns\ns\nq\n")
-:redir => output
-:debug silent! py3 test_keyboard_interrupt()
-:redir END
-:0 debuggreedy
-:call inputrestore()
-:silent $put =output
-:unlet output
-:py3 del test_keyboard_interrupt
-:"
-:" Cleanup
-py3 << EOF
-del cb
-del ee
-del sys
-del os
-del vim
-EOF
-:endfun
-:"
-:fun RunTest()
-:let checkrefs = !empty($PYTHONDUMPREFS)
-:let start = getline(1, '$')
-:for i in range(checkrefs ? 10 : 1)
-: if i != 0
-: %d _
-: call setline(1, start)
-: endif
-: call Test()
-: if i == 0
-: let result = getline(1, '$')
-: endif
-:endfor
-:if checkrefs
-: %d _
-: call setline(1, result)
-:endif
-:endfun
-:"
-:call RunTest()
-:delfunction RunTest
-:delfunction Test
-:call garbagecollect(1)
-:"
-:/^start:/,$wq! test.out
-:" vim: et ts=4 isk-=\:
-:call getchar()
-ENDTEST
-
-start:
diff --git a/src/nvim/testdir/test87.ok b/src/nvim/testdir/test87.ok
deleted file mode 100644
index d1ec84c6b8..0000000000
--- a/src/nvim/testdir/test87.ok
+++ /dev/null
@@ -1,1266 +0,0 @@
-start:
-[1, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
-[1, 2, function('strlen'), {'a': 1}]
-Vim(put):E684:
-[0, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
-[0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]]
-1
-[b'-1', b'0', b'1', b'b', b'f']
-[-1, <vim.Function '1'>, <vim.dictionary object at >, <vim.list object at >, b'asd']
-[(b'-1', <vim.dictionary object at >), (b'0', -1), (b'1', b'asd'), (b'b', <vim.list object at >), (b'f', <vim.Function '1'>)]
-'-1' : {'a': 1}
-'0' : -1
-'1' : 'asd'
-'b' : [1, 2, function('strlen')]
-'f' : function('1')
-[0, function('strlen')]
-[3]
-[1, 2, function('strlen')]
-[1, 2, function('strlen')]
-1
-'asd'
-2
-True
-False
-True
-False
-[b'0']
-{'0': -1}
-(b'0', -1)
-None
-[]
-[0, 1, 2, 3]
-[0, 1, 2, 3]
-[0, 1, 3]
-[0, 1]
-[0, 1]
-[0, 1]
-[0, 1, 2, 3]
-[0, 1, 2, 3]
-[0, 2, 3]
-[2, 3]
-[2, 3]
-[2, 3]
-[1, 3]
-[0, 2]
-[0, 1, 2, 3]
-['a', 0, 1, 2, 3]
-[0, 'b', 2, 3]
-[0, 1, 'c']
-[0, 1, 2, 3, 'd']
-[0, 1, 2, 'e', 3]
-['f', 2, 3]
-[0, 1, 'g', 2, 3]
-['h']
-[0, 1, 10, 3, 20, 5, 6, 7]
-[0, 1, 2, 3, 20, 5, 10, 7]
-[0, 1, 2, 3, 4, 5, 6, 7]
-[0, 1, 2, 3, 4, 5, 6, 7]
-[0, 1, 2, 3, 4, 5, 6, 7]
-[0, 1, 2, 3]
-[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
-[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
-[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
-l[1](1, 2, 3):(<class 'vim.error'>, error('Vim:E725: Calling dict function without Dictionary: DictNew',))
-f(1, 2, 3):(<class 'vim.error'>, error('Vim:E117: Unknown function: New',))
-[0.0, 0.0]
-KeyError
-TypeError
-TypeError
-ValueError
-TypeError
-TypeError
-KeyError
-KeyError
-d : locked:0;scope:0
-dl : locked:1;scope:0
-v: : locked:2;scope:1
-g: : locked:0;scope:2
-d:{'abc2': 1}
-dl:{'def': 1}
-l : locked:0
-ll : locked:1
-l:[0]
-ll:[1]
-[0, 1, 2]
-['a', 'b']
-['c', 1]
-['d', ['e']]
-0.0
-"\0": Vim(let):E859:
-{"\0": 1}: Vim(let):E859:
-undefined_name: Vim(let):Trace
-vim: Vim(let):E859:
-[1]
-[1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1]
-[0, 1, 2, 3]
-[2, 3, 4, 5]
-[0, 1]
-[4, 5]
-[2, 3]
-[]
-[2, 3]
-[]
-[0, 1, 2, 3, 4, 5]
-[0, 1, 2, 3, 4, 5]
-[0, 1, 2, 3, 4, 5]
-[4, 3]
-[0, 2, 4]
-[]
-Abc
-bac
-def
-bar
-jkl
-wopts iters equal: 1
-bopts iters equal: 1
->>> paste
- g/w/b:1/0/0
- g/w/b (in):1/0/0
- p/gopts1: False
- p/wopts1! KeyError
- inv: 2! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1! KeyError
- inv: 2! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 1
- W: 1:1 2:1 3:1 4:1
- B: 1:1 2:1 3:1 4:1
- del wopts3! KeyError
- del bopts3! KeyError
- G: 1
- W: 1:1 2:1 3:1 4:1
- B: 1:1 2:1 3:1 4:1
->>> previewheight
- g/w/b:1/0/0
- g/w/b (in):1/0/0
- p/gopts1: 12
- inv: 'a'! TypeError
- p/wopts1! KeyError
- inv: 'a'! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1! KeyError
- inv: 'a'! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 5
- W: 1:5 2:5 3:5 4:5
- B: 1:5 2:5 3:5 4:5
- del wopts3! KeyError
- del bopts3! KeyError
- G: 5
- W: 1:5 2:5 3:5 4:5
- B: 1:5 2:5 3:5 4:5
->>> operatorfunc
- g/w/b:1/0/0
- g/w/b (in):1/0/0
- p/gopts1: b''
- inv: 2! TypeError
- p/wopts1! KeyError
- inv: 2! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1! KeyError
- inv: 2! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 'A'
- W: 1:'A' 2:'A' 3:'A' 4:'A'
- B: 1:'A' 2:'A' 3:'A' 4:'A'
- del wopts3! KeyError
- del bopts3! KeyError
- G: 'A'
- W: 1:'A' 2:'A' 3:'A' 4:'A'
- B: 1:'A' 2:'A' 3:'A' 4:'A'
->>> number
- g/w/b:0/1/0
- g/w/b (in):0/1/0
- p/gopts1! KeyError
- inv: 0! KeyError
- gopts1! KeyError
- p/wopts1: False
- p/bopts1! KeyError
- inv: 0! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 0
- W: 1:1 2:1 3:0 4:0
- B: 1:1 2:1 3:0 4:0
- del wopts3! ValueError
- del bopts3! KeyError
- G: 0
- W: 1:1 2:1 3:0 4:0
- B: 1:1 2:1 3:0 4:0
->>> numberwidth
- g/w/b:0/1/0
- g/w/b (in):0/1/0
- p/gopts1! KeyError
- inv: -100! KeyError
- gopts1! KeyError
- p/wopts1: 8
- inv: -100! error
- p/bopts1! KeyError
- inv: -100! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: 8
- W: 1:3 2:5 3:2 4:8
- B: 1:3 2:5 3:2 4:8
- del wopts3! ValueError
- del bopts3! KeyError
- G: 8
- W: 1:3 2:5 3:2 4:8
- B: 1:3 2:5 3:2 4:8
->>> colorcolumn
- g/w/b:0/1/0
- g/w/b (in):0/1/0
- p/gopts1! KeyError
- inv: 'abc4'! KeyError
- gopts1! KeyError
- p/wopts1: b''
- inv: 'abc4'! error
- p/bopts1! KeyError
- inv: 'abc4'! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: ''
- W: 1:'+2' 2:'+3' 3:'+1' 4:''
- B: 1:'+2' 2:'+3' 3:'+1' 4:''
- del wopts3! ValueError
- del bopts3! KeyError
- G: ''
- W: 1:'+2' 2:'+3' 3:'+1' 4:''
- B: 1:'+2' 2:'+3' 3:'+1' 4:''
->>> statusline
- g/w/b:1/1/0
- g/w/b (in):1/1/0
- p/gopts1: b''
- inv: 0! TypeError
- p/wopts1: None
- inv: 0! TypeError
- p/bopts1! KeyError
- inv: 0! KeyError
- bopts1! KeyError
- bopts2! KeyError
- bopts3! KeyError
- G: '1'
- W: 1:'2' 2:'4' 3:'1' 4:'1'
- B: 1:'2' 2:'4' 3:'1' 4:'1'
- del bopts3! KeyError
- G: '1'
- W: 1:'2' 2:'1' 3:'1' 4:'1'
- B: 1:'2' 2:'1' 3:'1' 4:'1'
->>> autoindent
- g/w/b:0/0/1
- g/w/b (in):0/0/1
- p/gopts1! KeyError
- inv: 2! KeyError
- gopts1! KeyError
- p/wopts1! KeyError
- inv: 2! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: False
- G: 0
- W: 1:0 2:1 3:0 4:1
- B: 1:0 2:1 3:0 4:1
- del wopts3! KeyError
- del bopts3! ValueError
- G: 0
- W: 1:0 2:1 3:0 4:1
- B: 1:0 2:1 3:0 4:1
->>> shiftwidth
- g/w/b:0/0/1
- g/w/b (in):0/0/1
- p/gopts1! KeyError
- inv: 3! KeyError
- gopts1! KeyError
- p/wopts1! KeyError
- inv: 3! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: 8
- G: 8
- W: 1:0 2:2 3:8 4:1
- B: 1:0 2:2 3:8 4:1
- del wopts3! KeyError
- del bopts3! ValueError
- G: 8
- W: 1:0 2:2 3:8 4:1
- B: 1:0 2:2 3:8 4:1
->>> omnifunc
- g/w/b:0/0/1
- g/w/b (in):0/0/1
- p/gopts1! KeyError
- inv: 1! KeyError
- gopts1! KeyError
- p/wopts1! KeyError
- inv: 1! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: b''
- inv: 1! TypeError
- G: ''
- W: 1:'A' 2:'B' 3:'' 4:'C'
- B: 1:'A' 2:'B' 3:'' 4:'C'
- del wopts3! KeyError
- del bopts3! ValueError
- G: ''
- W: 1:'A' 2:'B' 3:'' 4:'C'
- B: 1:'A' 2:'B' 3:'' 4:'C'
->>> preserveindent
- g/w/b:0/0/1
- g/w/b (in):0/0/1
- p/gopts1! KeyError
- inv: 2! KeyError
- gopts1! KeyError
- p/wopts1! KeyError
- inv: 2! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: False
- G: 0
- W: 1:0 2:1 3:0 4:1
- B: 1:0 2:1 3:0 4:1
- del wopts3! KeyError
- del bopts3! ValueError
- G: 0
- W: 1:0 2:1 3:0 4:1
- B: 1:0 2:1 3:0 4:1
->>> path
- g/w/b:1/0/1
- g/w/b (in):1/0/1
- p/gopts1: b'.,..,,'
- inv: 0! TypeError
- p/wopts1! KeyError
- inv: 0! KeyError
- wopts1! KeyError
- wopts2! KeyError
- wopts3! KeyError
- p/bopts1: None
- inv: 0! TypeError
- G: '.,,'
- W: 1:'.,,' 2:',,' 3:'.,,' 4:'.'
- B: 1:'.,,' 2:',,' 3:'.,,' 4:'.'
- del wopts3! KeyError
- G: '.,,'
- W: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,'
- B: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,'
-First line
-First line
-def
-First line
-Second line
-Third line
-(7, 2)
-<buffer test87.in><buffer >
-baz
-bar
-Second line
-Third line
-foo
-1:BufFilePre:1
-1:BufFilePost:1
-testdir/foo
-5:BufFilePre:5
-5:BufFilePost:5
-testdir/bar
-1:BufFilePre:1
-1:BufFilePost:1
-testdir/test87.in
-valid: b:False, cb:True
-i:<buffer test87.in>
-i2:<buffer test87.in>
-i:<buffer a>
-i3:<buffer test87.in>
-1:<buffer test87.in>=<buffer test87.in>
-8:<buffer a>=<buffer a>
-9:<buffer b>=<buffer b>
-10:<buffer c>=<buffer c>
-4
-i4:<buffer test87.in>
-i4:<buffer test87.in>
-StopIteration
-Number of tabs: 4
-Current tab pages:
- <tabpage 0>(1): 1 windows, current is <window object (unknown)>
- Windows:
- <window object (unknown)>(1): displays buffer <buffer test87.in>; cursor is at (37, 0)
- <tabpage 1>(2): 1 windows, current is <window object (unknown)>
- Windows:
- <window object (unknown)>(1): displays buffer <buffer 0>; cursor is at (1, 0)
- <tabpage 2>(3): 2 windows, current is <window object (unknown)>
- Windows:
- <window object (unknown)>(1): displays buffer <buffer a.1>; cursor is at (1, 0)
- <window object (unknown)>(2): displays buffer <buffer 1>; cursor is at (1, 0)
- <tabpage 3>(4): 4 windows, current is <window 0>
- Windows:
- <window 0>(1): displays buffer <buffer c.2>; cursor is at (1, 0)
- <window 1>(2): displays buffer <buffer b.2>; cursor is at (1, 0)
- <window 2>(3): displays buffer <buffer a.2>; cursor is at (1, 0)
- <window 3>(4): displays buffer <buffer 2>; cursor is at (1, 0)
-Number of windows in current tab page: 4
-Current tab page: <tabpage 3>
-Current window: <window 0>: <window 0> is <window 0>
-Current buffer: <buffer c.2>: <buffer c.2> is <buffer c.2> is <buffer c.2>
-ValueError at assigning foreign tab window
-Type error at assigning None to vim.current.window
-Type error at assigning None to vim.current.tabpage
-Type error at assigning None to vim.current.buffer
-Current tab page: <tabpage 2>
-Current window: <window 0>
-Current buffer: <buffer test87.in>
-Current line: 'Type error at assigning None to vim.current.buffer'
-w.valid: [True, False]
-t.valid: [True, False, True, False]
-vim.vars:Dictionary:True
-vim.options:Options:True
-vim.bindeval("{}"):Dictionary:True
-vim.bindeval("[]"):List:True
-vim.bindeval("function('tr')"):Function:True
-vim.current.buffer:Buffer:True
-vim.current.range:Range:True
-vim.current.window:Window:True
-vim.current.tabpage:TabPage:True
-current:__dir__,buffer,line,range,tabpage,window
-buffer:__dir__,append,mark,name,number,options,range,valid,vars
-window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars
-tabpage:__dir__,number,valid,vars,window,windows
-range:__dir__,append,end,start
-dictionary:__dir__,get,has_key,items,keys,locked,pop,popitem,scope,update,values
-list:__dir__,extend,locked
-function:__dir__,softspace
-output:__dir__,flush,softspace,write,writelines
-{}
-{'a': 1}
-{'a': 1}
-[]
-['a', 'b', 'c', '7']
-function('tr')
-'
-abcdef
-line :
-abcdef
-abcA
-line :
-abcB'
-['a', 'dup_a']
-['a', 'a']
-['a', 'b', 'c', 'C']
-[2, 2]
-[2, 2]
-1
-1
-function('Put')
-b'testdir'
-test87.in
-b'src'
-testdir/test87.in
-b'testdir'
-test87.in
-> Output
->> OutputSetattr
-del sys.stdout.softspace:(<class 'AttributeError'>, AttributeError("can't delete OutputObject attributes",))
->>> Testing NumberToLong using sys.stdout.softspace = %s
-sys.stdout.softspace = []:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
-sys.stdout.softspace = None:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
-sys.stdout.softspace = -1:(<class 'ValueError'>, ValueError('number must be greater or equal to zero',))
-<<< Finished
->>> Testing NumberToLong using sys.stderr.softspace = %s
-sys.stderr.softspace = []:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
-sys.stderr.softspace = None:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
-sys.stderr.softspace = -1:(<class 'ValueError'>, ValueError('number must be greater or equal to zero',))
-<<< Finished
-sys.stdout.attr = None:(<class 'AttributeError'>, AttributeError('invalid attribute: attr',))
->> OutputWrite
-sys.stdout.write(None):(<class 'TypeError'>, TypeError("Can't convert 'NoneType' object to str implicitly",))
->> OutputWriteLines
-sys.stdout.writelines(None):(<class 'TypeError'>, TypeError("'NoneType' object is not iterable",))
-sys.stdout.writelines([1]):(<class 'TypeError'>, TypeError("Can't convert 'int' object to str implicitly",))
->>> Testing *Iter* using sys.stdout.writelines(%s)
-sys.stdout.writelines(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
-sys.stdout.writelines(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
-> VimCommand
->>> Testing StringToChars using vim.command(%s)
-vim.command(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.command(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.command("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
-vim.command("", 2):(<class 'TypeError'>, TypeError('command() takes exactly one argument (2 given)',))
-> VimToPython
-> VimEval
->>> Testing StringToChars using vim.eval(%s)
-vim.eval(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.eval(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.eval("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
-vim.eval("", FailingTrue()):(<class 'TypeError'>, TypeError('function takes exactly 1 argument (2 given)',))
-> VimEvalPy
->>> Testing StringToChars using vim.bindeval(%s)
-vim.bindeval(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.bindeval(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.bindeval("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
-vim.eval("", 2):(<class 'TypeError'>, TypeError('function takes exactly 1 argument (2 given)',))
-> VimStrwidth
->>> Testing StringToChars using vim.strwidth(%s)
-vim.strwidth(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.strwidth(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.strwidth("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
-> VimForeachRTP
-vim.foreach_rtp(None):(<class 'TypeError'>, TypeError("'NoneType' object is not callable",))
-vim.foreach_rtp(NoArgsCall()):(<class 'TypeError'>, TypeError('__call__() takes exactly 1 positional argument (2 given)',))
-vim.foreach_rtp(FailingCall()):(<class 'NotImplementedError'>, NotImplementedError('call',))
-vim.foreach_rtp(int, 2):(<class 'TypeError'>, TypeError('foreach_rtp() takes exactly one argument (2 given)',))
-> import
-import xxx_no_such_module_xxx:(<class 'ImportError'>, ImportError('No module named xxx_no_such_module_xxx',))
-import failing_import:(<class 'ImportError'>, ImportError('No module named failing_import',))
-import failing:(<class 'NotImplementedError'>, NotImplementedError())
-> Options
->> OptionsItem
-vim.options["abcQ"]:(<class 'KeyError'>, KeyError('abcQ',))
-vim.options[""]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
->>> Testing StringToChars using vim.options[%s]
-vim.options[1]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.options[b"\0"]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.options["\0"]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->> OptionsContains
->>> Testing StringToChars using %s in vim.options
-1 in vim.options:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-b"\0" in vim.options:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-"\0" in vim.options:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
-> Dictionary
->> DictionaryConstructor
-vim.Dictionary("abcI"):(<class 'ValueError'>, ValueError('expected sequence element of size 2, but got sequence of size 1',))
->> DictionarySetattr
-del d.locked:(<class 'AttributeError'>, AttributeError('cannot delete vim.Dictionary attributes',))
-d.locked = FailingTrue():(<class 'NotImplementedError'>, NotImplementedError('bool',))
-vim.vvars.locked = False:(<class 'TypeError'>, TypeError('cannot modify fixed dictionary',))
-d.scope = True:(<class 'AttributeError'>, AttributeError('cannot set attribute scope',))
-d.xxx = True:(<class 'AttributeError'>, AttributeError('cannot set attribute xxx',))
->> _DictionaryItem
-d.get("a", 2, 3):(<class 'TypeError'>, TypeError('function takes at most 2 arguments (3 given)',))
->>> Testing StringToChars using d.get(%s)
-d.get(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.get(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.get("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
-d.pop("a"):(<class 'KeyError'>, KeyError('a',))
-dl.pop("a"):(<class 'vim.error'>, error('dictionary is locked',))
->> DictionaryContains
-"" in d:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-0 in d:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
->> DictionaryIterNext
-for i in ned: ned["a"] = 1:(<class 'RuntimeError'>, RuntimeError('hashtab changed during iteration',))
->> DictionaryAssItem
-dl["b"] = 1:(<class 'vim.error'>, error('dictionary is locked',))
->>> Testing StringToChars using d[%s] = 1
-d[1] = 1:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d[b"\0"] = 1:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d["\0"] = 1:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d["a"] = {%s : 1}
-d["a"] = {1 : 1}:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d["a"] = {b"\0" : 1}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d["a"] = {"\0" : 1}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d["a"] = {"abcF" : {%s : 1}}
-d["a"] = {"abcF" : {1 : 1}}:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d["a"] = {"abcF" : {b"\0" : 1}}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d["a"] = {"abcF" : {"\0" : 1}}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d["a"] = {"abcF" : Mapping({%s : 1})}
-d["a"] = {"abcF" : Mapping({1 : 1})}:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d["a"] = {"abcF" : Mapping({b"\0" : 1})}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d["a"] = {"abcF" : Mapping({"\0" : 1})}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using d["a"] = {"abcF" : %s}
-d["a"] = {"abcF" : FailingIter()}:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-d["a"] = {"abcF" : FailingIterNext()}:(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d["a"] = {"abcF" : %s}
-d["a"] = {"abcF" : None}:(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-d["a"] = {"abcF" : {b"": 1}}:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d["a"] = {"abcF" : {"": 1}}:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d["a"] = {"abcF" : FailingMapping()}:(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d["a"] = {"abcF" : FailingMappingKey()}:(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d["a"] = {"abcF" : FailingNumber()}:(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using d["a"] = Mapping({%s : 1})
-d["a"] = Mapping({1 : 1}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d["a"] = Mapping({b"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d["a"] = Mapping({"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d["a"] = Mapping({"abcG" : {%s : 1}})
-d["a"] = Mapping({"abcG" : {1 : 1}}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d["a"] = Mapping({"abcG" : {b"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d["a"] = Mapping({"abcG" : {"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d["a"] = Mapping({"abcG" : Mapping({%s : 1})})
-d["a"] = Mapping({"abcG" : Mapping({1 : 1})}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d["a"] = Mapping({"abcG" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d["a"] = Mapping({"abcG" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using d["a"] = Mapping({"abcG" : %s})
-d["a"] = Mapping({"abcG" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-d["a"] = Mapping({"abcG" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d["a"] = Mapping({"abcG" : %s})
-d["a"] = Mapping({"abcG" : None}):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-d["a"] = Mapping({"abcG" : {b"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d["a"] = Mapping({"abcG" : {"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d["a"] = Mapping({"abcG" : FailingMapping()}):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d["a"] = Mapping({"abcG" : FailingMappingKey()}):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d["a"] = Mapping({"abcG" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing *Iter* using d["a"] = %s
-d["a"] = FailingIter():(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-d["a"] = FailingIterNext():(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d["a"] = %s
-d["a"] = None:(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-d["a"] = {b"": 1}:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d["a"] = {"": 1}:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d["a"] = FailingMapping():(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d["a"] = FailingMappingKey():(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d["a"] = FailingNumber():(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->> DictionaryUpdate
->>> kwargs
->>> iter
-d.update(FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d.update([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',))
-d.update([FailingIterNextN(1)]):(<class 'NotImplementedError'>, NotImplementedError('next N',))
->>> Testing *Iter* using d.update(%s)
-d.update(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
-d.update(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing StringToChars using d.update({%s : 1})
-d.update({1 : 1}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update({b"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update({"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update({"abcF" : {%s : 1}})
-d.update({"abcF" : {1 : 1}}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update({"abcF" : {b"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update({"abcF" : {"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update({"abcF" : Mapping({%s : 1})})
-d.update({"abcF" : Mapping({1 : 1})}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update({"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update({"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using d.update({"abcF" : %s})
-d.update({"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-d.update({"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d.update({"abcF" : %s})
-d.update({"abcF" : None}):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-d.update({"abcF" : {b"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update({"abcF" : {"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update({"abcF" : FailingMapping()}):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d.update({"abcF" : FailingMappingKey()}):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d.update({"abcF" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using d.update(Mapping({%s : 1}))
-d.update(Mapping({1 : 1})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update(Mapping({b"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update(Mapping({"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update(Mapping({"abcG" : {%s : 1}}))
-d.update(Mapping({"abcG" : {1 : 1}})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update(Mapping({"abcG" : {b"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update(Mapping({"abcG" : {"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update(Mapping({"abcG" : Mapping({%s : 1})}))
-d.update(Mapping({"abcG" : Mapping({1 : 1})})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update(Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update(Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using d.update(Mapping({"abcG" : %s}))
-d.update(Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-d.update(Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d.update(Mapping({"abcG" : %s}))
-d.update(Mapping({"abcG" : None})):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-d.update(Mapping({"abcG" : {b"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update(Mapping({"abcG" : {"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update(Mapping({"abcG" : FailingMapping()})):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d.update(Mapping({"abcG" : FailingMappingKey()})):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d.update(Mapping({"abcG" : FailingNumber()})):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing *Iter* using d.update(%s)
-d.update(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
-d.update(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d.update(%s)
-d.update(None):(<class 'TypeError'>, TypeError("'NoneType' object is not iterable",))
-d.update({b"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update({"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update(FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d.update(FailingMappingKey()):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d.update(FailingNumber()):(<class 'TypeError'>, TypeError("'FailingNumber' object is not iterable",))
-<<< Finished
->>> Testing StringToChars using d.update(((%s, 0),))
-d.update(((1, 0),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update(((b"\0", 0),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update((("\0", 0),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update((("a", {%s : 1}),))
-d.update((("a", {1 : 1}),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update((("a", {b"\0" : 1}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update((("a", {"\0" : 1}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update((("a", {"abcF" : {%s : 1}}),))
-d.update((("a", {"abcF" : {1 : 1}}),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update((("a", {"abcF" : {b"\0" : 1}}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update((("a", {"abcF" : {"\0" : 1}}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update((("a", {"abcF" : Mapping({%s : 1})}),))
-d.update((("a", {"abcF" : Mapping({1 : 1})}),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update((("a", {"abcF" : Mapping({b"\0" : 1})}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update((("a", {"abcF" : Mapping({"\0" : 1})}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using d.update((("a", {"abcF" : %s}),))
-d.update((("a", {"abcF" : FailingIter()}),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-d.update((("a", {"abcF" : FailingIterNext()}),)):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d.update((("a", {"abcF" : %s}),))
-d.update((("a", {"abcF" : None}),)):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-d.update((("a", {"abcF" : {b"": 1}}),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update((("a", {"abcF" : {"": 1}}),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update((("a", {"abcF" : FailingMapping()}),)):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d.update((("a", {"abcF" : FailingMappingKey()}),)):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d.update((("a", {"abcF" : FailingNumber()}),)):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using d.update((("a", Mapping({%s : 1})),))
-d.update((("a", Mapping({1 : 1})),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update((("a", Mapping({b"\0" : 1})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update((("a", Mapping({"\0" : 1})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update((("a", Mapping({"abcG" : {%s : 1}})),))
-d.update((("a", Mapping({"abcG" : {1 : 1}})),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update((("a", Mapping({"abcG" : {b"\0" : 1}})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update((("a", Mapping({"abcG" : {"\0" : 1}})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using d.update((("a", Mapping({"abcG" : Mapping({%s : 1})})),))
-d.update((("a", Mapping({"abcG" : Mapping({1 : 1})})),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-d.update((("a", Mapping({"abcG" : Mapping({b"\0" : 1})})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-d.update((("a", Mapping({"abcG" : Mapping({"\0" : 1})})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using d.update((("a", Mapping({"abcG" : %s})),))
-d.update((("a", Mapping({"abcG" : FailingIter()})),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-d.update((("a", Mapping({"abcG" : FailingIterNext()})),)):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d.update((("a", Mapping({"abcG" : %s})),))
-d.update((("a", Mapping({"abcG" : None})),)):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-d.update((("a", Mapping({"abcG" : {b"": 1}})),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update((("a", Mapping({"abcG" : {"": 1}})),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update((("a", Mapping({"abcG" : FailingMapping()})),)):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d.update((("a", Mapping({"abcG" : FailingMappingKey()})),)):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d.update((("a", Mapping({"abcG" : FailingNumber()})),)):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing *Iter* using d.update((("a", %s),))
-d.update((("a", FailingIter()),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-d.update((("a", FailingIterNext()),)):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using d.update((("a", %s),))
-d.update((("a", None),)):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-d.update((("a", {b"": 1}),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update((("a", {"": 1}),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-d.update((("a", FailingMapping()),)):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-d.update((("a", FailingMappingKey()),)):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-d.update((("a", FailingNumber()),)):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->> DictionaryPopItem
-d.popitem(1, 2):(<class 'TypeError'>, TypeError('popitem() takes no arguments (2 given)',))
->> DictionaryHasKey
-d.has_key():(<class 'TypeError'>, TypeError('has_key() takes exactly one argument (0 given)',))
-> List
->> ListConstructor
-vim.List(1, 2):(<class 'TypeError'>, TypeError('function takes at most 1 argument (2 given)',))
-vim.List(a=1):(<class 'TypeError'>, TypeError('list constructor does not accept keyword arguments',))
->>> Testing *Iter* using vim.List(%s)
-vim.List(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
-vim.List(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing StringToChars using vim.List([{%s : 1}])
-vim.List([{1 : 1}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.List([{b"\0" : 1}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.List([{"\0" : 1}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using vim.List([{"abcF" : {%s : 1}}])
-vim.List([{"abcF" : {1 : 1}}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.List([{"abcF" : {b"\0" : 1}}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.List([{"abcF" : {"\0" : 1}}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using vim.List([{"abcF" : Mapping({%s : 1})}])
-vim.List([{"abcF" : Mapping({1 : 1})}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.List([{"abcF" : Mapping({b"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.List([{"abcF" : Mapping({"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using vim.List([{"abcF" : %s}])
-vim.List([{"abcF" : FailingIter()}]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-vim.List([{"abcF" : FailingIterNext()}]):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using vim.List([{"abcF" : %s}])
-vim.List([{"abcF" : None}]):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-vim.List([{"abcF" : {b"": 1}}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-vim.List([{"abcF" : {"": 1}}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-vim.List([{"abcF" : FailingMapping()}]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-vim.List([{"abcF" : FailingMappingKey()}]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-vim.List([{"abcF" : FailingNumber()}]):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using vim.List([Mapping({%s : 1})])
-vim.List([Mapping({1 : 1})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.List([Mapping({b"\0" : 1})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.List([Mapping({"\0" : 1})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using vim.List([Mapping({"abcG" : {%s : 1}})])
-vim.List([Mapping({"abcG" : {1 : 1}})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.List([Mapping({"abcG" : {b"\0" : 1}})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.List([Mapping({"abcG" : {"\0" : 1}})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using vim.List([Mapping({"abcG" : Mapping({%s : 1})})])
-vim.List([Mapping({"abcG" : Mapping({1 : 1})})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.List([Mapping({"abcG" : Mapping({b"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-vim.List([Mapping({"abcG" : Mapping({"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using vim.List([Mapping({"abcG" : %s})])
-vim.List([Mapping({"abcG" : FailingIter()})]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-vim.List([Mapping({"abcG" : FailingIterNext()})]):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using vim.List([Mapping({"abcG" : %s})])
-vim.List([Mapping({"abcG" : None})]):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-vim.List([Mapping({"abcG" : {b"": 1}})]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-vim.List([Mapping({"abcG" : {"": 1}})]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-vim.List([Mapping({"abcG" : FailingMapping()})]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-vim.List([Mapping({"abcG" : FailingMappingKey()})]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-vim.List([Mapping({"abcG" : FailingNumber()})]):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing *Iter* using vim.List([%s])
-vim.List([FailingIter()]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-vim.List([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using vim.List([%s])
-vim.List([None]):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-vim.List([{b"": 1}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-vim.List([{"": 1}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-vim.List([FailingMapping()]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-vim.List([FailingMappingKey()]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-vim.List([FailingNumber()]):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->> ListItem
-l[1000]:(<class 'IndexError'>, IndexError('list index out of range',))
->> ListAssItem
-ll[1] = 2:(<class 'vim.error'>, error('list is locked',))
-l[1000] = 3:(<class 'IndexError'>, IndexError('list index out of range',))
->> ListAssSlice
-ll[1:100] = "abcJ":(<class 'vim.error'>, error('list is locked',))
->>> Testing *Iter* using l[:] = %s
-l[:] = FailingIter():(<class 'NotImplementedError'>, NotImplementedError('iter',))
-l[:] = FailingIterNext():(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
-nel[1:10:2] = "abcK":(<class 'ValueError'>, ValueError('attempt to assign sequence of size greater then 2 to extended slice',))
-(b'a', b'b', b'c', b'O')
-nel[1:10:2] = "a":(<class 'ValueError'>, ValueError('attempt to assign sequence of size 1 to extended slice of size 2',))
-(b'a', b'b', b'c', b'O')
-nel[1:1:-1] = "a":(<class 'ValueError'>, ValueError('attempt to assign sequence of size greater then 0 to extended slice',))
-(b'a', b'b', b'c', b'O')
-nel[:] = FailingIterNextN(2):(<class 'NotImplementedError'>, NotImplementedError('next N',))
-(b'a', b'b', b'c', b'O')
->>> Testing StringToChars using l[:] = [{%s : 1}]
-l[:] = [{1 : 1}]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l[:] = [{b"\0" : 1}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l[:] = [{"\0" : 1}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using l[:] = [{"abcF" : {%s : 1}}]
-l[:] = [{"abcF" : {1 : 1}}]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l[:] = [{"abcF" : {b"\0" : 1}}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l[:] = [{"abcF" : {"\0" : 1}}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using l[:] = [{"abcF" : Mapping({%s : 1})}]
-l[:] = [{"abcF" : Mapping({1 : 1})}]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l[:] = [{"abcF" : Mapping({b"\0" : 1})}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l[:] = [{"abcF" : Mapping({"\0" : 1})}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using l[:] = [{"abcF" : %s}]
-l[:] = [{"abcF" : FailingIter()}]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-l[:] = [{"abcF" : FailingIterNext()}]:(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using l[:] = [{"abcF" : %s}]
-l[:] = [{"abcF" : None}]:(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-l[:] = [{"abcF" : {b"": 1}}]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l[:] = [{"abcF" : {"": 1}}]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l[:] = [{"abcF" : FailingMapping()}]:(<class 'NotImplementedError'>, NotImplementedError('keys',))
-l[:] = [{"abcF" : FailingMappingKey()}]:(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-l[:] = [{"abcF" : FailingNumber()}]:(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using l[:] = [Mapping({%s : 1})]
-l[:] = [Mapping({1 : 1})]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l[:] = [Mapping({b"\0" : 1})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l[:] = [Mapping({"\0" : 1})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using l[:] = [Mapping({"abcG" : {%s : 1}})]
-l[:] = [Mapping({"abcG" : {1 : 1}})]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l[:] = [Mapping({"abcG" : {b"\0" : 1}})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l[:] = [Mapping({"abcG" : {"\0" : 1}})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using l[:] = [Mapping({"abcG" : Mapping({%s : 1})})]
-l[:] = [Mapping({"abcG" : Mapping({1 : 1})})]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l[:] = [Mapping({"abcG" : Mapping({b"\0" : 1})})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l[:] = [Mapping({"abcG" : Mapping({"\0" : 1})})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using l[:] = [Mapping({"abcG" : %s})]
-l[:] = [Mapping({"abcG" : FailingIter()})]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-l[:] = [Mapping({"abcG" : FailingIterNext()})]:(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using l[:] = [Mapping({"abcG" : %s})]
-l[:] = [Mapping({"abcG" : None})]:(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-l[:] = [Mapping({"abcG" : {b"": 1}})]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l[:] = [Mapping({"abcG" : {"": 1}})]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l[:] = [Mapping({"abcG" : FailingMapping()})]:(<class 'NotImplementedError'>, NotImplementedError('keys',))
-l[:] = [Mapping({"abcG" : FailingMappingKey()})]:(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-l[:] = [Mapping({"abcG" : FailingNumber()})]:(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing *Iter* using l[:] = [%s]
-l[:] = [FailingIter()]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-l[:] = [FailingIterNext()]:(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using l[:] = [%s]
-l[:] = [None]:(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-l[:] = [{b"": 1}]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l[:] = [{"": 1}]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l[:] = [FailingMapping()]:(<class 'NotImplementedError'>, NotImplementedError('keys',))
-l[:] = [FailingMappingKey()]:(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-l[:] = [FailingNumber()]:(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->> ListConcatInPlace
->>> Testing *Iter* using l.extend(%s)
-l.extend(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
-l.extend(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing StringToChars using l.extend([{%s : 1}])
-l.extend([{1 : 1}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l.extend([{b"\0" : 1}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l.extend([{"\0" : 1}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using l.extend([{"abcF" : {%s : 1}}])
-l.extend([{"abcF" : {1 : 1}}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l.extend([{"abcF" : {b"\0" : 1}}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l.extend([{"abcF" : {"\0" : 1}}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using l.extend([{"abcF" : Mapping({%s : 1})}])
-l.extend([{"abcF" : Mapping({1 : 1})}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l.extend([{"abcF" : Mapping({b"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l.extend([{"abcF" : Mapping({"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using l.extend([{"abcF" : %s}])
-l.extend([{"abcF" : FailingIter()}]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-l.extend([{"abcF" : FailingIterNext()}]):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using l.extend([{"abcF" : %s}])
-l.extend([{"abcF" : None}]):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-l.extend([{"abcF" : {b"": 1}}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l.extend([{"abcF" : {"": 1}}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l.extend([{"abcF" : FailingMapping()}]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-l.extend([{"abcF" : FailingMappingKey()}]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-l.extend([{"abcF" : FailingNumber()}]):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using l.extend([Mapping({%s : 1})])
-l.extend([Mapping({1 : 1})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l.extend([Mapping({b"\0" : 1})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l.extend([Mapping({"\0" : 1})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using l.extend([Mapping({"abcG" : {%s : 1}})])
-l.extend([Mapping({"abcG" : {1 : 1}})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l.extend([Mapping({"abcG" : {b"\0" : 1}})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l.extend([Mapping({"abcG" : {"\0" : 1}})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using l.extend([Mapping({"abcG" : Mapping({%s : 1})})])
-l.extend([Mapping({"abcG" : Mapping({1 : 1})})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-l.extend([Mapping({"abcG" : Mapping({b"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-l.extend([Mapping({"abcG" : Mapping({"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using l.extend([Mapping({"abcG" : %s})])
-l.extend([Mapping({"abcG" : FailingIter()})]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-l.extend([Mapping({"abcG" : FailingIterNext()})]):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using l.extend([Mapping({"abcG" : %s})])
-l.extend([Mapping({"abcG" : None})]):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-l.extend([Mapping({"abcG" : {b"": 1}})]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l.extend([Mapping({"abcG" : {"": 1}})]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l.extend([Mapping({"abcG" : FailingMapping()})]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-l.extend([Mapping({"abcG" : FailingMappingKey()})]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-l.extend([Mapping({"abcG" : FailingNumber()})]):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing *Iter* using l.extend([%s])
-l.extend([FailingIter()]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-l.extend([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using l.extend([%s])
-l.extend([None]):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-l.extend([{b"": 1}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l.extend([{"": 1}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-l.extend([FailingMapping()]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-l.extend([FailingMappingKey()]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-l.extend([FailingNumber()]):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->> ListSetattr
-del l.locked:(<class 'AttributeError'>, AttributeError('cannot delete vim.List attributes',))
-l.locked = FailingTrue():(<class 'NotImplementedError'>, NotImplementedError('bool',))
-l.xxx = True:(<class 'AttributeError'>, AttributeError('cannot set attribute xxx',))
-> Function
->> FunctionConstructor
-vim.Function("123"):(<class 'ValueError'>, ValueError('unnamed function 123 does not exist',))
-vim.Function("xxx_non_existent_function_xxx"):(<class 'ValueError'>, ValueError('function xxx_non_existent_function_xxx does not exist',))
-vim.Function("xxx#non#existent#function#xxx"):NOT FAILED
->> FunctionCall
->>> Testing StringToChars using f({%s : 1})
-f({1 : 1}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-f({b"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-f({"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using f({"abcF" : {%s : 1}})
-f({"abcF" : {1 : 1}}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-f({"abcF" : {b"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-f({"abcF" : {"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using f({"abcF" : Mapping({%s : 1})})
-f({"abcF" : Mapping({1 : 1})}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-f({"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-f({"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using f({"abcF" : %s})
-f({"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-f({"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using f({"abcF" : %s})
-f({"abcF" : None}):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-f({"abcF" : {b"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-f({"abcF" : {"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-f({"abcF" : FailingMapping()}):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-f({"abcF" : FailingMappingKey()}):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-f({"abcF" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using f(Mapping({%s : 1}))
-f(Mapping({1 : 1})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-f(Mapping({b"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-f(Mapping({"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using f(Mapping({"abcG" : {%s : 1}}))
-f(Mapping({"abcG" : {1 : 1}})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-f(Mapping({"abcG" : {b"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-f(Mapping({"abcG" : {"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using f(Mapping({"abcG" : Mapping({%s : 1})}))
-f(Mapping({"abcG" : Mapping({1 : 1})})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-f(Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-f(Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using f(Mapping({"abcG" : %s}))
-f(Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-f(Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using f(Mapping({"abcG" : %s}))
-f(Mapping({"abcG" : None})):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-f(Mapping({"abcG" : {b"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-f(Mapping({"abcG" : {"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-f(Mapping({"abcG" : FailingMapping()})):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-f(Mapping({"abcG" : FailingMappingKey()})):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-f(Mapping({"abcG" : FailingNumber()})):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing *Iter* using f(%s)
-f(FailingIter()):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-f(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using f(%s)
-f(None):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-f({b"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-f({"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-f(FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-f(FailingMappingKey()):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-f(FailingNumber()):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using fd(self={%s : 1})
-fd(self={1 : 1}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-fd(self={b"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-fd(self={"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using fd(self={"abcF" : {%s : 1}})
-fd(self={"abcF" : {1 : 1}}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-fd(self={"abcF" : {b"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-fd(self={"abcF" : {"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using fd(self={"abcF" : Mapping({%s : 1})})
-fd(self={"abcF" : Mapping({1 : 1})}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-fd(self={"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-fd(self={"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using fd(self={"abcF" : %s})
-fd(self={"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-fd(self={"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using fd(self={"abcF" : %s})
-fd(self={"abcF" : None}):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-fd(self={"abcF" : {b"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-fd(self={"abcF" : {"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-fd(self={"abcF" : FailingMapping()}):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-fd(self={"abcF" : FailingMappingKey()}):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-fd(self={"abcF" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing StringToChars using fd(self=Mapping({%s : 1}))
-fd(self=Mapping({1 : 1})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-fd(self=Mapping({b"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-fd(self=Mapping({"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using fd(self=Mapping({"abcG" : {%s : 1}}))
-fd(self=Mapping({"abcG" : {1 : 1}})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-fd(self=Mapping({"abcG" : {b"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-fd(self=Mapping({"abcG" : {"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing StringToChars using fd(self=Mapping({"abcG" : Mapping({%s : 1})}))
-fd(self=Mapping({"abcG" : Mapping({1 : 1})})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-fd(self=Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-fd(self=Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
-<<< Finished
->>> Testing *Iter* using fd(self=Mapping({"abcG" : %s}))
-fd(self=Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
-fd(self=Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',))
-<<< Finished
->>> Testing ConvertFromPyObject using fd(self=Mapping({"abcG" : %s}))
-fd(self=Mapping({"abcG" : None})):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim structure',))
-fd(self=Mapping({"abcG" : {b"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-fd(self=Mapping({"abcG" : {"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-fd(self=Mapping({"abcG" : FailingMapping()})):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-fd(self=Mapping({"abcG" : FailingMappingKey()})):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-fd(self=Mapping({"abcG" : FailingNumber()})):(<class 'NotImplementedError'>, NotImplementedError('int',))
-<<< Finished
->>> Testing *Iter* using fd(self=%s)
-fd(self=FailingIter()):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim dictionary',))
-fd(self=FailingIterNext()):(<class 'TypeError'>, TypeError('unable to convert FailingIterNext to vim dictionary',))
-<<< Finished
->>> Testing ConvertFromPyObject using fd(self=%s)
-fd(self=None):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim dictionary',))
-fd(self={b"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-fd(self={"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
-fd(self=FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',))
-fd(self=FailingMappingKey()):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
-fd(self=FailingNumber()):(<class 'TypeError'>, TypeError('unable to convert FailingNumber to vim dictionary',))
-<<< Finished
->>> Testing ConvertFromPyMapping using fd(self=%s)
-fd(self=[]):(<class 'AttributeError'>, AttributeError('keys',))
-<<< Finished
-> TabPage
->> TabPageAttr
-vim.current.tabpage.xxx:(<class 'AttributeError'>, AttributeError("'vim.tabpage' object has no attribute 'xxx'",))
-> TabList
->> TabListItem
-vim.tabpages[1000]:(<class 'IndexError'>, IndexError('no such tab page',))
-> Window
->> WindowAttr
-vim.current.window.xxx:(<class 'AttributeError'>, AttributeError("'vim.window' object has no attribute 'xxx'",))
->> WindowSetattr
-vim.current.window.buffer = 0:(<class 'TypeError'>, TypeError('readonly attribute: buffer',))
-vim.current.window.cursor = (100000000, 100000000):(<class 'vim.error'>, error('cursor position outside buffer',))
-vim.current.window.cursor = True:(<class 'TypeError'>, TypeError('argument must be 2-item sequence, not bool',))
->>> Testing NumberToLong using vim.current.window.height = %s
-vim.current.window.height = []:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
-vim.current.window.height = None:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
-vim.current.window.height = -1:(<class 'ValueError'>, ValueError('number must be greater or equal to zero',))
-<<< Finished
->>> Testing NumberToLong using vim.current.window.width = %s
-vim.current.window.width = []:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
-vim.current.window.width = None:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
-vim.current.window.width = -1:(<class 'ValueError'>, ValueError('number must be greater or equal to zero',))
-<<< Finished
-vim.current.window.xxxxxx = True:(<class 'AttributeError'>, AttributeError('xxxxxx',))
-> WinList
->> WinListItem
-vim.windows[1000]:(<class 'IndexError'>, IndexError('no such window',))
-> Buffer
->> StringToLine (indirect)
-vim.current.buffer[0] = "\na":(<class 'vim.error'>, error('string cannot contain newlines',))
-vim.current.buffer[0] = b"\na":(<class 'vim.error'>, error('string cannot contain newlines',))
->> SetBufferLine (indirect)
-vim.current.buffer[0] = True:(<class 'TypeError'>, TypeError('bad argument type for built-in operation',))
->> SetBufferLineList (indirect)
-vim.current.buffer[:] = True:(<class 'TypeError'>, TypeError('bad argument type for built-in operation',))
-vim.current.buffer[:] = ["\na", "bc"]:(<class 'vim.error'>, error('string cannot contain newlines',))
->> InsertBufferLines (indirect)
-vim.current.buffer.append(None):(<class 'TypeError'>, TypeError('bad argument type for built-in operation',))
-vim.current.buffer.append(["\na", "bc"]):(<class 'vim.error'>, error('string cannot contain newlines',))
-vim.current.buffer.append("\nbc"):(<class 'vim.error'>, error('string cannot contain newlines',))
->> RBItem
-vim.current.buffer[100000000]:(<class 'IndexError'>, IndexError('line number out of range',))
->> RBAsItem
-vim.current.buffer[100000000] = "":(<class 'IndexError'>, IndexError('line number out of range',))
->> BufferAttr
-vim.current.buffer.xxx:(<class 'AttributeError'>, AttributeError("'vim.buffer' object has no attribute 'xxx'",))
->> BufferSetattr
-vim.current.buffer.name = True:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got bool',))
-vim.current.buffer.xxx = True:(<class 'AttributeError'>, AttributeError('xxx',))
->> BufferMark
-vim.current.buffer.mark(0):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
-vim.current.buffer.mark("abcM"):(<class 'ValueError'>, ValueError('mark name must be a single character',))
-vim.current.buffer.mark("!"):(<class 'vim.error'>, error('invalid mark name',))
->> BufferRange
-vim.current.buffer.range(1, 2, 3):(<class 'TypeError'>, TypeError('function takes exactly 2 arguments (3 given)',))
-> BufMap
->> BufMapItem
-vim.buffers[100000000]:(<class 'KeyError'>, KeyError(100000000,))
->>> Testing NumberToLong using vim.buffers[%s]
-vim.buffers[[]]:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
-vim.buffers[None]:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
-vim.buffers[-1]:(<class 'ValueError'>, ValueError('number must be greater then zero',))
-vim.buffers[0]:(<class 'ValueError'>, ValueError('number must be greater then zero',))
-<<< Finished
-> Current
->> CurrentGetattr
-vim.current.xxx:(<class 'AttributeError'>, AttributeError("'vim.currentdata' object has no attribute 'xxx'",))
->> CurrentSetattr
-vim.current.line = True:(<class 'TypeError'>, TypeError('bad argument type for built-in operation',))
-vim.current.buffer = True:(<class 'TypeError'>, TypeError('expected vim.Buffer object, but got bool',))
-vim.current.window = True:(<class 'TypeError'>, TypeError('expected vim.Window object, but got bool',))
-vim.current.tabpage = True:(<class 'TypeError'>, TypeError('expected vim.TabPage object, but got bool',))
-vim.current.xxx = True:(<class 'AttributeError'>, AttributeError('xxx',))
-['.']
-'.'
-3,xx
-before
-after
-pythonx/topmodule/__init__.py
-pythonx/topmodule/submodule/__init__.py
-pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py
-vim.command("throw 'abcN'"):(<class 'vim.error'>, error('abcN',))
-Exe("throw 'def'"):(<class 'vim.error'>, error('def',))
-vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))
-vim.eval("Exe('echoerr ''jkl''')"):(<class 'vim.error'>, error('Vim(echoerr):jkl',))
-vim.eval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
-vim.eval("xxx_unknown_function_xxx()"):(<class 'vim.error'>, error('Vim:E117: Unknown function: xxx_unknown_function_xxx',))
-vim.bindeval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
-Caught KeyboardInterrupt
-Running :put
-No exception
-
diff --git a/src/nvim/tui/term_input.inl b/src/nvim/tui/term_input.inl
index efdcf0a41e..c396557160 100644
--- a/src/nvim/tui/term_input.inl
+++ b/src/nvim/tui/term_input.inl
@@ -4,7 +4,8 @@
#include "nvim/misc2.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
-#include "nvim/os/rstream.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/time.h"
#define PASTETOGGLE_KEY "<f37>"
@@ -12,9 +13,8 @@ struct term_input {
int in_fd;
bool paste_enabled;
TermKey *tk;
- uv_timer_t timer_handle;
- RBuffer *read_buffer;
- RStream *read_stream;
+ TimeWatcher timer_handle;
+ Stream read_stream;
};
static void forward_simple_utf8(TermKeyKey *key)
@@ -107,7 +107,7 @@ static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force)
return force ? termkey_getkey_force(tk, key) : termkey_getkey(tk, key);
}
-static void timer_cb(uv_timer_t *handle);
+static void timer_cb(TimeWatcher *watcher, void *data);
static int get_key_code_timeout(void)
{
@@ -147,27 +147,26 @@ static void tk_getkeys(TermInput *input, bool force)
if (ms > 0) {
// Stop the current timer if already running
- uv_timer_stop(&input->timer_handle);
- uv_timer_start(&input->timer_handle, timer_cb, (uint32_t)ms, 0);
+ time_watcher_stop(&input->timer_handle);
+ time_watcher_start(&input->timer_handle, timer_cb, (uint32_t)ms, 0);
} else {
tk_getkeys(input, true);
}
}
-
-static void timer_cb(uv_timer_t *handle)
+static void timer_cb(TimeWatcher *watcher, void *data)
{
- tk_getkeys(handle->data, true);
+ tk_getkeys(data, true);
}
static bool handle_bracketed_paste(TermInput *input)
{
- if (rbuffer_size(input->read_buffer) > 5 &&
- (!rbuffer_cmp(input->read_buffer, "\x1b[200~", 6) ||
- !rbuffer_cmp(input->read_buffer, "\x1b[201~", 6))) {
- bool enable = *rbuffer_get(input->read_buffer, 4) == '0';
+ if (rbuffer_size(input->read_stream.buffer) > 5 &&
+ (!rbuffer_cmp(input->read_stream.buffer, "\x1b[200~", 6) ||
+ !rbuffer_cmp(input->read_stream.buffer, "\x1b[201~", 6))) {
+ bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0';
// Advance past the sequence
- rbuffer_consumed(input->read_buffer, 6);
+ rbuffer_consumed(input->read_stream.buffer, 6);
if (input->paste_enabled == enable) {
return true;
}
@@ -194,19 +193,23 @@ static bool handle_bracketed_paste(TermInput *input)
static bool handle_forced_escape(TermInput *input)
{
- if (rbuffer_size(input->read_buffer) > 1
- && !rbuffer_cmp(input->read_buffer, "\x1b\x00", 2)) {
+ if (rbuffer_size(input->read_stream.buffer) > 1
+ && !rbuffer_cmp(input->read_stream.buffer, "\x1b\x00", 2)) {
// skip the ESC and NUL and push one <esc> to the input buffer
size_t rcnt;
- termkey_push_bytes(input->tk, rbuffer_read_ptr(input->read_buffer, &rcnt), 1);
- rbuffer_consumed(input->read_buffer, 2);
+ termkey_push_bytes(input->tk, rbuffer_read_ptr(input->read_stream.buffer,
+ &rcnt), 1);
+ rbuffer_consumed(input->read_stream.buffer, 2);
tk_getkeys(input, true);
return true;
}
return false;
}
-static void read_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
+static void restart_reading(void **argv);
+
+static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
+ bool eof)
{
TermInput *input = data;
@@ -223,8 +226,8 @@ static void read_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
//
// ls *.md | xargs nvim
input->in_fd = 2;
- rstream_set_file(input->read_stream, input->in_fd);
- rstream_start(input->read_stream);
+ stream_close(&input->read_stream, NULL);
+ queue_put(loop.fast_events, restart_reading, 1, input);
} else {
input_done();
}
@@ -240,7 +243,7 @@ static void read_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
// so the `handle_bracketed_paste`/`handle_forced_escape` calls above work
// as expected.
size_t count = 0;
- RBUFFER_EACH(input->read_buffer, c, i) {
+ RBUFFER_EACH(input->read_stream.buffer, c, i) {
count = i + 1;
if (c == '\x1b' && count > 1) {
count--;
@@ -248,13 +251,13 @@ static void read_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
}
}
- RBUFFER_UNTIL_EMPTY(input->read_buffer, ptr, len) {
+ RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
size_t consumed = termkey_push_bytes(input->tk, ptr, MIN(count, len));
// termkey_push_bytes can return (size_t)-1, so it is possible that
- // `consumed > input->read_buffer->size`, but since tk_getkeys is called
- // soon, it shouldn't happen
- assert(consumed <= input->read_buffer->size);
- rbuffer_consumed(input->read_buffer, consumed);
+ // `consumed > input->read_stream.buffer->size`, but since tk_getkeys is
+ // called soon, it shouldn't happen
+ assert(consumed <= input->read_stream.buffer->size);
+ rbuffer_consumed(input->read_stream.buffer, consumed);
// Need to process the keys now since there's no guarantee "count" will
// fit into libtermkey's input buffer.
tk_getkeys(input, false);
@@ -262,11 +265,18 @@ static void read_cb(RStream *rstream, RBuffer *buf, void *data, bool eof)
break;
}
}
- } while (rbuffer_size(input->read_buffer));
+ } while (rbuffer_size(input->read_stream.buffer));
// Make sure the next input escape sequence fits into the ring buffer
// without wrap around, otherwise it could be misinterpreted.
- rbuffer_reset(input->read_buffer);
+ rbuffer_reset(input->read_stream.buffer);
+}
+
+static void restart_reading(void **argv)
+{
+ TermInput *input = argv[0];
+ rstream_init_fd(&loop, &input->read_stream, input->in_fd, 0xfff, input);
+ rstream_start(&input->read_stream, read_cb);
}
static TermInput *term_input_new(void)
@@ -283,13 +293,10 @@ static TermInput *term_input_new(void)
int curflags = termkey_get_canonflags(rv->tk);
termkey_set_canonflags(rv->tk, curflags | TERMKEY_CANON_DELBS);
// setup input handle
- rv->read_buffer = rbuffer_new(0xfff);
- rv->read_stream = rstream_new(read_cb, rv->read_buffer, rv);
- rstream_set_file(rv->read_stream, rv->in_fd);
- rstream_start(rv->read_stream);
+ rstream_init_fd(&loop, &rv->read_stream, rv->in_fd, 0xfff, rv);
+ rstream_start(&rv->read_stream, read_cb);
// initialize a timer handle for handling ESC with libtermkey
- uv_timer_init(uv_default_loop(), &rv->timer_handle);
- rv->timer_handle.data = rv;
+ time_watcher_init(&loop, &rv->timer_handle, rv);
// Set the pastetoggle option to a special key that will be sent when
// \e[20{0,1}~/ are received
Error err = ERROR_INIT;
@@ -300,12 +307,13 @@ static TermInput *term_input_new(void)
static void term_input_destroy(TermInput *input)
{
- uv_timer_stop(&input->timer_handle);
- rstream_stop(input->read_stream);
- rstream_free(input->read_stream);
- uv_close((uv_handle_t *)&input->timer_handle, NULL);
+ time_watcher_stop(&input->timer_handle);
+ time_watcher_close(&input->timer_handle, NULL);
+ rstream_stop(&input->read_stream);
+ stream_close(&input->read_stream, NULL);
termkey_destroy(input->tk);
- event_poll(0); // Run once to remove references to input/timer handles
+ // Run once to remove references to input/timer handles
+ loop_poll_events(&loop, 0);
xfree(input);
}
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index fe29dbd961..57a2b896f7 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1,6 +1,7 @@
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
+#include <limits.h>
#include <uv.h>
#include <unibilium.h>
@@ -13,7 +14,8 @@
#include "nvim/memory.h"
#include "nvim/api/vim.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/signal.h"
#include "nvim/tui/tui.h"
#include "nvim/strings.h"
@@ -43,7 +45,7 @@ typedef struct {
uv_loop_t *write_loop;
unibi_term *ut;
uv_tty_t output_handle;
- uv_signal_t winch_handle;
+ SignalWatcher winch_handle;
Rect scroll_region;
kvec_t(Rect) invalid_regions;
int row, col;
@@ -55,14 +57,17 @@ typedef struct {
bool busy;
HlAttrs attrs, print_attrs;
Cell **screen;
+ int showing_mode;
struct {
int enable_mouse, disable_mouse;
int enable_bracketed_paste, disable_bracketed_paste;
- int enter_insert_mode, exit_insert_mode;
+ int enter_insert_mode, enter_replace_mode, exit_insert_mode;
int set_rgb_foreground, set_rgb_background;
} unibi_ext;
} TUIData;
+static bool volatile got_winch = false;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/tui.c.generated.h"
#endif
@@ -96,11 +101,13 @@ UI *tui_start(void)
data->can_use_terminal_scroll = true;
data->bufpos = 0;
data->bufsize = sizeof(data->buf) - CNORM_COMMAND_MAX_SIZE;
+ data->showing_mode = 0;
data->unibi_ext.enable_mouse = -1;
data->unibi_ext.disable_mouse = -1;
data->unibi_ext.enable_bracketed_paste = -1;
data->unibi_ext.disable_bracketed_paste = -1;
data->unibi_ext.enter_insert_mode = -1;
+ data->unibi_ext.enter_replace_mode = -1;
data->unibi_ext.exit_insert_mode = -1;
// write output to stderr if stdout is not a tty
@@ -132,9 +139,8 @@ UI *tui_start(void)
update_size(ui);
// listen for SIGWINCH
- uv_signal_init(uv_default_loop(), &data->winch_handle);
- uv_signal_start(&data->winch_handle, sigwinch_cb, SIGWINCH);
- data->winch_handle.data = ui;
+ signal_watcher_init(&loop, &data->winch_handle, ui);
+ signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH);
ui->stop = tui_stop;
ui->rgb = os_getenv("NVIM_TUI_ENABLE_TRUE_COLOR") != NULL;
@@ -147,8 +153,7 @@ UI *tui_start(void)
ui->busy_stop = tui_busy_stop;
ui->mouse_on = tui_mouse_on;
ui->mouse_off = tui_mouse_off;
- ui->insert_mode = tui_insert_mode;
- ui->normal_mode = tui_normal_mode;
+ ui->mode_change = tui_mode_change;
ui->set_scroll_region = tui_set_scroll_region;
ui->scroll = tui_scroll;
ui->highlight_set = tui_highlight_set;
@@ -172,12 +177,12 @@ static void tui_stop(UI *ui)
TUIData *data = ui->data;
// Destroy common stuff
kv_destroy(data->invalid_regions);
- uv_signal_stop(&data->winch_handle);
- uv_close((uv_handle_t *)&data->winch_handle, NULL);
+ signal_watcher_stop(&data->winch_handle);
+ signal_watcher_close(&data->winch_handle, NULL);
// Destroy input stuff
term_input_destroy(data->input);
// Destroy output stuff
- tui_normal_mode(ui);
+ tui_mode_change(ui, NORMAL);
tui_mouse_off(ui);
unibi_out(ui, unibi_exit_attribute_mode);
// cursor should be set to normal before exiting alternate screen
@@ -200,23 +205,14 @@ static void tui_stop(UI *ui)
xfree(ui);
}
-static void try_resize(Event ev)
+static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)
{
- UI *ui = ev.data;
+ got_winch = true;
+ UI *ui = data;
update_size(ui);
ui_refresh();
}
-static void sigwinch_cb(uv_signal_t *handle, int signum)
-{
- // Queue the event because resizing can result in recursive event_poll calls
- // FIXME(blueyed): TUI does not resize properly when not deferred. Why? #2322
- event_push((Event) {
- .data = handle->data,
- .handler = try_resize
- }, true);
-}
-
static bool attrs_differ(HlAttrs a1, HlAttrs a2)
{
return a1.foreground != a2.foreground || a1.background != a2.background
@@ -350,6 +346,14 @@ static void tui_resize(UI *ui, int width, int height)
data->scroll_region.left = 0;
data->scroll_region.right = width - 1;
data->row = data->col = 0;
+
+ if (!got_winch) { // Try to resize the terminal window.
+ char r[16]; // enough for 9999x9999
+ snprintf(r, sizeof(r), "\x1b[8;%d;%dt", height, width);
+ out(ui, r, strlen(r));
+ } else { // Already handled the SIGWINCH signal; avoid double-resize.
+ got_winch = false;
+ }
}
static void tui_clear(UI *ui)
@@ -398,16 +402,25 @@ static void tui_mouse_off(UI *ui)
data->mouse_enabled = false;
}
-static void tui_insert_mode(UI *ui)
+static void tui_mode_change(UI *ui, int mode)
{
TUIData *data = ui->data;
- unibi_out(ui, data->unibi_ext.enter_insert_mode);
-}
-static void tui_normal_mode(UI *ui)
-{
- TUIData *data = ui->data;
- unibi_out(ui, data->unibi_ext.exit_insert_mode);
+ if (mode == INSERT) {
+ if (data->showing_mode != INSERT) {
+ unibi_out(ui, data->unibi_ext.enter_insert_mode);
+ }
+ } else if (mode == REPLACE) {
+ if (data->showing_mode != REPLACE) {
+ unibi_out(ui, data->unibi_ext.enter_replace_mode);
+ }
+ } else {
+ assert(mode == NORMAL);
+ if (data->showing_mode != NORMAL) {
+ unibi_out(ui, data->unibi_ext.exit_insert_mode);
+ }
+ }
+ data->showing_mode = mode;
}
static void tui_set_scroll_region(UI *ui, int top, int bot, int left,
@@ -641,12 +654,22 @@ static void update_size(UI *ui)
{
TUIData *data = ui->data;
int width = 0, height = 0;
- // 1 - try from a system call(ioctl/TIOCGWINSZ on unix)
+
+ // 1 - look for non-default 'columns' and 'lines' options during startup
+ if (starting != 0 && (Columns != DFLT_COLS || Rows != DFLT_ROWS)) {
+ assert(Columns >= INT_MIN && Columns <= INT_MAX);
+ assert(Rows >= INT_MIN && Rows <= INT_MAX);
+ width = (int)Columns;
+ height = (int)Rows;
+ goto end;
+ }
+
+ // 2 - try from a system call(ioctl/TIOCGWINSZ on unix)
if (!uv_tty_get_winsize(&data->output_handle, &width, &height)) {
goto end;
}
- // 2 - use $LINES/$COLUMNS if available
+ // 3 - use $LINES/$COLUMNS if available
const char *val;
int advance;
if ((val = os_getenv("LINES"))
@@ -656,15 +679,15 @@ static void update_size(UI *ui)
goto end;
}
- // 3- read from terminfo if available
+ // 4 - read from terminfo if available
height = unibi_get_num(data->ut, unibi_lines);
width = unibi_get_num(data->ut, unibi_columns);
end:
if (width <= 0 || height <= 0) {
- // use a default of 80x24
- width = 80;
- height = 24;
+ // use the defaults
+ width = DFLT_COLS;
+ height = DFLT_ROWS;
}
ui->width = width;
@@ -756,12 +779,10 @@ static void fix_terminfo(TUIData *data)
unibi_set_if_empty(ut, unibi_from_status_line, "\x07");
}
- if (STARTS_WITH(term, "xterm") || STARTS_WITH(term, "rxvt") || inside_tmux) {
- data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL,
- "\x1b[?2004h");
- data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL,
- "\x1b[?2004l");
- }
+ data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL,
+ "\x1b[?2004h");
+ data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL,
+ "\x1b[?2004l");
#define XTERM_SETAF \
"\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"
@@ -784,18 +805,25 @@ static void fix_terminfo(TUIData *data)
#define TMUX_WRAP(seq) (inside_tmux ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq)
// Support changing cursor shape on some popular terminals.
const char *term_prog = os_getenv("TERM_PROGRAM");
+ const char *vte_version = os_getenv("VTE_VERSION");
- if ((term_prog && !strcmp(term_prog, "iTerm.app"))
- || os_getenv("ITERM_SESSION_ID") != NULL) {
- // iterm
+ if ((term_prog && !strcmp(term_prog, "Konsole"))
+ || os_getenv("KONSOLE_DBUS_SESSION") != NULL) {
+ // Konsole uses a proprietary escape code to set the cursor shape
+ // and does not suppport DECSCUSR.
data->unibi_ext.enter_insert_mode = (int)unibi_add_ext_str(ut, NULL,
TMUX_WRAP("\x1b]50;CursorShape=1;BlinkingCursorEnabled=1\x07"));
+ data->unibi_ext.enter_replace_mode = (int)unibi_add_ext_str(ut, NULL,
+ TMUX_WRAP("\x1b]50;CursorShape=2;BlinkingCursorEnabled=1\x07"));
data->unibi_ext.exit_insert_mode = (int)unibi_add_ext_str(ut, NULL,
TMUX_WRAP("\x1b]50;CursorShape=0;BlinkingCursorEnabled=0\x07"));
- } else {
- // xterm-like sequences for blinking bar and solid block
+ } else if (!vte_version || atoi(vte_version) >= 3900) {
+ // Assume that the terminal supports DECSCUSR unless it is an
+ // old VTE based terminal
data->unibi_ext.enter_insert_mode = (int)unibi_add_ext_str(ut, NULL,
TMUX_WRAP("\x1b[5 q"));
+ data->unibi_ext.enter_replace_mode = (int)unibi_add_ext_str(ut, NULL,
+ TMUX_WRAP("\x1b[3 q"));
data->unibi_ext.exit_insert_mode = (int)unibi_add_ext_str(ut, NULL,
TMUX_WRAP("\x1b[2 q"));
}
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 088055777a..ad875367c9 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -23,7 +23,7 @@
#include "nvim/normal.h"
#include "nvim/option.h"
#include "nvim/os_unix.h"
-#include "nvim/os/event.h"
+#include "nvim/event/loop.h"
#include "nvim/os/time.h"
#include "nvim/os/input.h"
#include "nvim/os/signal.h"
@@ -121,7 +121,7 @@ void ui_update_encoding(void)
// May update the shape of the cursor.
void ui_cursor_shape(void)
{
- ui_change_mode();
+ ui_mode_change();
}
void ui_refresh(void)
@@ -214,9 +214,9 @@ void ui_detach(UI *ui)
shift_index++;
}
- ui_count--;
- // schedule a refresh
- event_push((Event) { .handler = refresh }, false);
+ if (--ui_count) {
+ ui_refresh();
+ }
}
void ui_clear(void)
@@ -469,32 +469,19 @@ static void flush_cursor_update(void)
// Notify that the current mode has changed. Can be used to change cursor
// shape, for example.
-static void ui_change_mode(void)
+static void ui_mode_change(void)
{
- static int showing_insert_mode = MAYBE;
-
+ int mode;
if (!full_screen) {
return;
}
-
- if (State & INSERT) {
- if (showing_insert_mode != TRUE) {
- UI_CALL(insert_mode);
- }
- showing_insert_mode = TRUE;
- } else {
- if (showing_insert_mode != FALSE) {
- UI_CALL(normal_mode);
- }
- showing_insert_mode = FALSE;
- }
+ /* Get a simple UI mode out of State. */
+ if ((State & REPLACE) == REPLACE)
+ mode = REPLACE;
+ else if (State & INSERT)
+ mode = INSERT;
+ else
+ mode = NORMAL;
+ UI_CALL(mode_change, mode);
conceal_check_cursur_line();
}
-
-static void refresh(Event event)
-{
- if (ui_count) {
- ui_refresh();
- }
-}
-
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 76ceec7775..9cfd99c096 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -24,8 +24,7 @@ struct ui_t {
void (*busy_stop)(UI *ui);
void (*mouse_on)(UI *ui);
void (*mouse_off)(UI *ui);
- void (*insert_mode)(UI *ui);
- void (*normal_mode)(UI *ui);
+ void (*mode_change)(UI *ui, int mode);
void (*set_scroll_region)(UI *ui, int top, int bot, int left, int right);
void (*scroll)(UI *ui, int count);
void (*highlight_set)(UI *ui, HlAttrs attrs);
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 757fdf385c..7ab7467661 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -71,9 +71,61 @@ static char *features[] = {
// clang-format off
static int included_patches[] = {
+ //790,
+ //789,
+ //788,
+ //787,
+ //786,
+ //785,
+ 784,
+ //783,
+ //782,
+ 781,
+ //780,
+ //779,
+ //778,
+ //777,
+ 776,
+ 775,
+ 774,
+ 773,
+ //772,
+ //771,
+ //770,
+ //769,
+ //768,
+ //767,
+ //766,
+ //765,
+ //764,
+ //763,
+ //762,
+ //761,
+ //760,
+ //759,
+ //758,
+ //757,
+ //756,
+ //755,
+ //754,
+ //753,
+ //752,
+ //751,
+ //750,
+ //749,
+ //748,
+ //747,
+ //746,
+ //745,
+ //744,
+ //743,
+ //742,
+ //741,
+ //740,
+ //739,
//738 NA
//737,
- //736,
+ 736,
//735,
//734,
//733,
@@ -141,8 +193,8 @@ static int included_patches[] = {
//671,
//670,
//669 NA
- //668,
- //667,
+ 668,
+ 667,
//666 NA
//665,
//664 NA
@@ -209,7 +261,7 @@ static int included_patches[] = {
//603,
//602,
601,
- //600,
+ 600,
599,
//598,
597,
@@ -1046,6 +1098,15 @@ void intro_message(int colon)
N_("by Bram Moolenaar et al."),
N_("Vim is open source and freely distributable"),
"",
+ N_("First time using a vi-like editor?"),
+ N_("Type :Tutor<Enter> to get started!"),
+ "",
+ N_("Already know your way around Vim?"),
+ N_("See :help nvim-intro for an introduction to Neovim."),
+ "",
+ N_("Still have questions?"),
+ N_("Reach out to the Neovim community at neovim.io/community."),
+ "",
N_("Help poor children in Uganda!"),
N_("type :help iccf<Enter> for information "),
"",
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index c88a8872f3..9fbc6dd300 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -6,7 +6,7 @@
*/
#ifndef NVIM_VIM_H
-# define NVIM_VIM_H
+#define NVIM_VIM_H
#define MIN(X, Y) (X < Y ? X : Y)
#define MAX(X, Y) (X > Y ? X : Y)
@@ -332,20 +332,15 @@ enum {
/* Maximum number of bytes in a multi-byte character. It can be one 32-bit
* character of up to 6 bytes, or one 16-bit character of up to three bytes
* plus six following composing characters of three bytes each. */
-# define MB_MAXBYTES 21
+#define MB_MAXBYTES 21
/* This has to go after the include of proto.h, as proto/gui.pro declares
* functions of these names. The declarations would break if the defines had
* been seen at that stage. But it must be before globals.h, where error_ga
* is declared. */
-#if !defined(FEAT_GUI_W32) && !defined(FEAT_GUI_X11) \
- && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MAC)
-# define mch_errmsg(str) fprintf(stderr, "%s", (str))
-# define display_errors() fflush(stderr)
-# define mch_msg(str) printf("%s", (str))
-#else
-# define USE_MCH_ERRMSG
-#endif
+#define mch_errmsg(str) fprintf(stderr, "%s", (str))
+#define display_errors() fflush(stderr)
+#define mch_msg(str) printf("%s", (str))
#include "nvim/globals.h" /* global variables and messages */
#include "nvim/buffer_defs.h" /* buffer and windows */
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index b85594f7af..c924988d06 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -35,6 +35,20 @@ describe('buffer_* functions', function()
eq('', curbuf('get_line', 0))
end)
+ it('get_line: out-of-bounds returns empty string', function()
+ curbuf('set_line', 0, 'line1.a')
+ eq('', curbuf('get_line', 1))
+ eq('', curbuf('get_line', -2))
+ end)
+
+ it('set_line, del_line: out-of-bounds is an error', function()
+ curbuf('set_line', 0, 'line1.a')
+ eq(false, pcall(curbuf, 'set_line', 1, 'line1.b'))
+ eq(false, pcall(curbuf, 'set_line', -2, 'line1.b'))
+ eq(false, pcall(curbuf, 'del_line', 2))
+ eq(false, pcall(curbuf, 'del_line', -3))
+ end)
+
it('can handle NULs', function()
curbuf('set_line', 0, 'ab\0cd')
eq('ab\0cd', curbuf('get_line', 0))
@@ -43,6 +57,27 @@ describe('buffer_* functions', function()
describe('{get,set}_line_slice', function()
+ it('get_line_slice: out-of-bounds returns empty array', function()
+ curbuf('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'})
+ eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 2, true, true)) --sanity
+
+ eq({}, curbuf('get_line_slice', 2, 3, false, true))
+ eq({}, curbuf('get_line_slice', 3, 9, true, true))
+ eq({}, curbuf('get_line_slice', 3, -1, true, true))
+ eq({}, curbuf('get_line_slice', -3, -4, false, true))
+ eq({}, curbuf('get_line_slice', -4, -5, true, true))
+ end)
+
+ it('set_line_slice: out-of-bounds is an error', function()
+ curbuf('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'})
+ eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 2, true, true)) --sanity
+
+ eq({'c'}, curbuf('get_line_slice', -1, 4, true, true))
+ eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 5, true, true))
+ eq(false, pcall(curbuf, 'set_line_slice', 4, 5, true, true, {'d'}))
+ eq(false, pcall(curbuf, 'set_line_slice', -4, -5, true, true, {'d'}))
+ end)
+
it('works', function()
eq({''}, curbuf('get_line_slice', 0, -1, true, true))
-- Replace buffer
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index c158c26341..9e880a4f04 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -34,6 +34,15 @@ describe('vim_* functions', function()
end)
end)
+ describe('call_function', function()
+ it('works', function()
+ nvim('call_function', 'setqflist', {{{ filename = 'something', lnum = 17}}, 'r'})
+ eq(17, nvim('call_function', 'getqflist', {})[1].lnum)
+ eq(17, nvim('call_function', 'eval', {17}))
+ eq('foo', nvim('call_function', 'simplify', {'this/./is//redundant/../../../foo'}))
+ end)
+ end)
+
describe('strwidth', function()
it('works', function()
eq(3, nvim('strwidth', 'abc'))
diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua
index 9282a66240..0550d22fa6 100644
--- a/test/functional/clipboard/clipboard_provider_spec.lua
+++ b/test/functional/clipboard/clipboard_provider_spec.lua
@@ -92,7 +92,7 @@ end)
describe('clipboard usage', function()
before_each(function()
clear()
- execute('let &rtp = "test/functional/clipboard,".&rtp')
+ execute('let &rtp = "test/functional/fixtures,".&rtp')
execute('call getreg("*")') -- force load of provider
end)
@@ -197,6 +197,17 @@ describe('clipboard usage', function()
expect('some more')
end)
+ it('pastes unnamed register if the provider fails', function()
+ insert('the text')
+ feed('yy')
+ execute("let g:cliperror = 1")
+ feed('"*p')
+ expect([[
+ the text
+ the text]])
+ end)
+
+
describe('with clipboard=unnamed', function()
-- the basic behavior of unnamed register should be the same
-- even when handled by clipboard provider
@@ -221,12 +232,15 @@ describe('clipboard usage', function()
expect('words')
eq({{'words'}, 'v'}, eval("g:test_clip['*']"))
+ -- "+ shouldn't have changed
+ eq({''}, eval("g:test_clip['+']"))
+
execute("let g:test_clip['*'] = ['linewise stuff','']")
feed('p')
expect([[
words
linewise stuff]])
- end)
+ end)
it('does not clobber "0 when pasting', function()
insert('a line')
@@ -261,6 +275,60 @@ describe('clipboard usage', function()
expect("indeed star")
end)
+ it('unamed operations work even if the provider fails', function()
+ insert('the text')
+ feed('yy')
+ execute("let g:cliperror = 1")
+ feed('p')
+ expect([[
+ the text
+ the text]])
+ end)
+
+ end)
+
+ describe('with clipboard=unnamedplus', function()
+ before_each(function()
+ execute('set clipboard=unnamedplus')
+ end)
+
+ it('links the "+ and unnamed registers', function()
+ insert("one two")
+ feed('^"+dwdw"+P')
+ expect('two')
+ eq({{'two'}, 'v'}, eval("g:test_clip['+']"))
+
+ -- "* shouldn't have changed
+ eq({''}, eval("g:test_clip['*']"))
+
+ execute("let g:test_clip['+'] = ['three']")
+ feed('p')
+ expect('twothree')
+ end)
+
+ it('and unnamed, yanks to both', function()
+ execute('set clipboard=unnamedplus,unnamed')
+ insert([[
+ really unnamed
+ text]])
+ feed('ggdd"*p"+p')
+ expect([[
+ text
+ really unnamed
+ really unnamed]])
+ eq({{'really unnamed', ''}, 'V'}, eval("g:test_clip['+']"))
+ eq({{'really unnamed', ''}, 'V'}, eval("g:test_clip['*']"))
+
+ -- unnamedplus takes predecence when pasting
+ execute("let g:test_clip['+'] = ['the plus','']")
+ execute("let g:test_clip['*'] = ['the star','']")
+ feed("p")
+ expect([[
+ text
+ really unnamed
+ really unnamed
+ the plus]])
+ end)
end)
it('supports :put', function()
@@ -301,6 +369,7 @@ describe('clipboard usage', function()
[2] = {foreground = Screen.colors.Blue},
[3] = {bold = true, foreground = Screen.colors.SeaGreen}},
{{bold = true, foreground = Screen.colors.Blue}})
+ feed('<cr>') -- clear out of Press ENTER screen
end)
it('can paste "* to the commandline', function()
@@ -335,4 +404,34 @@ describe('clipboard usage', function()
'Howdy!',
}, 'v'}, eval("g:test_clip['*']"))
end)
+
+ it('handles middleclick correctly', function()
+ local screen = Screen.new(30, 5)
+ screen:attach()
+ insert([[
+ the source
+ a target]])
+ feed('gg"*ywwyw')
+ -- clicking depends on the exact visual layout, so expect it:
+ screen:expect([[
+ the ^source |
+ a target |
+ ~ |
+ ~ |
+ |
+ ]], nil, {{bold = true, foreground = Screen.colors.Blue}})
+
+ feed('<MiddleMouse><0,1>')
+ expect([[
+ the source
+ the a target]])
+
+ -- on error, fall back to unnamed register
+ execute("let g:cliperror = 1")
+ feed('<MiddleMouse><6,1>')
+ expect([[
+ the source
+ the a sourcetarget]])
+ end)
+
end)
diff --git a/test/functional/eval/glob_spec.lua b/test/functional/eval/glob_spec.lua
new file mode 100644
index 0000000000..136417249c
--- /dev/null
+++ b/test/functional/eval/glob_spec.lua
@@ -0,0 +1,25 @@
+local helpers = require('test.functional.helpers')
+local clear, execute, eval, eq = helpers.clear, helpers.execute, helpers.eval, helpers.eq
+
+before_each(function()
+ clear()
+ lfs.mkdir('test-glob')
+ execute('cd test-glob')
+end)
+
+after_each(function()
+ lfs.rmdir('test-glob')
+end)
+
+describe('glob()', function()
+ it("glob('.*') returns . and .. ", function()
+ eq({'.', '..'}, eval("glob('.*', 0, 1)"))
+ -- Do it again to verify scandir_next_with_dots() internal state.
+ eq({'.', '..'}, eval("glob('.*', 0, 1)"))
+ end)
+ it("glob('*') returns an empty list ", function()
+ eq({}, eval("glob('*', 0, 1)"))
+ -- Do it again to verify scandir_next_with_dots() internal state.
+ eq({}, eval("glob('*', 0, 1)"))
+ end)
+end)
diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua
new file mode 100644
index 0000000000..8ca2cca32c
--- /dev/null
+++ b/test/functional/eval/msgpack_functions_spec.lua
@@ -0,0 +1,615 @@
+local helpers = require('test.functional.helpers')
+local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
+local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq
+local execute, source = helpers.execute, helpers.source
+local nvim = helpers.nvim
+describe('msgpack*() functions', function()
+ before_each(function()
+ clear()
+ end)
+ local obj_test = function(msg, obj)
+ it(msg, function()
+ nvim('set_var', 'obj', obj)
+ eq(obj, eval('msgpackparse(msgpackdump(g:obj))'))
+ end)
+ end
+ -- Regression test: msgpack_list_write was failing to write buffer with zero
+ -- length.
+ obj_test('are able to dump and restore {"file": ""}', {{file=''}})
+ -- Regression test: msgpack_list_write was failing to write buffer with NL at
+ -- the end.
+ obj_test('are able to dump and restore {0, "echo mpack"}', {{0, 'echo mpack'}})
+ obj_test('are able to dump and restore "Test\\n"', {'Test\n'})
+ -- Regression test: msgpack_list_write was failing to write buffer with NL
+ -- inside.
+ obj_test('are able to dump and restore "Test\\nTest 2"', {'Test\nTest 2'})
+ -- Test that big objects (requirement: dump to something that is bigger then
+ -- IOSIZE) are also fine. This particular object is obtained by concatenating
+ -- 5 identical shada files.
+ local big_obj = {
+ 1, 1436711454, 78, {
+ encoding="utf-8",
+ max_kbyte=10,
+ pid=19269,
+ version="NVIM 0.0.0-alpha+201507121634"
+ },
+ 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 8, 1436711391, 8, { file="" },
+ 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" },
+ 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" },
+ 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" },
+ 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" },
+ 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" },
+ 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" },
+ 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" },
+ 4, 1436708101, 25, { 0, "echo msgpackdump([1])" },
+ 4, 1436708966, 6, { 0, "cq" },
+ 4, 1436709606, 25, { 0, "echo msgpackdump([5])" },
+ 4, 1436709610, 26, { 0, "echo msgpackdump([10])" },
+ 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" },
+ 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" },
+ 4, 1436709634, 57, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])"
+ },
+ 4, 1436709651, 67, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])"
+ },
+ 4, 1436709660, 70, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])"
+ },
+ 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" },
+ 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" },
+ 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" },
+ 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" },
+ 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" },
+ 4, 1436711142, 14, { 0, "echo mpack" },
+ 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" },
+ 4, 1436711206, 16, { 0, "echo lengths" },
+ 4, 1436711244, 92, {
+ 0,
+ ("let sum = len(lengths) - 1 | call map(copy(lengths), "
+ .. "'extend(g:, {\"sum\": sum + v:val})')")
+ },
+ 4, 1436711245, 12, { 0, "echo sum" },
+ 4, 1436711398, 10, { 0, "echo s" },
+ 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" },
+ 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" },
+ 4, 1436711415, 22, { 0, "echo shada_objects" },
+ 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" },
+ 4, 1436711454, 6, { 0, "qa" },
+ 4, 1436711442, 9, { 1, "test", 47 },
+ 4, 1436711443, 15, { 1, "aontsuesan", 47 },
+ 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 },
+ 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 },
+ 3, 0, 3, { "" },
+ 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 1, 1436711454, 78, {
+ encoding="utf-8",
+ max_kbyte=10,
+ pid=19269,
+ version="NVIM 0.0.0-alpha+201507121634"
+ },
+ 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 8, 1436711391, 8, { file="" },
+ 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" },
+ 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" },
+ 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" },
+ 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" },
+ 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" },
+ 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" },
+ 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" },
+ 4, 1436708101, 25, { 0, "echo msgpackdump([1])" },
+ 4, 1436708966, 6, { 0, "cq" },
+ 4, 1436709606, 25, { 0, "echo msgpackdump([5])" },
+ 4, 1436709610, 26, { 0, "echo msgpackdump([10])" },
+ 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" },
+ 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" },
+ 4, 1436709634, 57, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])"
+ },
+ 4, 1436709651, 67, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])"
+ },
+ 4, 1436709660, 70, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])"
+ },
+ 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" },
+ 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" },
+ 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" },
+ 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" },
+ 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" },
+ 4, 1436711142, 14, { 0, "echo mpack" },
+ 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" },
+ 4, 1436711206, 16, { 0, "echo lengths" },
+ 4, 1436711244, 92, {
+ 0,
+ ("let sum = len(lengths) - 1 | call map(copy(lengths), "
+ .. "'extend(g:, {\"sum\": sum + v:val})')")
+ },
+ 4, 1436711245, 12, { 0, "echo sum" },
+ 4, 1436711398, 10, { 0, "echo s" },
+ 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" },
+ 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" },
+ 4, 1436711415, 22, { 0, "echo shada_objects" },
+ 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" },
+ 4, 1436711454, 6, { 0, "qa" },
+ 4, 1436711442, 9, { 1, "test", 47 },
+ 4, 1436711443, 15, { 1, "aontsuesan", 47 },
+ 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 },
+ 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 },
+ 3, 0, 3, { "" },
+ 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 1, 1436711454, 78, {
+ encoding="utf-8",
+ max_kbyte=10,
+ pid=19269,
+ version="NVIM 0.0.0-alpha+201507121634"
+ },
+ 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 8, 1436711391, 8, { file="" },
+ 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" },
+ 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" },
+ 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" },
+ 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" },
+ 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" },
+ 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" },
+ 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" },
+ 4, 1436708101, 25, { 0, "echo msgpackdump([1])" },
+ 4, 1436708966, 6, { 0, "cq" },
+ 4, 1436709606, 25, { 0, "echo msgpackdump([5])" },
+ 4, 1436709610, 26, { 0, "echo msgpackdump([10])" },
+ 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" },
+ 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" },
+ 4, 1436709634, 57, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])"
+ },
+ 4, 1436709651, 67, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])"
+ },
+ 4, 1436709660, 70, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])"
+ },
+ 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" },
+ 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" },
+ 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" },
+ 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" },
+ 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" },
+ 4, 1436711142, 14, { 0, "echo mpack" },
+ 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" },
+ 4, 1436711206, 16, { 0, "echo lengths" },
+ 4, 1436711244, 92, {
+ 0,
+ ("let sum = len(lengths) - 1 | call map(copy(lengths), "
+ .. "'extend(g:, {\"sum\": sum + v:val})')")
+ },
+ 4, 1436711245, 12, { 0, "echo sum" },
+ 4, 1436711398, 10, { 0, "echo s" },
+ 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" },
+ 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" },
+ 4, 1436711415, 22, { 0, "echo shada_objects" },
+ 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" },
+ 4, 1436711454, 6, { 0, "qa" },
+ 4, 1436711442, 9, { 1, "test", 47 },
+ 4, 1436711443, 15, { 1, "aontsuesan", 47 },
+ 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 },
+ 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 },
+ 3, 0, 3, { "" },
+ 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 1, 1436711454, 78, {
+ encoding="utf-8",
+ max_kbyte=10,
+ pid=19269,
+ version="NVIM 0.0.0-alpha+201507121634"
+ },
+ 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 8, 1436711391, 8, { file="" },
+ 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" },
+ 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" },
+ 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" },
+ 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" },
+ 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" },
+ 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" },
+ 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" },
+ 4, 1436708101, 25, { 0, "echo msgpackdump([1])" },
+ 4, 1436708966, 6, { 0, "cq" },
+ 4, 1436709606, 25, { 0, "echo msgpackdump([5])" },
+ 4, 1436709610, 26, { 0, "echo msgpackdump([10])" },
+ 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" },
+ 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" },
+ 4, 1436709634, 57, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])"
+ },
+ 4, 1436709651, 67, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])"
+ },
+ 4, 1436709660, 70, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])"
+ },
+ 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" },
+ 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" },
+ 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" },
+ 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" },
+ 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" },
+ 4, 1436711142, 14, { 0, "echo mpack" },
+ 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" },
+ 4, 1436711206, 16, { 0, "echo lengths" },
+ 4, 1436711244, 92, {
+ 0,
+ ("let sum = len(lengths) - 1 | call map(copy(lengths), "
+ .. "'extend(g:, {\"sum\": sum + v:val})')")
+ },
+ 4, 1436711245, 12, { 0, "echo sum" },
+ 4, 1436711398, 10, { 0, "echo s" },
+ 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" },
+ 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" },
+ 4, 1436711415, 22, { 0, "echo shada_objects" },
+ 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" },
+ 4, 1436711454, 6, { 0, "qa" },
+ 4, 1436711442, 9, { 1, "test", 47 },
+ 4, 1436711443, 15, { 1, "aontsuesan", 47 },
+ 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 },
+ 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 },
+ 3, 0, 3, { "" },
+ 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 1, 1436711454, 78, {
+ encoding="utf-8",
+ max_kbyte=10,
+ pid=19269,
+ version="NVIM 0.0.0-alpha+201507121634"
+ },
+ 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" },
+ 8, 1436711391, 8, { file="" },
+ 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" },
+ 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" },
+ 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" },
+ 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" },
+ 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" },
+ 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" },
+ 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" },
+ 4, 1436708101, 25, { 0, "echo msgpackdump([1])" },
+ 4, 1436708966, 6, { 0, "cq" },
+ 4, 1436709606, 25, { 0, "echo msgpackdump([5])" },
+ 4, 1436709610, 26, { 0, "echo msgpackdump([10])" },
+ 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" },
+ 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" },
+ 4, 1436709634, 57, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])"
+ },
+ 4, 1436709651, 67, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])"
+ },
+ 4, 1436709660, 70, {
+ 0,
+ "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])"
+ },
+ 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" },
+ 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" },
+ 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" },
+ 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" },
+ 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" },
+ 4, 1436711142, 14, { 0, "echo mpack" },
+ 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" },
+ 4, 1436711206, 16, { 0, "echo lengths" },
+ 4, 1436711244, 92, {
+ 0,
+ ("let sum = len(lengths) - 1 | call map(copy(lengths), "
+ .. "'extend(g:, {\"sum\": sum + v:val})')")
+ },
+ 4, 1436711245, 12, { 0, "echo sum" },
+ 4, 1436711398, 10, { 0, "echo s" },
+ 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" },
+ 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" },
+ 4, 1436711415, 22, { 0, "echo shada_objects" },
+ 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" },
+ 4, 1436711454, 6, { 0, "qa" },
+ 4, 1436711442, 9, { 1, "test", 47 },
+ 4, 1436711443, 15, { 1, "aontsuesan", 47 },
+ 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 },
+ 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 },
+ 3, 0, 3, { "" },
+ 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }
+ }
+ obj_test('are able to dump and restore rather big object', big_obj)
+
+ obj_test('are able to dump and restore floating-point value', {0.125})
+
+ it('restore nil as special dict', function()
+ execute('let dumped = ["\\xC0"]')
+ execute('let parsed = msgpackparse(dumped)')
+ eq({{_TYPE={}, _VAL=0}}, eval('parsed'))
+ eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.nil'))
+ end)
+
+ it('restore boolean false as zero', function()
+ execute('let dumped = ["\\xC2"]')
+ execute('let parsed = msgpackparse(dumped)')
+ eq({{_TYPE={}, _VAL=0}}, eval('parsed'))
+ eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.boolean'))
+ end)
+
+ it('restore boolean true as one', function()
+ execute('let dumped = ["\\xC3"]')
+ execute('let parsed = msgpackparse(dumped)')
+ eq({{_TYPE={}, _VAL=1}}, eval('parsed'))
+ eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.boolean'))
+ end)
+
+ it('dump string as BIN 8', function()
+ nvim('set_var', 'obj', {'Test'})
+ eq({"\196\004Test"}, eval('msgpackdump(obj)'))
+ end)
+
+ it('restore FIXSTR as special dict', function()
+ execute('let dumped = ["\\xa2ab"]')
+ execute('let parsed = msgpackparse(dumped)')
+ eq({{_TYPE={}, _VAL={'ab'}}}, eval('parsed'))
+ eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string'))
+ end)
+
+ it('restore BIN 8 as string', function()
+ execute('let dumped = ["\\xC4\\x02ab"]')
+ eq({'ab'}, eval('msgpackparse(dumped)'))
+ end)
+
+ it('restore FIXEXT1 as special dictionary', function()
+ execute('let dumped = ["\\xD4\\x10", ""]')
+ execute('let parsed = msgpackparse(dumped)')
+ eq({{_TYPE={}, _VAL={0x10, {"", ""}}}}, eval('parsed'))
+ eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext'))
+ end)
+
+ it('restore MAP with BIN key as special dictionary', function()
+ execute('let dumped = ["\\x81\\xC4\\x01a\\xC4\\n"]')
+ execute('let parsed = msgpackparse(dumped)')
+ eq({{_TYPE={}, _VAL={{'a', ''}}}}, eval('parsed'))
+ eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
+ end)
+
+ it('restore MAP with duplicate STR keys as special dictionary', function()
+ execute('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]')
+ execute('let parsed = msgpackparse(dumped)')
+ eq({{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'a'}}, ''},
+ {{_TYPE={}, _VAL={'a'}}, ''}}}}, eval('parsed'))
+ eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
+ eq(1, eval('g:parsed[0]._VAL[0][0]._TYPE is v:msgpack_types.string'))
+ eq(1, eval('g:parsed[0]._VAL[1][0]._TYPE is v:msgpack_types.string'))
+ end)
+
+ it('restore MAP with MAP key as special dictionary', function()
+ execute('let dumped = ["\\x81\\x80\\xC4\\n"]')
+ execute('let parsed = msgpackparse(dumped)')
+ eq({{_TYPE={}, _VAL={{{}, ''}}}}, eval('parsed'))
+ eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
+ end)
+
+ it('can restore and dump UINT64_MAX', function()
+ execute('let dumped = ["\\xCF" . repeat("\\xFF", 8)]')
+ execute('let parsed = msgpackparse(dumped)')
+ execute('let dumped2 = msgpackdump(parsed)')
+ eq(1, eval('type(parsed[0]) == type(0) ' ..
+ '|| parsed[0]._TYPE is v:msgpack_types.integer'))
+ if eval('type(parsed[0]) == type(0)') == 1 then
+ eq(1, eval('0xFFFFFFFFFFFFFFFF == parsed[0]'))
+ else
+ eq({_TYPE={}, _VAL={1, 3, 0x7FFFFFFF, 0x7FFFFFFF}}, eval('parsed[0]'))
+ end
+ eq(1, eval('dumped ==# dumped2'))
+ end)
+
+ it('can restore and dump INT64_MIN', function()
+ execute('let dumped = ["\\xD3\\x80" . repeat("\\n", 7)]')
+ execute('let parsed = msgpackparse(dumped)')
+ execute('let dumped2 = msgpackdump(parsed)')
+ eq(1, eval('type(parsed[0]) == type(0) ' ..
+ '|| parsed[0]._TYPE is v:msgpack_types.integer'))
+ if eval('type(parsed[0]) == type(0)') == 1 then
+ eq(1, eval('-0x8000000000000000 == parsed[0]'))
+ else
+ eq({_TYPE={}, _VAL={-1, 2, 0, 0}}, eval('parsed[0]'))
+ end
+ eq(1, eval('dumped ==# dumped2'))
+ end)
+
+ it('can restore and dump BIN string with zero byte', function()
+ execute('let dumped = ["\\xC4\\x01\\n"]')
+ execute('let parsed = msgpackparse(dumped)')
+ execute('let dumped2 = msgpackdump(parsed)')
+ eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed'))
+ eq(1, eval('parsed[0]._TYPE is v:msgpack_types.binary'))
+ eq(1, eval('dumped ==# dumped2'))
+ end)
+
+ it('can restore and dump STR string with zero byte', function()
+ execute('let dumped = ["\\xA1\\n"]')
+ execute('let parsed = msgpackparse(dumped)')
+ execute('let dumped2 = msgpackdump(parsed)')
+ eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed'))
+ eq(1, eval('parsed[0]._TYPE is v:msgpack_types.string'))
+ eq(1, eval('dumped ==# dumped2'))
+ end)
+
+ it('can restore and dump BIN string with NL', function()
+ execute('let dumped = ["\\xC4\\x01", ""]')
+ execute('let parsed = msgpackparse(dumped)')
+ execute('let dumped2 = msgpackdump(parsed)')
+ eq({"\n"}, eval('parsed'))
+ eq(1, eval('dumped ==# dumped2'))
+ end)
+
+ it('can dump generic mapping with generic mapping keys and values', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ execute('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ execute('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
+ execute('call add(todump._VAL, [todumpv1, todumpv2])')
+ eq({'\129\128\128'}, eval('msgpackdump([todump])'))
+ end)
+
+ it('can dump generic mapping with ext', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
+ eq({'\212\005', ''}, eval('msgpackdump([todump])'))
+ end)
+
+ it('can dump generic mapping with array', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
+ eq({'\146\005\145\196\n'}, eval('msgpackdump([todump])'))
+ end)
+
+ it('can dump generic mapping with UINT64_MAX', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.integer}')
+ execute('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
+ eq({'\207\255\255\255\255\255\255\255\255'}, eval('msgpackdump([todump])'))
+ end)
+
+ it('can dump generic mapping with INT64_MIN', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.integer}')
+ execute('let todump._VAL = [-1, 2, 0, 0]')
+ eq({'\211\128\n\n\n\n\n\n\n'}, eval('msgpackdump([todump])'))
+ end)
+
+ it('dump and restore generic mapping with floating-point value', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
+ eq({0.125}, eval('msgpackparse(msgpackdump([todump]))'))
+ end)
+
+ it('fails to dump a function reference', function()
+ execute('let Todump = function("tr")')
+ execute([[
+ try
+ let dumped = msgpackdump([Todump])
+ let exception = 0
+ catch
+ let exception = v:exception
+ endtry
+ ]])
+ eq('Vim(let):E475: Invalid argument: attempt to dump function reference',
+ eval('exception'))
+ end)
+
+ it('fails to dump a function reference in a list', function()
+ execute('let todump = [function("tr")]')
+ execute([[
+ try
+ let dumped = msgpackdump([todump])
+ let exception = 0
+ catch
+ let exception = v:exception
+ endtry
+ ]])
+ eq('Vim(let):E475: Invalid argument: attempt to dump function reference',
+ eval('exception'))
+ end)
+
+ it('fails to dump a recursive list', function()
+ execute('let todump = [[[]]]')
+ execute('call add(todump[0][0], todump)')
+ execute([[
+ try
+ let dumped = msgpackdump([todump])
+ let exception = 0
+ catch
+ let exception = v:exception
+ endtry
+ ]])
+ eq('Vim(let):E475: Invalid argument: container references itself',
+ eval('exception'))
+ end)
+
+ it('fails to dump a recursive dict', function()
+ execute('let todump = {"d": {"d": {}}}')
+ execute('call extend(todump.d.d, {"d": todump})')
+ execute([[
+ try
+ let dumped = msgpackdump([todump])
+ let exception = 0
+ catch
+ let exception = v:exception
+ endtry
+ ]])
+ eq('Vim(let):E475: Invalid argument: container references itself',
+ eval('exception'))
+ end)
+
+ it('fails to dump a recursive list in a special dict', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
+ execute('call add(todump._VAL, todump)')
+ execute([[
+ try
+ let dumped = msgpackdump([todump])
+ let exception = 0
+ catch
+ let exception = v:exception
+ endtry
+ ]])
+ eq('Vim(let):E475: Invalid argument: container references itself',
+ eval('exception'))
+ end)
+
+ it('fails to dump a recursive (key) map in a special dict', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
+ execute('call add(todump._VAL, [todump, 0])')
+ execute([[
+ try
+ let dumped = msgpackdump([todump])
+ let exception = 0
+ catch
+ let exception = v:exception
+ endtry
+ ]])
+ eq('Vim(let):E475: Invalid argument: container references itself',
+ eval('exception'))
+ end)
+
+ it('fails to dump a recursive (val) map in a special dict', function()
+ execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
+ execute('call add(todump._VAL, [0, todump])')
+ execute([[
+ try
+ let dumped = msgpackdump([todump])
+ let exception = 0
+ catch
+ let exception = v:exception
+ endtry
+ ]])
+ eq('Vim(let):E475: Invalid argument: container references itself',
+ eval('exception'))
+ end)
+
+ it('fails to dump a recursive (val) special list in a special dict',
+ function()
+ execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
+ execute('call add(todump._VAL, [0, todump._VAL])')
+ execute([[
+ try
+ let dumped = msgpackdump([todump])
+ let exception = 0
+ catch
+ let exception = v:exception
+ endtry
+ ]])
+ eq('Vim(let):E475: Invalid argument: container references itself',
+ eval('exception'))
+ end)
+
+ it('msgpackparse(systemlist(...)) does not segfault. #3135', function()
+ local cmd = "msgpackparse(systemlist('"
+ ..helpers.nvim_prog.." --api-info'))['_TYPE']['_VAL'][0][0]"
+ local api_info = eval(cmd)
+ api_info = eval(cmd) -- do it again (try to force segfault)
+ api_info = eval(cmd) -- do it again
+ eq('functions', api_info)
+ end)
+end)
diff --git a/test/functional/ex_cmds/grep_spec.lua b/test/functional/ex_cmds/grep_spec.lua
new file mode 100644
index 0000000000..9c792099c1
--- /dev/null
+++ b/test/functional/ex_cmds/grep_spec.lua
@@ -0,0 +1,22 @@
+local helpers = require('test.functional.helpers')
+local clear, execute, nvim, feed, eq, ok, eval =
+ helpers.clear, helpers.execute, helpers.nvim, helpers.feed,
+ helpers.eq, helpers.ok, helpers.eval
+
+describe(':grep', function()
+ before_each(clear)
+
+ it('does not hang on large input #2983', function()
+ if eval("executable('grep')") == 0 then
+ pending('missing "grep" command')
+ return
+ end
+
+ execute([[set grepprg=grep\ -r]])
+ -- Change to test directory so that the test does not run too long.
+ execute('cd test')
+ execute('grep a **/*')
+ feed('<cr>') -- Press ENTER
+ ok(eval('len(getqflist())') > 9000) -- IT'S OVER 9000!!1
+ end)
+end)
diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua
new file mode 100644
index 0000000000..6af889bf9e
--- /dev/null
+++ b/test/functional/ex_cmds/menu_spec.lua
@@ -0,0 +1,38 @@
+local helpers = require('test.functional.helpers')
+local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim
+local expect = helpers.expect
+local feed = helpers.feed
+local command = helpers.command
+
+describe(':emenu', function()
+
+ before_each(function()
+ clear()
+ execute('nnoremenu Test.Test inormal<ESC>')
+ execute('inoremenu Test.Test insert')
+ execute('vnoremenu Test.Test x')
+ end)
+
+ it('executes correct bindings in normal mode without using API', function()
+ execute('emenu Test.Test')
+ expect('normal')
+ end)
+
+ it('executes correct bindings in normal mode', function()
+ command('emenu Test.Test')
+ expect('normal')
+ end)
+
+ it('executes correct bindings in insert mode', function()
+ feed('i')
+ command('emenu Test.Test')
+ expect('insert')
+ end)
+
+ it('executes correct bindings in visual mode', function()
+ feed('iabcde<ESC>0lvll')
+ command('emenu Test.Test')
+ expect('ae')
+ end)
+
+end)
diff --git a/test/functional/ex_cmds/recover_spec.lua b/test/functional/ex_cmds/recover_spec.lua
index d4c9477133..b92739e40e 100644
--- a/test/functional/ex_cmds/recover_spec.lua
+++ b/test/functional/ex_cmds/recover_spec.lua
@@ -20,11 +20,11 @@ describe(':preserve', function()
local swapdir = lfs.currentdir()..'/testdir_recover_spec'
before_each(function()
clear()
- os.remove(swapdir)
+ helpers.rmdir(swapdir)
lfs.mkdir(swapdir)
end)
after_each(function()
- os.remove(swapdir)
+ helpers.rmdir(swapdir)
end)
it("saves to custom 'directory' and (R)ecovers (issue #1836)", function()
diff --git a/test/functional/clipboard/autoload/provider/clipboard.vim b/test/functional/fixtures/autoload/provider/clipboard.vim
index d88b68464e..0935ea45ff 100644
--- a/test/functional/clipboard/autoload/provider/clipboard.vim
+++ b/test/functional/fixtures/autoload/provider/clipboard.vim
@@ -3,18 +3,28 @@ let g:test_clip = { '+': [''], '*': [''], }
let s:methods = {}
let g:cliplossy = 0
+let g:cliperror = 0
function! s:methods.get(reg)
+ if g:cliperror
+ return 0
+ end
+ let reg = a:reg == '"' ? '+' : a:reg
if g:cliplossy
" behave like pure text clipboard
- return g:test_clip[a:reg][0]
+ return g:test_clip[reg][0]
else
- "behave like VIMENC clipboard
- return g:test_clip[a:reg]
+ " behave like VIMENC clipboard
+ return g:test_clip[reg]
end
endfunction
function! s:methods.set(lines, regtype, reg)
+ if a:reg == '"'
+ call s:methods.set(a:lines,a:regtype,'+')
+ call s:methods.set(a:lines,a:regtype,'*')
+ return 0
+ end
let g:test_clip[a:reg] = [a:lines, a:regtype]
endfunction
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 33d04616a0..1159707282 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -6,7 +6,6 @@ local AsyncSession = require('nvim.async_session')
local Session = require('nvim.session')
local nvim_prog = os.getenv('NVIM_PROG') or 'build/bin/nvim'
---- FIXME: 'autoindent' messes up the insert() function
local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N',
'--cmd', 'set shortmess+=I background=light noswapfile noautoindent',
'--embed'}
@@ -290,6 +289,28 @@ local function expect(contents)
return eq(dedent(contents), curbuf_contents())
end
+local function rmdir(path)
+ if lfs.attributes(path, 'mode') ~= 'directory' then
+ return nil
+ end
+ for file in lfs.dir(path) do
+ if file == '.' or file == '..' then
+ goto continue
+ end
+ ret, err = os.remove(path..'/'..file)
+ if not ret then
+ error('os.remove: '..err)
+ return nil
+ end
+ ::continue::
+ end
+ ret, err = os.remove(path)
+ if not ret then
+ error('os.remove: '..err)
+ end
+ return ret
+end
+
return {
clear = clear,
spawn = spawn,
@@ -321,5 +342,6 @@ return {
curbuf_contents = curbuf_contents,
wait = wait,
set_session = set_session,
- write_file = write_file
+ write_file = write_file,
+ rmdir = rmdir
}
diff --git a/test/functional/job/job_spec.lua b/test/functional/job/job_spec.lua
index b60f9ff7a4..7085d61cc7 100644
--- a/test/functional/job/job_spec.lua
+++ b/test/functional/job/job_spec.lua
@@ -304,7 +304,7 @@ describe('jobs', function()
source([[
call rpcnotify(g:channel, 'wait', jobwait([
\ jobstart([&sh, '-c', 'exit 4']),
- \ jobstart([&sh, '-c', 'sleep 10000; exit 5']),
+ \ jobstart([&sh, '-c', 'sleep 10; exit 5']),
\ ], 100))
]])
eq({'notification', 'wait', {{4, -1}}}, next_msg())
diff --git a/test/functional/legacy/057_sort_spec.lua b/test/functional/legacy/057_sort_spec.lua
new file mode 100644
index 0000000000..585b391198
--- /dev/null
+++ b/test/functional/legacy/057_sort_spec.lua
@@ -0,0 +1,603 @@
+-- Tests for :sort command.
+
+local helpers = require('test.functional.helpers')
+local insert, execute, clear, expect, eq, eval, source = helpers.insert,
+ helpers.execute, helpers.clear, helpers.expect, helpers.eq, helpers.eval,
+ helpers.source
+
+describe(':sort', function()
+ local text = [[
+ abc
+ ab
+ a
+ a321
+ a123
+ a122
+ b321
+ b123
+ c123d
+ 123b
+ c321d
+ b322b
+ b321
+ b321b
+ ]]
+ before_each(clear)
+
+ it('alphabetical', function()
+ insert(text)
+ execute('sort')
+ expect([[
+
+ 123b
+ a
+ a122
+ a123
+ a321
+ ab
+ abc
+ b123
+ b321
+ b321
+ b321b
+ b322b
+ c123d
+ c321d]])
+ end)
+
+ it('numerical', function()
+ insert([[
+ abc
+ ab
+ a321
+ a123
+ a122
+ a
+ x-22
+ b321
+ b123
+ c123d
+ -24
+ 123b
+ c321d
+ 0
+ b322b
+ b321
+ b321b
+ ]])
+ execute('sort n')
+ expect([[
+ abc
+ ab
+ a
+
+ -24
+ x-22
+ 0
+ a122
+ a123
+ b123
+ c123d
+ 123b
+ a321
+ b321
+ c321d
+ b321
+ b321b
+ b322b]])
+ end)
+
+ it('hexadecimal', function()
+ insert(text)
+ execute('sort x')
+ expect([[
+
+ a
+ ab
+ abc
+ 123b
+ a122
+ a123
+ a321
+ b123
+ b321
+ b321
+ b321b
+ b322b
+ c123d
+ c321d]])
+ end)
+
+ it('alphabetical, unique', function()
+ insert(text)
+ execute('sort u')
+ expect([[
+
+ 123b
+ a
+ a122
+ a123
+ a321
+ ab
+ abc
+ b123
+ b321
+ b321b
+ b322b
+ c123d
+ c321d]])
+ end)
+
+ it('alphabetical, reverse', function()
+ insert(text)
+ execute('sort!')
+ expect([[
+ c321d
+ c123d
+ b322b
+ b321b
+ b321
+ b321
+ b123
+ abc
+ ab
+ a321
+ a123
+ a122
+ a
+ 123b
+ ]])
+ end)
+
+ it('numerical, reverse', function()
+ insert(text)
+ execute('sort! n')
+ expect([[
+ b322b
+ b321b
+ b321
+ c321d
+ b321
+ a321
+ 123b
+ c123d
+ b123
+ a123
+ a122
+
+ a
+ ab
+ abc]])
+ end)
+
+ it('unique, reverse', function()
+ insert(text)
+ execute('sort! u')
+ expect([[
+ c321d
+ c123d
+ b322b
+ b321b
+ b321
+ b123
+ abc
+ ab
+ a321
+ a123
+ a122
+ a
+ 123b
+ ]])
+ end)
+
+ it('octal', function()
+ insert(text)
+ execute('sort o')
+ expect([[
+ abc
+ ab
+ a
+
+ a122
+ a123
+ b123
+ c123d
+ 123b
+ a321
+ b321
+ c321d
+ b321
+ b321b
+ b322b]])
+ end)
+
+ it('reverse, hexadecimal', function()
+ insert(text)
+ execute('sort! x')
+ expect([[
+ c321d
+ c123d
+ b322b
+ b321b
+ b321
+ b321
+ b123
+ a321
+ a123
+ a122
+ 123b
+ abc
+ ab
+ a
+ ]])
+ end)
+
+ it('alphabetical, skip first character', function()
+ insert(text)
+ execute('sort/./')
+ expect([[
+ a
+
+ a122
+ a123
+ b123
+ 123b
+ c123d
+ a321
+ b321
+ b321
+ b321b
+ c321d
+ b322b
+ ab
+ abc]])
+ end)
+
+ it('alphabetical, skip first 2 characters', function()
+ insert(text)
+ execute('sort/../')
+ expect([[
+ ab
+ a
+
+ a321
+ b321
+ b321
+ b321b
+ c321d
+ a122
+ b322b
+ a123
+ b123
+ 123b
+ c123d
+ abc]])
+ end)
+
+ it('alphabetical, unique, skip first 2 characters', function()
+ insert(text)
+ execute('sort/../u')
+ expect([[
+ ab
+ a
+
+ a321
+ b321
+ b321b
+ c321d
+ a122
+ b322b
+ a123
+ b123
+ 123b
+ c123d
+ abc]])
+ end)
+
+ it('numerical, skip first character', function()
+ insert(text)
+ execute('sort/./n')
+ expect([[
+ abc
+ ab
+ a
+
+ a122
+ a123
+ b123
+ c123d
+ 123b
+ a321
+ b321
+ c321d
+ b321
+ b321b
+ b322b]])
+ end)
+
+ it('alphabetical, sort on first character', function()
+ insert(text)
+ execute('sort/./r')
+ expect([[
+
+ 123b
+ abc
+ ab
+ a
+ a321
+ a123
+ a122
+ b321
+ b123
+ b322b
+ b321
+ b321b
+ c123d
+ c321d]])
+ end)
+
+ it('alphabetical, sort on first 2 characters', function()
+ insert(text)
+ execute('sort/../r')
+ expect([[
+ a
+
+ 123b
+ a123
+ a122
+ a321
+ abc
+ ab
+ b123
+ b321
+ b322b
+ b321
+ b321b
+ c123d
+ c321d]])
+ end)
+
+ it('numerical, sort on first character', function()
+ insert(text)
+ execute('sort/./rn')
+ expect([[
+ abc
+ ab
+ a
+ a321
+ a123
+ a122
+ b321
+ b123
+ c123d
+ 123b
+ c321d
+ b322b
+ b321
+ b321b
+ ]])
+ end)
+
+ it('alphabetical, skip past first digit', function()
+ insert(text)
+ execute([[sort/\d/]])
+ expect([[
+ abc
+ ab
+ a
+
+ a321
+ b321
+ b321
+ b321b
+ c321d
+ a122
+ b322b
+ a123
+ b123
+ 123b
+ c123d]])
+ end)
+
+ it('alphabetical, sort on first digit', function()
+ insert(text)
+ execute([[sort/\d/r]])
+ expect([[
+ abc
+ ab
+ a
+
+ a123
+ a122
+ b123
+ c123d
+ 123b
+ a321
+ b321
+ c321d
+ b322b
+ b321
+ b321b]])
+ end)
+
+ it('numerical, skip past first digit', function()
+ insert(text)
+ execute([[sort/\d/n]])
+ expect([[
+ abc
+ ab
+ a
+
+ a321
+ b321
+ c321d
+ b321
+ b321b
+ a122
+ b322b
+ a123
+ b123
+ c123d
+ 123b]])
+ end)
+
+ it('numerical, sort on first digit', function()
+ insert(text)
+ execute([[sort/\d/rn]])
+ expect([[
+ abc
+ ab
+ a
+
+ a123
+ a122
+ b123
+ c123d
+ 123b
+ a321
+ b321
+ c321d
+ b322b
+ b321
+ b321b]])
+ end)
+
+ it('alphabetical, skip past first 2 digits', function()
+ insert(text)
+ execute([[sort/\d\d/]])
+ expect([[
+ abc
+ ab
+ a
+
+ a321
+ b321
+ b321
+ b321b
+ c321d
+ a122
+ b322b
+ a123
+ b123
+ 123b
+ c123d]])
+ end)
+
+ it('numerical, skip past first 2 digits', function()
+ insert(text)
+ execute([[sort/\d\d/n]])
+ expect([[
+ abc
+ ab
+ a
+
+ a321
+ b321
+ c321d
+ b321
+ b321b
+ a122
+ b322b
+ a123
+ b123
+ c123d
+ 123b]])
+ end)
+
+ it('hexadecimal, skip past first 2 digits', function()
+ insert(text)
+ execute([[sort/\d\d/x]])
+ expect([[
+ abc
+ ab
+ a
+
+ a321
+ b321
+ b321
+ a122
+ a123
+ b123
+ b321b
+ c321d
+ b322b
+ 123b
+ c123d]])
+ end)
+
+ it('alpha, on first 2 digits', function()
+ insert(text)
+ execute([[sort/\d\d/r]])
+ expect([[
+ abc
+ ab
+ a
+
+ a123
+ a122
+ b123
+ c123d
+ 123b
+ a321
+ b321
+ c321d
+ b322b
+ b321
+ b321b]])
+ end)
+
+ it('numeric, on first 2 digits', function()
+ insert(text)
+ execute([[sort/\d\d/rn]])
+ expect([[
+ abc
+ ab
+ a
+
+ a123
+ a122
+ b123
+ c123d
+ 123b
+ a321
+ b321
+ c321d
+ b322b
+ b321
+ b321b]])
+ end)
+
+ it('hexadecimal, on first 2 digits', function()
+ insert(text)
+ execute([[sort/\d\d/rx]])
+ expect([[
+ abc
+ ab
+ a
+
+ a123
+ a122
+ b123
+ c123d
+ 123b
+ a321
+ b321
+ c321d
+ b322b
+ b321
+ b321b]])
+ end)
+
+ it('fails with wrong arguments', function()
+ insert(text)
+ -- This should fail with "E474: Invalid argument".
+ source([[
+ try
+ sort no
+ catch
+ let tmpvar = v:exception
+ endtry]])
+ eq('Vim(sort):E474: Invalid argument', eval('tmpvar'))
+ expect(text)
+ end)
+end)
diff --git a/test/functional/legacy/060_exists_and_has_functions_spec.lua b/test/functional/legacy/060_exists_and_has_functions_spec.lua
index c4d2b01522..e9b79b490d 100644
--- a/test/functional/legacy/060_exists_and_has_functions_spec.lua
+++ b/test/functional/legacy/060_exists_and_has_functions_spec.lua
@@ -1,18 +1,15 @@
--- Tests for the exists() and has() functions. ts=8 sw=2
+-- Tests for the exists() and has() functions.
local helpers = require('test.functional.helpers')
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
local write_file = helpers.write_file
-local os = require('os')
describe('exists() and has() functions', function()
- setup(clear)
-
- it('is working', function()
-
+ setup(function()
+ clear()
-- Create a temporary script needed for the test.
- write_file('test60.vim', [=[
+ write_file('test60.vim', [[
" Vim script for exists() function test
" Script-local variables are checked here
@@ -110,7 +107,14 @@ describe('exists() and has() functions', function()
echo "FAILED"
endif
unlet str
- ]=])
+ ]])
+ end)
+ teardown(function()
+ os.remove('test.out')
+ os.remove('test60.vim')
+ end)
+
+ it('is working', function()
source([=[
" Add the special directory with test scripts to &rtp
@@ -648,7 +652,7 @@ describe('exists() and has() functions', function()
]=])
-- Assert buffer contents.
- expect([=[
+ expect([[
#myagroup: 1
OK
@@ -859,11 +863,7 @@ describe('exists() and has() functions', function()
has patch 7.1.999: 1
has patch 7.4.123: 1
has patch 9.1.0: 0
- has patch 9.9.1: 0]=])
+ has patch 9.9.1: 0]])
end)
- teardown(function()
- os.remove('test.out')
- os.remove('test60.vim')
- end)
end)
diff --git a/test/functional/legacy/062_tab_pages_spec.lua b/test/functional/legacy/062_tab_pages_spec.lua
new file mode 100644
index 0000000000..6bbb06f9a7
--- /dev/null
+++ b/test/functional/legacy/062_tab_pages_spec.lua
@@ -0,0 +1,240 @@
+-- Tests for tab pages
+
+local helpers = require('test.functional.helpers')
+local feed, insert, source, clear, execute, expect, eval, eq =
+ helpers.feed, helpers.insert, helpers.source, helpers.clear,
+ helpers.execute, helpers.expect, helpers.eval, helpers.eq
+
+describe('tab pages', function()
+ before_each(clear)
+
+ it('can be opened and closed', function()
+ execute('tabnew')
+ eq(2, eval('tabpagenr()'))
+ execute('quit')
+ eq(1, eval('tabpagenr()'))
+ end)
+
+ it('can be iterated with :tabdo', function()
+ source([[
+ 0tabnew
+ 1tabnew
+ $tabnew
+ tabdo call append(line('$'), 'this is tab page ' . tabpagenr())
+ tabclose! 2
+ tabrewind
+ ]])
+ eq('this is tab page 1', eval("getline('$')"))
+ execute('tablast')
+ eq('this is tab page 4', eval("getline('$')"))
+ end)
+
+ it('have local variables accasible with settabvar()/gettabvar()', function()
+ -- Test for settabvar() and gettabvar() functions. Open a new tab page and
+ -- set 3 variables to a number, string and a list. Verify that the
+ -- variables are correctly set.
+ source([[
+ tabnew
+ tabfirst
+ call settabvar(2, 'val_num', 100)
+ call settabvar(2, 'val_str', 'SetTabVar test')
+ call settabvar(2, 'val_list', ['red', 'blue', 'green'])
+ ]])
+
+ eq(100, eval('gettabvar(2, "val_num")'))
+ eq('SetTabVar test', eval('gettabvar(2, "val_str")'))
+ eq({'red', 'blue', 'green'}, eval('gettabvar(2, "val_list")'))
+ execute('tabnext 2')
+ eq(100, eval('t:val_num'))
+ eq('SetTabVar test', eval('t:val_str'))
+ eq({'red', 'blue', 'green'}, eval('t:val_list'))
+ end)
+
+ it('work together with the drop feature and loaded buffers', function()
+ -- Test for ":tab drop exist-file" to keep current window.
+ execute('sp test1')
+ execute('tab drop test1')
+ eq(1, eval('tabpagenr("$")'))
+ eq(2, eval('winnr("$")'))
+ eq(1, eval('winnr()'))
+ end)
+
+ it('work together with the drop feature and new files', function()
+ -- Test for ":tab drop new-file" to keep current window of tabpage 1.
+ execute('split')
+ execute('tab drop newfile')
+ eq(2, eval('tabpagenr("$")'))
+ eq(2, eval('tabpagewinnr(1, "$")'))
+ eq(1, eval('tabpagewinnr(1)'))
+ end)
+
+ it('work together with the drop feature and multi loaded buffers', function()
+ -- Test for ":tab drop multi-opend-file" to keep current tabpage and
+ -- window.
+ execute('new test1')
+ execute('tabnew')
+ execute('new test1')
+ execute('tab drop test1')
+ eq(2, eval('tabpagenr()'))
+ eq(2, eval('tabpagewinnr(2, "$")'))
+ eq(1, eval('tabpagewinnr(2)'))
+ end)
+
+ it('can be navigated with :tabmove', function()
+ execute('lang C')
+ execute('for i in range(9) | tabnew | endfor')
+ feed('1gt')
+ eq(1, eval('tabpagenr()'))
+ execute('tabmove 5')
+ eq(6, eval('tabpagenr()'))
+ execute('tabmove -2')
+ eq(4, eval('tabpagenr()'))
+ execute('tabmove +4')
+ eq(8, eval('tabpagenr()'))
+ execute('tabmove')
+ eq(10, eval('tabpagenr()'))
+ execute('tabmove -20')
+ eq(1, eval('tabpagenr()'))
+ execute('tabmove +20')
+ eq(10, eval('tabpagenr()'))
+ execute('3tabmove')
+ eq(4, eval('tabpagenr()'))
+ execute('7tabmove 5')
+ eq(6, eval('tabpagenr()'))
+ execute('let a="No error caught."')
+ execute('try')
+ execute('tabmove foo')
+ execute('catch E474')
+ execute('let a="E474 caught."')
+ execute('endtry')
+ eq('E474 caught.', eval('a'))
+ end)
+
+ it('can trigger certain autocommands', function()
+ insert('Results:')
+
+ -- Test autocommands.
+ source([[
+ tabonly!
+ let g:r=[]
+ command -nargs=1 -bar C :call add(g:r, '=== '.<q-args>.' ===')|<args>
+ function Test()
+ autocmd TabEnter * :call add(g:r, 'TabEnter')
+ autocmd WinEnter * :call add(g:r, 'WinEnter')
+ autocmd BufEnter * :call add(g:r, 'BufEnter')
+ autocmd TabLeave * :call add(g:r, 'TabLeave')
+ autocmd WinLeave * :call add(g:r, 'WinLeave')
+ autocmd BufLeave * :call add(g:r, 'BufLeave')
+ let t:a='a'
+ C tab split
+ let t:a='b'
+ C tabnew
+ let t:a='c'
+ call add(g:r, join(map(range(1, tabpagenr('$')),
+ \ 'gettabvar(v:val, "a")')))
+ C call map(range(1, tabpagenr('$')),
+ \ 'settabvar(v:val, ''a'', v:val*2)')
+ call add(g:r, join(map(range(1, tabpagenr('$')),
+ \ 'gettabvar(v:val, "a")')))
+ let w:a='a'
+ C vsplit
+ let w:a='a'
+ let tabn=tabpagenr()
+ let winr=range(1, winnr('$'))
+ C tabnext 1
+ call add(g:r, join(map(copy(winr),
+ \ 'gettabwinvar('.tabn.', v:val, "a")')))
+ C call map(copy(winr),
+ \ 'settabwinvar('.tabn.', v:val, ''a'', v:val*2)')
+ call add(g:r, join(map(copy(winr),
+ \ 'gettabwinvar('.tabn.', v:val, "a")')))
+ augroup TabDestructive
+ autocmd TabEnter * :C tabnext 2 | C tabclose 3
+ augroup END
+ C tabnext 3
+ let g:r+=[tabpagenr().'/'.tabpagenr('$')]
+ autocmd! TabDestructive TabEnter
+ C tabnew
+ C tabnext 1
+ autocmd TabDestructive TabEnter * nested
+ \ :C tabnext 2 | C tabclose 3
+ C tabnext 3
+ let g:r+=[tabpagenr().'/'.tabpagenr('$')]
+ endfunction
+ call Test()
+ $ put =g:r
+ ]])
+
+ -- Assert buffer contents.
+ expect([[
+ Results:
+ === tab split ===
+ WinLeave
+ TabLeave
+ WinEnter
+ TabEnter
+ === tabnew ===
+ WinLeave
+ TabLeave
+ WinEnter
+ TabEnter
+ BufLeave
+ BufEnter
+ a b c
+ === call map(range(1, tabpagenr('$')), 'settabvar(v:val, ''a'', v:val*2)') ===
+ 2 4 6
+ === vsplit ===
+ WinLeave
+ WinEnter
+ === tabnext 1 ===
+ BufLeave
+ WinLeave
+ TabLeave
+ WinEnter
+ TabEnter
+ BufEnter
+ a a
+ === call map(copy(winr), 'settabwinvar('.tabn.', v:val, ''a'', v:val*2)') ===
+ 2 4
+ === tabnext 3 ===
+ BufLeave
+ WinLeave
+ TabLeave
+ WinEnter
+ TabEnter
+ === tabnext 2 ===
+ === tabclose 3 ===
+ 2/2
+ === tabnew ===
+ WinLeave
+ TabLeave
+ WinEnter
+ TabEnter
+ BufLeave
+ BufEnter
+ === tabnext 1 ===
+ BufLeave
+ WinLeave
+ TabLeave
+ WinEnter
+ TabEnter
+ BufEnter
+ === tabnext 3 ===
+ BufLeave
+ WinLeave
+ TabLeave
+ WinEnter
+ TabEnter
+ === tabnext 2 ===
+ BufLeave
+ WinLeave
+ TabLeave
+ WinEnter
+ TabEnter
+ === tabnext 2 ===
+ === tabclose 3 ===
+ BufEnter
+ === tabclose 3 ===
+ 2/2]])
+ end)
+end)
diff --git a/test/functional/legacy/077_mf_hash_grow_spec.lua b/test/functional/legacy/077_mf_hash_grow_spec.lua
index 01d916ef04..825f08e968 100644
--- a/test/functional/legacy/077_mf_hash_grow_spec.lua
+++ b/test/functional/legacy/077_mf_hash_grow_spec.lua
@@ -15,7 +15,7 @@ describe('mf_hash_grow()', function()
-- Check to see if cksum exists, otherwise skip the test
if os.execute('which cksum 2>&1 > /dev/null') ~= 0 then
- pending("was not tested because cksum was not found")
+ pending('was not tested because cksum was not found', function() end)
else
it('is working', function()
execute('set fileformat=unix undolevels=-1')
diff --git a/test/functional/legacy/080_substitute_spec.lua b/test/functional/legacy/080_substitute_spec.lua
new file mode 100644
index 0000000000..89ef7a713c
--- /dev/null
+++ b/test/functional/legacy/080_substitute_spec.lua
@@ -0,0 +1,162 @@
+-- Test for *sub-replace-special* and *sub-replace-expression* on substitue().
+-- Test for submatch() on substitue().
+-- Test for *:s%* on :substitute.
+
+local helpers = require('test.functional.helpers')
+local feed, insert, source = helpers.feed, helpers.insert, helpers.source
+local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
+local eq, eval = helpers.eq, helpers.eval
+
+describe('substitue()', function()
+ before_each(clear)
+
+ -- The original test contained several TEST_X lines to delimit different
+ -- parts. These where used to split the test into different it() blocks.
+ -- The TEST_X strings are repeated in the description of the blocks to make
+ -- it easier to incorporate upstream changes.
+
+ local function test_1_and_2()
+ eq('AA', eval("substitute('A', 'A', '&&', '')"))
+ eq('&', eval([[substitute('B', 'B', '\&', '')]]))
+ eq('C123456789987654321', eval([[substitute('C123456789', ]] ..
+ [['C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', ]] ..
+ [['\0\9\8\7\6\5\4\3\2\1', '')]]))
+ eq('d', eval("substitute('D', 'D', 'd', '')"))
+ eq('~', eval("substitute('E', 'E', '~', '')"))
+ eq('~', eval([[substitute('F', 'F', '\~', '')]]))
+ eq('Gg', eval([[substitute('G', 'G', '\ugg', '')]]))
+ eq('Hh', eval([[substitute('H', 'H', '\Uh\Eh', '')]]))
+ eq('iI', eval([[substitute('I', 'I', '\lII', '')]]))
+ eq('jJ', eval([[substitute('J', 'J', '\LJ\EJ', '')]]))
+ eq('Kk', eval([[substitute('K', 'K', '\Uk\ek', '')]]))
+ eq('l\rl', eval("substitute('lLl', 'L', '\r', '')"))
+ eq('m\rm', eval([[substitute('mMm', 'M', '\r', '')]]))
+ eq('n\rn', eval("substitute('nNn', 'N', '\\\r', '')"))
+ eq('o\no', eval([[substitute('oOo', 'O', '\n', '')]]))
+ eq('p\bp', eval([[substitute('pPp', 'P', '\b', '')]]))
+ eq('q\tq', eval([[substitute('qQq', 'Q', '\t', '')]]))
+ eq('r\\r', eval([[substitute('rRr', 'R', '\\', '')]]))
+ eq('scs', eval([[substitute('sSs', 'S', '\c', '')]]))
+ eq('t\rt', eval([[substitute('tTt', 'T', "\r", '')]]))
+ eq('u\nu', eval([[substitute('uUu', 'U', "\n", '')]]))
+ eq('v\bv', eval([[substitute('vVv', 'V', "\b", '')]]))
+ eq('w\\w', eval([[substitute('wWw', 'W', "\\", '')]]))
+ eq('XxxX', eval([[substitute('X', 'X', '\L\uxXx\l\EX', '')]]))
+ eq('yYYy', eval([[substitute('Y', 'Y', '\U\lYyY\u\Ey', '')]]))
+ end
+
+ it('with "set magic" (TEST_1)', function()
+ execute('set magic')
+ test_1_and_2()
+ end)
+
+ it('with "set nomagic" (TEST_2)', function()
+ execute('set nomagic')
+ test_1_and_2()
+ end)
+
+ it('with sub-replace-expression (TEST_3)', function()
+ execute('set magic&')
+ eq('a\\a', eval([[substitute('aAa', 'A', '\="\\"', '')]]))
+ eq('b\\\\b', eval([[substitute('bBb', 'B', '\="\\\\"', '')]]))
+ eq('c\rc', eval([[substitute('cCc', 'C', '\="]]..'\r'..[["', '')]]))
+ eq('d\\\rd', eval([[substitute('dDd', 'D', '\="\\]]..'\r'..[["', '')]]))
+ eq('e\\\\\re',
+ eval([[substitute('eEe', 'E', '\="\\\\]]..'\r'..[["', '')]]))
+ eq('f\\rf', eval([[substitute('fFf', 'F', '\="\\r"', '')]]))
+ eq('j\\nj', eval([[substitute('jJj', 'J', '\="\\n"', '')]]))
+ eq('k\rk', eval([[substitute('kKk', 'K', '\="\r"', '')]]))
+ eq('l\nl', eval([[substitute('lLl', 'L', '\="\n"', '')]]))
+ end)
+
+ it('with submatch() (TEST_4)', function()
+ execute('set magic&')
+ eq('a\\a', eval([[substitute('aAa', 'A', ]] ..
+ [['\=substitute(submatch(0), ".", "\\", "")', '')]]))
+ eq('b\\b', eval([[substitute('bBb', 'B', ]] ..
+ [['\=substitute(submatch(0), ".", "\\\\", "")', '')]]))
+ eq('c\rc', eval([[substitute('cCc', 'C', ]] ..
+ [['\=substitute(submatch(0), ".", "]]..'\r'..[[", "")', '')]]))
+ eq('d\rd', eval([[substitute('dDd', 'D', ]] ..
+ [['\=substitute(submatch(0), ".", "\\]]..'\r'..[[", "")', '')]]))
+ eq('e\\\re', eval([[substitute('eEe', 'E', ]] ..
+ [['\=substitute(submatch(0), ".", "\\\\]]..'\r'..[[", "")', '')]]))
+ eq('f\rf', eval([[substitute('fFf', 'F', ]] ..
+ [['\=substitute(submatch(0), ".", "\\r", "")', '')]]))
+ eq('j\nj', eval([[substitute('jJj', 'J', ]] ..
+ [['\=substitute(submatch(0), ".", "\\n", "")', '')]]))
+ eq('k\rk', eval([[substitute('kKk', 'K', ]] ..
+ [['\=substitute(submatch(0), ".", "\r", "")', '')]]))
+ eq('l\nl', eval([[substitute('lLl', 'L', ]] ..
+ [['\=substitute(submatch(0), ".", "\n", "")', '')]]))
+ end)
+
+ it('with submatch() (TEST_5)', function()
+ execute('set magic&')
+ eq('A123456789987654321', eval([[substitute('A123456789', ]] ..
+ [['A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', ]] ..
+ [['\=submatch(0) . submatch(9) . submatch(8) . submatch(7) . ]] ..
+ [[submatch(6) . submatch(5) . submatch(4) . submatch(3) . ]] ..
+ [[submatch(2) . submatch(1)', '')]]))
+ eq("[['A123456789'], ['9'], ['8'], ['7'], ['6'], ['5'], ['4'], ['3'], " ..
+ "['2'], ['1']]", eval([[substitute('A123456789', ]] ..
+ [['A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', ]] ..
+ [['\=string([submatch(0, 1), submatch(9, 1), submatch(8, 1), ]] ..
+ [[submatch(7, 1), submatch(6, 1), submatch(5, 1), submatch(4, 1), ]] ..
+ [[submatch(3, 1), submatch(2, 1), submatch(1, 1)])', '')]]))
+ end)
+
+ -- TEST_6 was about the 'cpoptions' flag / which was removed in pull request
+ -- #2943.
+
+ it('with submatch or \\ze (TEST_7)', function()
+ execute('set magic&')
+ eq('A\rA', eval("substitute('A\rA', 'A.', '\\=submatch(0)', '')"))
+ eq('B\nB', eval([[substitute("B\nB", 'B.', '\=submatch(0)', '')]]))
+ eq("['B\n']B",
+ eval([[substitute("B\nB", 'B.', '\=string(submatch(0, 1))', '')]]))
+ eq('-abab', eval([[substitute('-bb', '\zeb', 'a', 'g')]]))
+ eq('c-cbcbc', eval([[substitute('-bb', '\ze', 'c', 'g')]]))
+ end)
+
+ it('with \\zs and \\ze (TEST_10)', function()
+ execute('set magic&')
+ eq('a1a2a3a', eval([[substitute('123', '\zs', 'a', 'g')]]))
+ eq('aaa', eval([[substitute('123', '\zs.', 'a', 'g')]]))
+ eq('1a2a3a', eval([[substitute('123', '.\zs', 'a', 'g')]]))
+ eq('a1a2a3a', eval([[substitute('123', '\ze', 'a', 'g')]]))
+ eq('a1a2a3', eval([[substitute('123', '\ze.', 'a', 'g')]]))
+ eq('aaa', eval([[substitute('123', '.\ze', 'a', 'g')]]))
+ eq('aa2a3a', eval([[substitute('123', '1\|\ze', 'a', 'g')]]))
+ eq('1aaa', eval([[substitute('123', '1\zs\|[23]', 'a', 'g')]]))
+ end)
+end)
+
+describe(':substitue', function()
+ before_each(clear)
+
+ it('with \\ze and \\zs and confirmation dialog (TEST_8)', function()
+ insert([[
+ ,,X
+ ,,Y
+ ,,Z]])
+ execute('set magic&')
+ execute([[1s/\(^\|,\)\ze\(,\|X\)/\1N/g]])
+ execute([[2s/\(^\|,\)\ze\(,\|Y\)/\1N/gc]])
+ feed('a') -- For the dialog of the previous :s command.
+ execute([[3s/\(^\|,\)\ze\(,\|Z\)/\1N/gc]])
+ feed('yy') -- For the dialog of the previous :s command.
+ expect([[
+ N,,NX
+ N,,NY
+ N,,NZ]])
+ end)
+
+ it('with confirmation dialog (TEST_9)', function()
+ insert('xxx')
+ execute('set magic&')
+ execute('s/x/X/gc')
+ feed('yyq') -- For the dialog of the previous :s command.
+ expect('XXx')
+ end)
+end)
diff --git a/test/functional/legacy/mapping_spec.lua b/test/functional/legacy/mapping_spec.lua
index c387d7484c..0843506827 100644
--- a/test/functional/legacy/mapping_spec.lua
+++ b/test/functional/legacy/mapping_spec.lua
@@ -23,16 +23,27 @@ describe('mapping', function()
execute('set langmap=+{ langnoremap')
feed('o+<esc>')
- -- expr mapping with langmap.
+ -- Insert mode expr mapping with langmap.
execute('inoremap <expr> { "FAIL_iexplangmap"')
feed('o+<esc>')
+ -- langmap should not get remapped in cmdline mode.
+ execute('cnoremap { FAIL_clangmap')
+ feed('o+<esc>')
+ execute('cunmap {')
+
+ -- cmdline mode expr mapping with langmap.
+ execute('cnoremap <expr> { "FAIL_cexplangmap"')
+ feed('o+<esc>')
+ execute('cunmap {')
-- Assert buffer contents.
expect([[
test starts here:
vim
+
+ +
+ +
+]])
end)
end)
diff --git a/test/functional/runtime/autoload/remote/define_spec.lua b/test/functional/provider/define_spec.lua
index 9b97ed84d9..9b97ed84d9 100644
--- a/test/functional/runtime/autoload/remote/define_spec.lua
+++ b/test/functional/provider/define_spec.lua
diff --git a/test/functional/runtime/autoload/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua
index 43889b7b2a..5be5390370 100644
--- a/test/functional/runtime/autoload/provider/python3_spec.lua
+++ b/test/functional/provider/python3_spec.lua
@@ -1,19 +1,19 @@
do
- local proc =
- io.popen([[python3 -c 'import neovim, sys; sys.stdout.write("ok")' 2> /dev/null]])
+ local proc = io.popen(
+ [[python3 -c 'import neovim, sys; sys.stdout.write("ok")' 2> /dev/null]])
if proc:read() ~= 'ok' then
- -- Don't run these tests if python3 is not available
+ pending(
+ 'python3 (or the python3 neovim module) is broken or missing',
+ function() end)
return
end
end
-
local helpers = require('test.functional.helpers')
local eval, command, feed = helpers.eval, helpers.command, helpers.feed
local eq, clear, insert = helpers.eq, helpers.clear, helpers.insert
local expect, write_file = helpers.expect, helpers.write_file
-
describe('python3 commands and functions', function()
before_each(function()
clear()
diff --git a/test/functional/runtime/autoload/provider/python_spec.lua b/test/functional/provider/python_spec.lua
index e71a7a4309..ec1a853546 100644
--- a/test/functional/runtime/autoload/provider/python_spec.lua
+++ b/test/functional/provider/python_spec.lua
@@ -1,19 +1,19 @@
do
- local proc =
- io.popen([[python -c 'import neovim, sys; sys.stdout.write("ok")' 2> /dev/null]])
+ local proc = io.popen(
+ [[python -c 'import neovim, sys; sys.stdout.write("ok")' 2> /dev/null]])
if proc:read() ~= 'ok' then
- -- Don't run these tests if python is not available
+ pending(
+ 'python (or the python neovim module) is broken or missing',
+ function() end)
return
end
end
-
local helpers = require('test.functional.helpers')
local eval, command, feed = helpers.eval, helpers.command, helpers.feed
local eq, clear, insert = helpers.eq, helpers.clear, helpers.insert
local expect, write_file = helpers.expect, helpers.write_file
-
describe('python commands and functions', function()
before_each(function()
clear()
diff --git a/test/functional/shell/viml_system_spec.lua b/test/functional/shell/viml_system_spec.lua
index 6e10715612..4985c24aec 100644
--- a/test/functional/shell/viml_system_spec.lua
+++ b/test/functional/shell/viml_system_spec.lua
@@ -186,7 +186,7 @@ describe('system()', function()
describe("with a program that doesn't close stdout", function()
if not xclip then
- pending('skipped (missing xclip)')
+ pending('skipped (missing xclip)', function() end)
else
it('will exit properly after passing input', function()
eq('', eval([[system('xclip -i -selection clipboard', 'clip-data')]]))
@@ -365,7 +365,7 @@ describe('systemlist()', function()
describe("with a program that doesn't close stdout", function()
if not xclip then
- pending('skipped (missing xclip)')
+ pending('skipped (missing xclip)', function() end)
else
it('will exit properly after passing input', function()
eq({}, eval(
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index b72527e7b6..1a96cb4dba 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local thelpers = require('test.functional.terminal.helpers')
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
local nvim_dir, execute = helpers.nvim_dir, helpers.execute
+local eq, eval = helpers.eq, helpers.eval
describe('terminal window highlighting', function()
@@ -161,3 +162,27 @@ describe('terminal window highlighting with custom palette', function()
]])
end)
end)
+
+describe('synIDattr()', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 7)
+ execute('highlight Normal ctermfg=1 guifg=#ff0000')
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it('returns RGB number if GUI', function()
+ screen:attach(true)
+ eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg")'))
+ end)
+
+ it('returns color number if non-GUI', function()
+ screen:attach(false)
+ eq('1', eval('synIDattr(hlID("Normal"), "fg")'))
+ end)
+end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 9635f6119c..1d616ed853 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -259,6 +259,13 @@ This is probably due to an indeterminism in the test. Try adding
`wait()` (or even a separate `screen:expect(...)`) at a point of possible
indeterminism, typically in between a `feed()` or `execute()` which is non-
synchronous, and a synchronous api call.
+
+Note that sometimes a `wait` can trigger redraws and consequently generate more
+indeterminism. If adding `wait` calls seems to increase the frequency of these
+messages, try removing every `wait` call in the test.
+
+If everything else fails, use Screen:redraw_debug to help investigate what is
+ causing the problem.
]])
local tb = debug.traceback()
local index = string.find(tb, '\n%s*%[C]')
@@ -333,12 +340,9 @@ function Screen:_handle_mouse_off()
self._mouse_enabled = false
end
-function Screen:_handle_insert_mode()
- self._mode = 'insert'
-end
-
-function Screen:_handle_normal_mode()
- self._mode = 'normal'
+function Screen:_handle_mode_change(mode)
+ assert(mode == 'insert' or mode == 'replace' or mode == 'normal')
+ self._mode = mode
end
function Screen:_handle_set_scroll_region(top, bot, left, right)
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index d57c1773b1..421c167300 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -63,6 +63,29 @@ describe('Screen', function()
end
end)
end)
+
+ it('has correct default title with unnamed file', function()
+ local expected = '[No Name] - NVIM'
+ execute('set title')
+ screen:wait(function()
+ local actual = screen.title
+ if actual ~= expected then
+ return 'Expected title to be "'..expected..'" but was "'..actual..'"'
+ end
+ end)
+ end)
+
+ it('has correct default title with named file', function()
+ local expected = 'myfile (/mydir) - NVIM'
+ execute('set title')
+ execute('file /mydir/myfile')
+ screen:wait(function()
+ local actual = screen.title
+ if actual ~= expected then
+ return 'Expected title to be "'..expected..'" but was "'..actual..'"'
+ end
+ end)
+ end)
end)
describe(':set icon', function()
@@ -488,7 +511,6 @@ describe('Screen', function()
end)
it('has minimum width/height values', function()
- wait()
screen:try_resize(1, 1)
screen:expect([[
-- INS^ERT --|
diff --git a/test/unit/fixtures/queue.c b/test/unit/fixtures/queue.c
new file mode 100644
index 0000000000..bbb6274b21
--- /dev/null
+++ b/test/unit/fixtures/queue.c
@@ -0,0 +1,16 @@
+#include <string.h>
+#include <stdlib.h>
+#include "nvim/event/queue.h"
+#include "queue.h"
+
+
+void ut_queue_put(Queue *queue, const char *str)
+{
+ queue_put(queue, NULL, 1, str);
+}
+
+const char *ut_queue_get(Queue *queue)
+{
+ Event event = queue_get(queue);
+ return event.argv[0];
+}
diff --git a/test/unit/fixtures/queue.h b/test/unit/fixtures/queue.h
new file mode 100644
index 0000000000..ae949c9f29
--- /dev/null
+++ b/test/unit/fixtures/queue.h
@@ -0,0 +1,4 @@
+#include "nvim/event/queue.h"
+
+void ut_queue_put(Queue *queue, const char *str);
+const char *ut_queue_get(Queue *queue);
diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua
index 3d5c6bc885..9cca3ca244 100644
--- a/test/unit/os/fs_spec.lua
+++ b/test/unit/os/fs_spec.lua
@@ -19,7 +19,7 @@ require('bit')
cimport('unistd.h')
cimport('./src/nvim/os/shell.h')
cimport('./src/nvim/option_defs.h')
-cimport('./src/nvim/os/event.h')
+cimport('./src/nvim/main.h')
cimport('./src/nvim/fileio.h')
local fs = cimport('./src/nvim/os/os.h')
cppimport('sys/stat.h')
@@ -32,6 +32,14 @@ local directory = nil
local absolute_executable = nil
local executable_name = nil
+local function set_bit(number, to_set)
+ return bit.bor(number, to_set)
+end
+
+local function unset_bit(number, to_unset)
+ return bit.band(number, (bit.bnot(to_unset)))
+end
+
local function assert_file_exists(filepath)
neq(nil, lfs.attributes(filepath))
end
@@ -40,11 +48,24 @@ local function assert_file_does_not_exist(filepath)
eq(nil, lfs.attributes(filepath))
end
+local function os_setperm(filename, perm)
+ return fs.os_setperm((to_cstr(filename)), perm)
+end
+
+local function os_getperm(filename)
+ local perm = fs.os_getperm((to_cstr(filename)))
+ return tonumber(perm)
+end
+
describe('fs function', function()
+ local orig_test_file_perm
setup(function()
lfs.mkdir('unit-test-directory');
+
io.open('unit-test-directory/test.file', 'w').close()
+ orig_test_file_perm = os_getperm('unit-test-directory/test.file')
+
io.open('unit-test-directory/test_2.file', 'w').close()
lfs.link('test.file', 'unit-test-directory/test_link.file', true)
-- Since the tests are executed, they are called by an executable. We use
@@ -188,6 +209,10 @@ describe('fs function', function()
end)
describe('file permissions', function()
+ before_each(function()
+ os_setperm('unit-test-directory/test.file', orig_test_file_perm)
+ end)
+
local function os_getperm(filename)
local perm = fs.os_getperm((to_cstr(filename)))
return tonumber(perm)
@@ -208,6 +233,10 @@ describe('fs function', function()
return fs.os_file_is_readonly((to_cstr(filename)))
end
+ local function os_file_is_readable(filename)
+ return fs.os_file_is_readable((to_cstr(filename)))
+ end
+
local function os_file_is_writable(filename)
return fs.os_file_is_writable((to_cstr(filename)))
end
@@ -216,14 +245,6 @@ describe('fs function', function()
return 0 ~= (bit.band(number, check_bit))
end
- local function set_bit(number, to_set)
- return bit.bor(number, to_set)
- end
-
- local function unset_bit(number, to_unset)
- return bit.band(number, (bit.bnot(to_unset)))
- end
-
describe('os_getperm', function()
it('returns -1 when the given file does not exist', function()
eq(-1, (os_getperm('non-existing-file')))
@@ -270,7 +291,7 @@ describe('fs function', function()
-- Some systems may not have `id` utility.
if (os.execute('id -G > /dev/null 2>&1') ~= 0) then
- pending('skipped (missing `id` utility)')
+ pending('skipped (missing `id` utility)', function() end)
else
it('owner of a file may change the group of the file to any group of which that owner is a member', function()
local file_gid = lfs.attributes(filename, 'gid')
@@ -296,7 +317,7 @@ describe('fs function', function()
-- On Windows `os_fchown` always returns 0
-- because `uv_fs_chown` is no-op on this platform.
if (ffi.os == 'Windows' or ffi.C.geteuid() == 0) then
- pending('skipped (os_fchown is no-op on Windows)')
+ pending('skipped (os_fchown is no-op on Windows)', function() end)
else
it('returns nonzero if process has not enough permissions', function()
-- chown to root
@@ -322,16 +343,35 @@ describe('fs function', function()
end)
end)
+ describe('os_file_is_readable', function()
+ it('returns false if the file is not readable', function()
+ local perm = os_getperm('unit-test-directory/test.file')
+ perm = unset_bit(perm, ffi.C.kS_IRUSR)
+ perm = unset_bit(perm, ffi.C.kS_IRGRP)
+ perm = unset_bit(perm, ffi.C.kS_IROTH)
+ eq(OK, (os_setperm('unit-test-directory/test.file', perm)))
+ eq(false, os_file_is_readable('unit-test-directory/test.file'))
+ end)
+
+ it('returns false if the file does not exist', function()
+ eq(false, os_file_is_readable(
+ 'unit-test-directory/what_are_you_smoking.gif'))
+ end)
+
+ it('returns true if the file is readable', function()
+ eq(true, os_file_is_readable(
+ 'unit-test-directory/test.file'))
+ end)
+ end)
+
describe('os_file_is_writable', function()
it('returns 0 if the file is readonly', function()
local perm = os_getperm('unit-test-directory/test.file')
- local perm_orig = perm
perm = unset_bit(perm, ffi.C.kS_IWUSR)
perm = unset_bit(perm, ffi.C.kS_IWGRP)
perm = unset_bit(perm, ffi.C.kS_IWOTH)
eq(OK, (os_setperm('unit-test-directory/test.file', perm)))
eq(0, os_file_is_writable('unit-test-directory/test.file'))
- eq(OK, (os_setperm('unit-test-directory/test.file', perm_orig)))
end)
it('returns 1 if the file is writable', function()
@@ -486,6 +526,16 @@ describe('fs function', function()
return fs.os_rmdir(to_cstr(path))
end
+ local function os_mkdir_recurse(path, mode)
+ local failed_str = ffi.new('char *[1]', {nil})
+ local ret = fs.os_mkdir_recurse(path, mode, failed_str)
+ local str = failed_str[0]
+ if str ~= nil then
+ str = ffi.string(str)
+ end
+ return ret, str
+ end
+
describe('os_mkdir', function()
it('returns non-zero when given an already existing directory', function()
local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
@@ -501,6 +551,59 @@ describe('fs function', function()
end)
end)
+ describe('os_mkdir_recurse', function()
+ it('returns zero when given an already existing directory', function()
+ local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
+ local ret, failed_str = os_mkdir_recurse('unit-test-directory', mode)
+ eq(0, ret)
+ eq(nil, failed_str)
+ end)
+
+ it('fails to create a directory where there is a file', function()
+ local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
+ local ret, failed_str = os_mkdir_recurse(
+ 'unit-test-directory/test.file', mode)
+ neq(0, ret)
+ eq('unit-test-directory/test.file', failed_str)
+ end)
+
+ it('fails to create a directory where there is a file in path', function()
+ local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
+ local ret, failed_str = os_mkdir_recurse(
+ 'unit-test-directory/test.file/test', mode)
+ neq(0, ret)
+ eq('unit-test-directory/test.file', failed_str)
+ end)
+
+ it('succeeds to create a directory', function()
+ local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
+ local ret, failed_str = os_mkdir_recurse(
+ 'unit-test-directory/new-dir-recurse', mode)
+ eq(0, ret)
+ eq(nil, failed_str)
+ eq(true, os_isdir('unit-test-directory/new-dir-recurse'))
+ lfs.rmdir('unit-test-directory/new-dir-recurse')
+ eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
+ end)
+
+ it('succeeds to create a directory tree', function()
+ local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR
+ local ret, failed_str = os_mkdir_recurse(
+ 'unit-test-directory/new-dir-recurse/1/2/3', mode)
+ eq(0, ret)
+ eq(nil, failed_str)
+ eq(true, os_isdir('unit-test-directory/new-dir-recurse'))
+ eq(true, os_isdir('unit-test-directory/new-dir-recurse/1'))
+ eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2'))
+ eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2/3'))
+ lfs.rmdir('unit-test-directory/new-dir-recurse/1/2/3')
+ lfs.rmdir('unit-test-directory/new-dir-recurse/1/2')
+ lfs.rmdir('unit-test-directory/new-dir-recurse/1')
+ lfs.rmdir('unit-test-directory/new-dir-recurse')
+ eq(false, os_isdir('unit-test-directory/new-dir-recurse'))
+ end)
+ end)
+
describe('os_rmdir', function()
it('returns non_zero when given a non-existing directory', function()
neq(0, (os_rmdir('non-existing-directory')))
diff --git a/test/unit/os/shell_spec.lua b/test/unit/os/shell_spec.lua
index 91d807da0b..91123bfd58 100644
--- a/test/unit/os/shell_spec.lua
+++ b/test/unit/os/shell_spec.lua
@@ -14,7 +14,7 @@ local helpers = require('test.unit.helpers')
local shell = helpers.cimport(
'./src/nvim/os/shell.h',
'./src/nvim/option_defs.h',
- './src/nvim/os/event.h',
+ './src/nvim/main.h',
'./src/nvim/misc1.h'
)
local ffi, eq, neq = helpers.ffi, helpers.eq, helpers.neq
diff --git a/test/unit/queue_spec.lua b/test/unit/queue_spec.lua
new file mode 100644
index 0000000000..9326c1cad6
--- /dev/null
+++ b/test/unit/queue_spec.lua
@@ -0,0 +1,123 @@
+local helpers = require("test.unit.helpers")
+
+local ffi = helpers.ffi
+local eq = helpers.eq
+
+local queue = helpers.cimport("./test/unit/fixtures/queue.h")
+
+describe('queue', function()
+ local parent, child1, child2, child3
+
+ local function put(q, str)
+ queue.ut_queue_put(q, str)
+ end
+
+ local function get(q)
+ return ffi.string(queue.ut_queue_get(q))
+ end
+
+ local function free(q)
+ queue.queue_free(q)
+ end
+
+ before_each(function()
+ parent = queue.queue_new_parent(ffi.NULL, ffi.NULL)
+ child1 = queue.queue_new_child(parent)
+ child2 = queue.queue_new_child(parent)
+ child3 = queue.queue_new_child(parent)
+ put(child1, 'c1i1')
+ put(child1, 'c1i2')
+ put(child2, 'c2i1')
+ put(child1, 'c1i3')
+ put(child2, 'c2i2')
+ put(child2, 'c2i3')
+ put(child2, 'c2i4')
+ put(child3, 'c3i1')
+ put(child3, 'c3i2')
+ end)
+
+ it('removing from parent removes from child', function()
+ eq('c1i1', get(parent))
+ eq('c1i2', get(parent))
+ eq('c2i1', get(parent))
+ eq('c1i3', get(parent))
+ eq('c2i2', get(parent))
+ eq('c2i3', get(parent))
+ eq('c2i4', get(parent))
+ end)
+
+ it('removing from child removes from parent', function()
+ eq('c2i1', get(child2))
+ eq('c2i2', get(child2))
+ eq('c1i1', get(child1))
+ eq('c1i2', get(parent))
+ eq('c1i3', get(parent))
+ eq('c2i3', get(parent))
+ eq('c2i4', get(parent))
+ end)
+
+ it('removing from child at the beginning of parent', function()
+ eq('c1i1', get(child1))
+ eq('c1i2', get(child1))
+ eq('c2i1', get(parent))
+ end)
+
+ it('removing from parent after get from parent and put to child', function()
+ eq('c1i1', get(parent))
+ eq('c1i2', get(parent))
+ eq('c2i1', get(parent))
+ eq('c1i3', get(parent))
+ eq('c2i2', get(parent))
+ eq('c2i3', get(parent))
+ eq('c2i4', get(parent))
+ eq('c3i1', get(parent))
+ put(child1, 'c1i11')
+ put(child1, 'c1i22')
+ eq('c3i2', get(parent))
+ eq('c1i11', get(parent))
+ eq('c1i22', get(parent))
+ end)
+
+ it('removing from parent after get and put to child', function()
+ eq('c1i1', get(child1))
+ eq('c1i2', get(child1))
+ eq('c2i1', get(child2))
+ eq('c1i3', get(child1))
+ eq('c2i2', get(child2))
+ eq('c2i3', get(child2))
+ eq('c2i4', get(child2))
+ eq('c3i1', get(child3))
+ eq('c3i2', get(parent))
+ put(child1, 'c1i11')
+ put(child2, 'c2i11')
+ put(child1, 'c1i12')
+ eq('c2i11', get(child2))
+ eq('c1i11', get(parent))
+ eq('c1i12', get(parent))
+ end)
+
+ it('put after removing from child at the end of parent', function()
+ eq('c3i1', get(child3))
+ eq('c3i2', get(child3))
+ put(child1, 'c1i11')
+ put(child2, 'c2i11')
+ eq('c1i1', get(parent))
+ eq('c1i2', get(parent))
+ eq('c2i1', get(parent))
+ eq('c1i3', get(parent))
+ eq('c2i2', get(parent))
+ eq('c2i3', get(parent))
+ eq('c2i4', get(parent))
+ eq('c1i11', get(parent))
+ eq('c2i11', get(parent))
+ end)
+
+ it('removes from parent queue when child is freed', function()
+ free(child2)
+ eq('c1i1', get(parent))
+ eq('c1i2', get(parent))
+ eq('c1i3', get(parent))
+ eq('c3i1', get(child3))
+ eq('c3i2', get(child3))
+ end)
+end)
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 50f610008d..ff4a11b417 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -6,10 +6,10 @@ project(NEOVIM_DEPS)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
set(DEPS_INSTALL_DIR "${CMAKE_BINARY_DIR}/usr" CACHE PATH "Dependencies install directory.")
-set(DEPS_BIN_DIR "${DEPS_INSTALL_DIR}/bin")
-set(DEPS_LIB_DIR "${DEPS_INSTALL_DIR}/lib")
-set(DEPS_BUILD_DIR "${CMAKE_BINARY_DIR}/build")
-set(DEPS_DOWNLOAD_DIR "${DEPS_BUILD_DIR}/downloads")
+set(DEPS_BIN_DIR "${DEPS_INSTALL_DIR}/bin" CACHE PATH "Dependencies binary install directory.")
+set(DEPS_LIB_DIR "${DEPS_INSTALL_DIR}/lib" CACHE PATH "Dependencies library install directory.")
+set(DEPS_BUILD_DIR "${CMAKE_BINARY_DIR}/build" CACHE PATH "Dependencies build directory.")
+set(DEPS_DOWNLOAD_DIR "${DEPS_BUILD_DIR}/downloads" CACHE PATH "Dependencies download directory.")
option(USE_BUNDLED "Use bundled dependencies." ON)
diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake
index ff1f57442d..14454fa5a0 100644
--- a/third-party/cmake/BuildLuarocks.cmake
+++ b/third-party/cmake/BuildLuarocks.cmake
@@ -113,40 +113,10 @@ add_custom_target(lpeg
list(APPEND THIRD_PARTY_DEPS lpeg)
if(USE_BUNDLED_BUSTED)
- # The following are only required if we want to run tests
- # with busted
- add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/stable-busted-deps
- COMMAND ${LUAROCKS_BINARY}
- ARGS build lua_cliargs 2.5-1 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build luafilesystem 1.6.3-1 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build dkjson 2.5-2 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build say 1.3-0 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build luassert 1.7.6-0 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build lua-term 0.3-1 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build penlight 1.3.2-2 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build mediator_lua 1.1.1-0 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build luasocket 3.0rc1-2 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build xml 1.1.2-1 ${LUAROCKS_BUILDARGS}
- COMMAND ${LUAROCKS_BINARY}
- ARGS build ansicolors 1.0.2-3 ${LUAROCKS_BUILDARGS}
- COMMAND ${CMAKE_COMMAND} -E touch ${HOSTDEPS_LIB_DIR}/luarocks/rocks/stable-busted-deps
- DEPENDS lpeg)
- add_custom_target(stable-busted-deps
- DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/stable-busted-deps)
-
add_custom_command(OUTPUT ${HOSTDEPS_BIN_DIR}/busted
COMMAND ${LUAROCKS_BINARY}
- ARGS build https://raw.githubusercontent.com/Olivine-Labs/busted/v2.0.rc8-0/busted-2.0.rc8-0.rockspec ${LUAROCKS_BUILDARGS}
- DEPENDS stable-busted-deps)
+ ARGS build https://raw.githubusercontent.com/Olivine-Labs/busted/v2.0.rc10-0/busted-2.0.rc10-0.rockspec ${LUAROCKS_BUILDARGS}
+ DEPENDS luarocks)
add_custom_target(busted
DEPENDS ${HOSTDEPS_BIN_DIR}/busted)
@@ -157,5 +127,5 @@ if(USE_BUNDLED_BUSTED)
add_custom_target(nvim-client
DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/nvim-client)
- list(APPEND THIRD_PARTY_DEPS stable-busted-deps busted nvim-client)
+ list(APPEND THIRD_PARTY_DEPS busted nvim-client)
endif()