Merge branch 'master' into colored-cmdline

This commit is contained in:
ZyX 2017-07-15 18:56:45 +03:00
commit 69719e658c
112 changed files with 7029 additions and 3745 deletions

View File

@ -51,14 +51,14 @@ endif()
# Set default build type.
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "CMAKE_BUILD_TYPE not given, defaulting to 'Dev'.")
set(CMAKE_BUILD_TYPE "Dev" CACHE STRING "Choose the type of build." FORCE)
message(STATUS "CMAKE_BUILD_TYPE not given, defaulting to 'Debug'.")
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE)
endif()
# Set available build types for CMake GUIs.
# A different build type can still be set by -DCMAKE_BUILD_TYPE=...
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
STRINGS "Debug" "Dev" "Release" "MinSizeRel" "RelWithDebInfo")
STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
# If not in a git repo (e.g., a tarball) these tokens define the complete
# version string, else they are combined with the result of `git describe`.
@ -107,46 +107,24 @@ if(NOT CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DMIN_LOG_LEVEL)
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DMIN_LOG_LEVEL=3")
endif()
# Enable assertions for RelWithDebInfo.
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG)
if(CMAKE_COMPILER_IS_GNUCC)
check_c_compiler_flag(-Og HAS_OG_FLAG)
else()
set(HAS_OG_FLAG 0)
endif()
# Set custom build flags for RelWithDebInfo.
# -DNDEBUG purposely omitted because we want assertions.
if(HAS_OG_FLAG)
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Og -g"
CACHE STRING "Flags used by the compiler during release-with-debug builds." FORCE)
elseif(NOT MSVC)
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g"
CACHE STRING "Flags used by the compiler during release-with-debug builds." FORCE)
elseif(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG)
string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
endif()
# Set build flags for custom Dev build type.
# -DNDEBUG purposely omitted because we want assertions.
if(MSVC)
SET(CMAKE_C_FLAGS_DEV ""
CACHE STRING "Flags used by the compiler during development (optimized, but with debug info and logging) builds."
FORCE)
else()
if(CMAKE_COMPILER_IS_GNUCC)
check_c_compiler_flag(-Og HAS_OG_FLAG)
else()
set(HAS_OG_FLAG 0)
endif()
if(HAS_OG_FLAG)
set(CMAKE_C_FLAGS_DEV "-Og -g"
CACHE STRING "Flags used by the compiler during development (optimized, but with debug info and logging) builds."
FORCE)
else()
set(CMAKE_C_FLAGS_DEV "-O2 -g"
CACHE STRING "Flags used by the compiler during development (optimized, but with debug info and logging) builds."
FORCE)
endif()
endif()
SET(CMAKE_EXE_LINKER_FLAGS_DEV ""
CACHE STRING "Flags used for linking binaries during development (optimized, but with debug info and logging) builds."
FORCE)
SET(CMAKE_SHARED_LINKER_FLAGS_DEV ""
CACHE STRING "Flags used by the shared libraries linker during development (optimized, but with debug info and logging) builds."
FORCE)
MARK_AS_ADVANCED(
CMAKE_C_FLAGS_DEV
CMAKE_EXE_LINKER_FLAGS_DEV
CMAKE_SHARED_LINKER_FLAGS_DEV)
# Enable -Wconversion.
if(NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion")
@ -600,9 +578,26 @@ if(LUACHECK_PRG)
add_custom_target(testlint
COMMAND ${CMAKE_COMMAND}
-DLUACHECK_PRG=${LUACHECK_PRG}
-DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
-DLUAFILES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
-DIGNORE_PATTERN="*/preload.lua"
-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
-P ${PROJECT_SOURCE_DIR}/cmake/RunTestsLint.cmake)
-P ${PROJECT_SOURCE_DIR}/cmake/RunLuacheck.cmake)
add_custom_target(
blobcodelint
COMMAND
${CMAKE_COMMAND}
-DLUACHECK_PRG=${LUACHECK_PRG}
-DLUAFILES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/src/nvim/lua
-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
-DREAD_GLOBALS=vim
-P ${PROJECT_SOURCE_DIR}/cmake/RunLuacheck.cmake
)
# TODO(ZyX-I): Run linter for all lua code in src
add_custom_target(
lualint
DEPENDS blobcodelint
)
endif()
set(CPACK_PACKAGE_NAME "Neovim")

View File

@ -1,16 +1,19 @@
<!-- Before reporting: search existing issues and check the FAQ. -->
- `nvim --version`:
- Vim (version: ) behaves differently?
- Operating system/version:
- Terminal name/version:
- `$TERM`:
### Actual behaviour
### Expected behaviour
### Steps to reproduce using `nvim -u NORC`
```
nvim -u NORC
```
### Actual behaviour
### Expected behaviour

View File

@ -107,6 +107,9 @@ functionaltest-lua: | nvim
testlint: | build/.ran-cmake deps
$(BUILD_CMD) -C build testlint
lualint: | build/.ran-cmake deps
$(BUILD_CMD) -C build lualint
unittest: | nvim
+$(BUILD_CMD) -C build unittest
@ -138,6 +141,6 @@ check-single-includes: build/.ran-cmake
appimage:
bash scripts/genappimage.sh
lint: check-single-includes clint testlint
lint: check-single-includes clint testlint lualint
.PHONY: test testlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage
.PHONY: test testlint lualint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage

View File

@ -20,6 +20,12 @@ run_test 'top_make testlint' testlint
exit_suite --continue
enter_suite 'lualint'
run_test 'top_make lualint' lualint
exit_suite --continue
enter_suite single-includes
CLICOLOR_FORCE=1 run_test_wd \

View File

@ -27,6 +27,9 @@ find_path(JEMALLOC_INCLUDE_DIR jemalloc/jemalloc.h
if(JEMALLOC_USE_STATIC)
list(APPEND JEMALLOC_NAMES
"${CMAKE_STATIC_LIBRARY_PREFIX}jemalloc${CMAKE_STATIC_LIBRARY_SUFFIX}")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
list(INSERT JEMALLOC_NAMES 0
"${CMAKE_STATIC_LIBRARY_PREFIX}jemalloc${CMAKE_STATIC_LIBRARY_SUFFIX}")
endif()
list(APPEND JEMALLOC_NAMES jemalloc)

22
cmake/RunLuacheck.cmake Normal file
View File

@ -0,0 +1,22 @@
set(LUACHECK_ARGS -q "${LUAFILES_DIR}")
if(DEFINED IGNORE_PATTERN)
list(APPEND LUACHECK_ARGS --exclude-files "${LUAFILES_DIR}/${IGNORE_PATTERN}")
endif()
if(DEFINED CHECK_PATTERN)
list(APPEND LUACHECK_ARGS --include-files "${LUAFILES_DIR}/${CHECK_PATTERN}")
endif()
if(DEFINED READ_GLOBALS)
list(APPEND LUACHECK_ARGS --read-globals "${READ_GLOBALS}")
endif()
execute_process(
COMMAND "${LUACHECK_PRG}" ${LUACHECK_ARGS}
WORKING_DIRECTORY "${LUAFILES_DIR}"
ERROR_VARIABLE err
RESULT_VARIABLE res
)
if(NOT res EQUAL 0)
message(STATUS "Output to stderr:\n${err}")
message(FATAL_ERROR "Linting tests failed with error: ${res}.")
endif()

View File

@ -1,13 +0,0 @@
set(IGNORE_FILES "${TEST_DIR}/*/preload.lua")
execute_process(
COMMAND ${LUACHECK_PRG} -q ${TEST_DIR} --exclude-files ${IGNORE_FILES}
WORKING_DIRECTORY ${TEST_DIR}
ERROR_VARIABLE err
RESULT_VARIABLE res
${EXTRA_ARGS})
if(NOT res EQUAL 0)
message(STATUS "Output to stderr:\n${err}")
message(FATAL_ERROR "Linting tests failed with error: ${res}.")
endif()

View File

@ -13,26 +13,21 @@
# Sets the build type; defaults to Debug. Valid values:
#
# - Debug: Disables optimizations (-O0), enables debug information and logging.
# - Debug: Disables optimizations (-O0), enables debug information.
#
# - Dev: Enables all optimizations that do not interfere with
# debugging (-Og if available, -O2 and -g if not).
# Enables debug information and logging.
#
# - RelWithDebInfo: Enables optimizations (-O2) and debug information.
# Disables logging.
# - RelWithDebInfo: Enables optimizations (-Og or -O2) with debug information.
#
# - MinSizeRel: Enables all -O2 optimization that do not typically
# increase code size, and performs further optimizations
# designed to reduce code size (-Os).
# Disables debug information and logging.
# Disables debug information.
#
# - Release: Same as RelWithDebInfo, but disables debug information.
#
# CMAKE_BUILD_TYPE := Debug
# The default log level is 1 (INFO) (unless CMAKE_BUILD_TYPE is "Release").
# Log levels: 0 (DEBUG), 1 (INFO), 2 (WARNING), 3 (ERROR)
# Default is 1 (INFO) unless CMAKE_BUILD_TYPE is Release or RelWithDebInfo.
# CMAKE_EXTRA_FLAGS += -DMIN_LOG_LEVEL=1
# By default, nvim uses bundled versions of its required third-party

View File

@ -33,7 +33,8 @@ function! health#check(plugin_names) abort
setlocal wrap breakindent
setlocal filetype=markdown
setlocal conceallevel=2 concealcursor=nc
setlocal keywordprg=:help iskeyword=@,48-57,_,192-255,-,#
setlocal keywordprg=:help
let &l:iskeyword='!-~,^*,^|,^",192-255'
call s:enhance_syntax()
if empty(healthchecks)

View File

@ -125,6 +125,10 @@ function! s:check_clipboard() abort
call health#report_warn(
\ 'No clipboard tool found. Clipboard registers will not work.',
\ [':help clipboard'])
elseif exists('g:clipboard') && (type({}) != type(g:clipboard)
\ || !has_key(g:clipboard, 'copy') || !has_key(g:clipboard, 'paste'))
call health#report_error(
\ 'g:clipboard exists but is malformed. It must be a dictionary with the keys documented at :help g:clipboard')
else
call health#report_ok('Clipboard tool found: '. clipboard_tool)
endif

View File

@ -8,7 +8,7 @@ let s:paste = {}
" ownership of the selection, so we know how long the cache is valid.
let s:selection = { 'owner': 0, 'data': [] }
function! s:selection.on_exit(jobid, data, event)
function! s:selection.on_exit(jobid, data, event) abort
" At this point this nvim instance might already have launched
" a new provider instance. Don't drop ownership in this case.
if self.owner == a:jobid
@ -18,7 +18,7 @@ endfunction
let s:selections = { '*': s:selection, '+': copy(s:selection)}
function! s:try_cmd(cmd, ...)
function! s:try_cmd(cmd, ...) abort
let argv = split(a:cmd, " ")
let out = a:0 ? systemlist(argv, a:1, 1) : systemlist(argv, [''], 1)
if v:shell_error
@ -34,7 +34,7 @@ function! s:try_cmd(cmd, ...)
endfunction
" Returns TRUE if `cmd` exits with success, else FALSE.
function! s:cmd_ok(cmd)
function! s:cmd_ok(cmd) abort
call system(a:cmd)
return v:shell_error == 0
endfunction
@ -47,7 +47,12 @@ function! provider#clipboard#Error() abort
endfunction
function! provider#clipboard#Executable() abort
if has('mac') && executable('pbcopy')
if exists('g:clipboard')
let s:copy = get(g:clipboard, 'copy', { '+': v:null, '*': v:null })
let s:paste = get(g:clipboard, 'paste', { '+': v:null, '*': v:null })
let s:cache_enabled = get(g:clipboard, 'cache_enabled', 1)
return get(g:clipboard, 'name', 'g:clipboard')
elseif has('mac') && executable('pbcopy')
let s:copy['+'] = 'pbcopy'
let s:paste['+'] = 'pbpaste'
let s:copy['*'] = s:copy['+']
@ -102,14 +107,14 @@ endif
let s:clipboard = {}
function! s:clipboard.get(reg)
function! s:clipboard.get(reg) abort
if s:selections[a:reg].owner > 0
return s:selections[a:reg].data
end
return s:try_cmd(s:paste[a:reg])
endfunction
function! s:clipboard.set(lines, regtype, reg)
function! s:clipboard.set(lines, regtype, reg) abort
if a:reg == '"'
call s:clipboard.set(a:lines,a:regtype,'+')
if s:copy['*'] != s:copy['+']
@ -144,6 +149,6 @@ function! s:clipboard.set(lines, regtype, reg)
let selection.owner = jobid
endfunction
function! provider#clipboard#Call(method, args)
function! provider#clipboard#Call(method, args) abort
return call(s:clipboard[a:method],a:args,s:clipboard)
endfunction

View File

@ -165,7 +165,16 @@ nvim_input({keys}) *nvim_input()*
*nvim_replace_termcodes()*
nvim_replace_termcodes({str}, {from_part}, {do_lt}, {special})
Replaces any terminal codes with the internal representation
Replaces terminal codes and |keycodes| (<CR>, <Esc>, ...) in a
string with the internal representation.
Parameters:~
{str} String to be converted.
{from_part} Legacy Vim parameter. Usually true.
{do_lt} Also translate <lt>. Does nothing if
`special` is false.
{special} Replace |keycodes|, e.g. <CR> becomes a "\n"
char.
nvim_command_output({str}) *nvim_command_output()*
TODO: Documentation
@ -182,8 +191,10 @@ nvim_eval({expr}) *nvim_eval()*
Evaluation result or expanded object
nvim_call_function({fname}, {args}) *nvim_call_function()*
Calls a VimL function with the given arguments. On VimL error:
Returns a generic error; v:errmsg is not updated.
Calls a VimL function with the given arguments
On VimL error: Returns a generic error; v:errmsg is not
updated.
Parameters:~
{fname} Function to call
@ -192,6 +203,23 @@ nvim_call_function({fname}, {args}) *nvim_call_function()*
Return:~
Result of the function call
nvim_execute_lua({code}, {args}) *nvim_execute_lua()*
Execute lua code. Parameters might be passed, they are
available inside the chunk as `...`. The chunk can return a
value.
To evaluate an expression, it must be prefixed with "return ".
For instance, to call a lua function with arguments sent in
and get its return value back, use the code "return
my_function(...)".
Parameters:~
{code} lua code to execute
{args} Arguments to the code
Return:~
Return value of lua code if present or NIL.
nvim_strwidth({str}) *nvim_strwidth()*
Calculates the number of display cells occupied by `text`.
<Tab> counts as one cell.
@ -382,6 +410,17 @@ nvim_get_mode() *nvim_get_mode()*
Return:~
Dictionary { "mode": String, "blocking": Boolean }
nvim_get_keymap({mode}) *nvim_get_keymap()*
Get a list of dictionaries describing global (i.e. non-buffer)
mappings Note that the "buffer" key will be 0 to represent
false.
Parameters:~
{mode} The abbreviation for the mode
Return:~
An array of maparg() like dictionaries describing mappings
nvim_get_api_info() *nvim_get_api_info()*
TODO: Documentation
@ -414,6 +453,54 @@ nvim_call_atomic({calls}) *nvim_call_atomic()*
error ocurred, the values from all preceding calls will
still be returned.
nvim__id({obj}) *nvim__id()*
Returns object given as argument
This API function is used for testing. One should not rely on
its presence in plugins.
Parameters:~
{obj} Object to return.
Return:~
its argument.
nvim__id_array({arr}) *nvim__id_array()*
Returns array given as argument
This API function is used for testing. One should not rely on
its presence in plugins.
Parameters:~
{arr} Array to return.
Return:~
its argument.
nvim__id_dictionary({dct}) *nvim__id_dictionary()*
Returns dictionary given as argument
This API function is used for testing. One should not rely on
its presence in plugins.
Parameters:~
{dct} Dictionary to return.
Return:~
its argument.
nvim__id_float({flt}) *nvim__id_float()*
Returns floating-point value given as argument
This API function is used for testing. One should not rely on
its presence in plugins.
Parameters:~
{flt} Value to return.
Return:~
its argument.
==============================================================================
Buffer Functions *api-buffer*
@ -492,6 +579,18 @@ nvim_buf_get_changedtick({buffer}) *nvim_buf_get_changedtick()*
Return:~
b:changedtickvalue.
nvim_buf_get_keymap({buffer}, {mode}) *nvim_buf_get_keymap()*
Get a list of dictionaries describing buffer-local mappings
Note that the buffer key in the dictionary will represent the
buffer handle where the mapping is present
Parameters:~
{mode} The abbreviation for the mode
{buffer_id} Buffer handle
Return:~
An array of maparg() like dictionaries describing mappings
nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()*
Sets a buffer-scoped (b:) variable

View File

@ -389,12 +389,26 @@ CTRL-L A match is done on the pattern in front of the cursor. If
If there are multiple matches the longest common part is
inserted in place of the pattern. If the result is shorter
than the pattern, no completion is done.
*/_CTRL-L*
When 'incsearch' is set, entering a search pattern for "/" or
"?" and the current match is displayed then CTRL-L will add
one character from the end of the current match. If
'ignorecase' and 'smartcase' are set and the command line has
no uppercase characters, the added character is converted to
lowercase.
*c_CTRL-G* */_CTRL-G*
CTRL-G When 'incsearch' is set, entering a search pattern for "/" or
"?" and the current match is displayed then CTRL-G will move
to the next match (does not take |search-offset| into account)
Use CTRL-T to move to the previous match. Hint: on a regular
keyboard T is above G.
*c_CTRL-T* */_CTRL-T*
CTRL-T When 'incsearch' is set, entering a search pattern for "/" or
"?" and the current match is displayed then CTRL-T will move
to the previous match (does not take |search-offset| into
account).
Use CTRL-G to move to the next match. Hint: on a regular
keyboard T is above G.
The 'wildchar' option defaults to <Tab> (CTRL-E when in Vi compatible mode; in
a previous version <Esc> was used). In the pattern standard wildcards '*' and

View File

@ -39,10 +39,16 @@ Functions ~
*highlightID()* Obsolete name for |hlID()|.
*last_buffer_nr()* Obsolete name for bufnr("$").
Modifiers ~
*:menu-<special>*
*:menu-special* <> notation is always enabled. |cpo-<|
*:map-<special>*
*:map-special* <> notation is always enabled. |cpo-<|
Options ~
*'fe'* 'fenc'+'enc' before Vim 6.0; no longer used.
*'langnoremap'* Deprecated alias to 'nolangremap'.
*'vi'*
*'viminfo'* Deprecated alias to 'shada' option.
vim:tw=78:ts=8:ft=help:norl:
vim:noet:tw=78:ts=8:ft=help:norl:

View File

@ -1852,10 +1852,11 @@ v:t_number Value of Number type. Read-only. See: |type()|
v:t_string Value of String type. Read-only. See: |type()|
*v:termresponse* *termresponse-variable*
v:termresponse The escape sequence returned by the terminal for the |t_RV|
termcap entry. It is set when Vim receives an escape sequence
that starts with ESC [ or CSI and ends in a 'c', with only
digits, ';' and '.' in between.
v:termresponse The escape sequence returned by the terminal for the DA
(request primary device attributes) control sequence. It is
set when Vim receives an escape sequence that starts with ESC
[ or CSI and ends in a 'c', with only digits, ';' and '.' in
between.
When this option is set, the TermResponse autocommand event is
fired, so that you can react to the response from the
terminal.

View File

@ -490,9 +490,6 @@ expression register: >
:amenu Insert.foobar "='foobar'<CR>P
Note that the '<' and 'k' flags in 'cpoptions' also apply here (when
included they make the <> form and raw key codes not being recognized).
Note that <Esc> in Cmdline mode executes the command, like in a mapping. This
is Vi compatible. Use CTRL-C to quit Cmdline mode.
@ -504,21 +501,13 @@ The ":set ic" will not be echoed when using this menu. Messages from the
executed command are still given though. To shut them up too, add a ":silent"
in the executed command: >
:menu <silent> Search.Header :exe ":silent normal /Header\r"<CR>
"<silent>" may also appear just after "<special>" or "<script>".
*:menu-<special>* *:menu-special*
Define a menu with <> notation for special keys, even though the "<" flag
may appear in 'cpoptions'. This is useful if the side effect of setting
'cpoptions' is not desired. Example: >
:menu <special> Search.Header /Header<CR>
"<special>" must appear as the very first argument to the ":menu" command or
just after "<silent>" or "<script>".
"<silent>" may also appear just after "<script>".
*:menu-<script>* *:menu-script*
The "to" part of the menu will be inspected for mappings. If you don't want
this, use the ":noremenu" command (or the similar one for a specific mode).
If you do want to use script-local mappings, add "<script>" as the very first
argument to the ":menu" command or just after "<silent>" or "<special>".
argument to the ":menu" command or just after "<silent>".
*menu-priority*
You can give a priority to a menu. Menus with a higher priority go more to

View File

@ -9,7 +9,147 @@ Lua Interface to Nvim *lua* *Lua*
Type <M-]> to see the table of contents.
==============================================================================
1. Commands *lua-commands*
1. Importing modules *lua-require*
Neovim lua interface automatically adjusts `package.path` and `package.cpath`
according to effective &runtimepath value. Adjustment happens after
'runtimepath' is changed. `package.path` is adjusted by simply appending
`/lua/?.lua` and `/lua/?/init.lua` to each directory from 'runtimepath' (`/`
is actually the first character of `package.config`).
Similarly to `package.path`, modified directories from `runtimepath` are also
added to `package.cpath`. In this case, instead of appending `/lua/?.lua` and
`/lua/?/init.lua` to each runtimepath, all unique `?`-containing suffixes of
the existing `package.cpath` are used. Here is an example:
1. Given that
- 'runtimepath' contains `/foo/bar,/xxx;yyy/baz,/abc`;
- initial (defined at compile time or derived from
`$LUA_CPATH`/`$LUA_INIT`) `package.cpath` contains
`./?.so;/def/ghi/a?d/j/g.elf;/def/?.so`.
2. It finds `?`-containing suffixes `/?.so`, `/a?d/j/g.elf` and `/?.so`, in
order: parts of the path starting from the first path component containing
question mark and preceding path separator.
3. The suffix of `/def/?.so`, namely `/?.so` is not unique, as its the same
as the suffix of the first path from `package.path` (i.e. `./?.so`). Which
leaves `/?.so` and `/a?d/j/g.elf`, in this order.
4. 'runtimepath' has three paths: `/foo/bar`, `/xxx;yyy/baz` and `/abc`. The
second one contains semicolon which is a paths separator so it is out,
leaving only `/foo/bar` and `/abc`, in order.
5. The cartesian product of paths from 4. and suffixes from 3. is taken,
giving four variants. In each variant `/lua` path segment is inserted
between path and suffix, leaving
- `/foo/bar/lua/?.so`
- `/foo/bar/lua/a?d/j/g.elf`
- `/abc/lua/?.so`
- `/abc/lua/a?d/j/g.elf`
6. New paths are prepended to the original `package.cpath`.
The result will look like this:
`/foo/bar,/xxx;yyy/baz,/abc` ('runtimepath')
× `./?.so;/def/ghi/a?d/j/g.elf;/def/?.so` (`package.cpath`)
= `/foo/bar/lua/?.so;/foo/bar/lua/a?d/j/g.elf;/abc/lua/?.so;/abc/lua/a?d/j/g.elf;./?.so;/def/ghi/a?d/j/g.elf;/def/?.so`
Note: to keep up with 'runtimepath' updates paths added at previous update are
remembered and removed at the next update, while all paths derived from the
new 'runtimepath' are prepended as described above. This allows removing
paths when path is removed from 'runtimepath', adding paths when they are
added and reordering `package.path`/`package.cpath` content if 'runtimepath'
was reordered.
Note 2: even though adjustments happens automatically Neovim does not track
current values of `package.path` or `package.cpath`. If you happened to
delete some paths from there you need to reset 'runtimepath' to make them
readded. Just running `let &runtimepath = &runtimepath` should work.
Note 3: skipping paths from 'runtimepath' which contain semicolons applies
both to `package.path` and `package.cpath`. Given that there is a number of
badly written plugins using shell which will not work with paths containing
semicolons it is better to not have them in 'runtimepath' at all.
------------------------------------------------------------------------------
1.1. Example of the plugin which uses lua modules: *lua-require-example*
The following example plugin adds a command `:MakeCharBlob` which transforms
current buffer into a long `unsigned char` array. Lua contains transformation
function in a module `lua/charblob.lua` which is imported in
`autoload/charblob.vim` (`require("charblob")`). Example plugin is supposed
to be put into any directory from 'runtimepath', e.g. `~/.config/nvim` (in
this case `lua/charblob.lua` means `~/.config/nvim/lua/charblob.lua`).
autoload/charblob.vim: >
function charblob#encode_buffer()
call setline(1, luaeval(
\ 'require("charblob").encode(unpack(_A))',
\ [getline(1, '$'), &textwidth, ' ']))
endfunction
plugin/charblob.vim: >
if exists('g:charblob_loaded')
finish
endif
let g:charblob_loaded = 1
command MakeCharBlob :call charblob#encode_buffer()
lua/charblob.lua: >
local function charblob_bytes_iter(lines)
local init_s = {
next_line_idx = 1,
next_byte_idx = 1,
lines = lines,
}
local function next(s, _)
if lines[s.next_line_idx] == nil then
return nil
end
if s.next_byte_idx > #(lines[s.next_line_idx]) then
s.next_line_idx = s.next_line_idx + 1
s.next_byte_idx = 1
return ('\n'):byte()
end
local ret = lines[s.next_line_idx]:byte(s.next_byte_idx)
if ret == ('\n'):byte() then
ret = 0 -- See :h NL-used-for-NUL.
end
s.next_byte_idx = s.next_byte_idx + 1
return ret
end
return next, init_s, nil
end
local function charblob_encode(lines, textwidth, indent)
local ret = {
'const unsigned char blob[] = {',
indent,
}
for byte in charblob_bytes_iter(lines) do
-- .- space + number (width 3) + comma
if #(ret[#ret]) + 5 > textwidth then
ret[#ret + 1] = indent
else
ret[#ret] = ret[#ret] .. ' '
end
ret[#ret] = ret[#ret] .. (('%3u,'):format(byte))
end
ret[#ret + 1] = '};'
return ret
end
return {
bytes_iter = charblob_bytes_iter,
encode = charblob_encode,
}
==============================================================================
2. Commands *lua-commands*
*:lua*
:[range]lua {chunk}

View File

@ -442,8 +442,8 @@ available on a few terminals.
Note: There are two codes for the delete key. 127 is the decimal ASCII value
for the delete key, which is always recognized. Some delete keys send another
value, in which case this value is obtained from the termcap entry "kD". Both
values have the same effect.
value, in which case this value is obtained from the |terminfo| entry "key_dc".
Both values have the same effect.
Note: The keypad keys are used in the same way as the corresponding "normal"
keys. For example, <kHome> has the same effect as <Home>. If a keypad key

View File

@ -102,36 +102,30 @@ function. Here's a more object-oriented version of the above:
>
let Shell = {}
function Shell.on_stdout(job_id, data) dict
call append(line('$'), self.get_name().' stdout: '.join(a:data))
function Shell.on_stdout(_job_id, data, event)
call append(line('$'),
\ printf('[%s] %s: %s', a:event, self.name, join(a:data[:-2])))
endfunction
function Shell.on_stderr(job_id, data) dict
call append(line('$'), self.get_name().' stderr: '.join(a:data))
let Shell.on_stderr = function(Shell.on_stdout)
function Shell.on_exit(job_id, _data, event)
let msg = printf('job %d ("%s") finished', a:job_id, self.name)
call append(line('$'), printf('[%s] BOOM!', a:event))
call append(line('$'), printf('[%s] %s!', a:event, msg))
endfunction
function Shell.on_exit(job_id, data) dict
call append(line('$'), self.get_name().' exited')
function Shell.new(name, cmd)
let object = extend(copy(g:Shell), {'name': a:name})
let object.cmd = ['sh', '-c', a:cmd]
let object.id = jobstart(object.cmd, object)
$
return object
endfunction
function Shell.get_name() dict
return 'shell '.self.name
endfunction
function Shell.new(name, ...) dict
let instance = extend(copy(g:Shell), {'name': a:name})
let argv = ['bash']
if a:0 > 0
let argv += ['-c', a:1]
endif
let instance.id = jobstart(argv, instance)
return instance
endfunction
let s1 = Shell.new('1')
let s2 = Shell.new('2', 'for i in {1..10}; do echo hello $i!; sleep 1; done')
let instance = Shell.new('bomb',
\ 'for i in $(seq 9 -1 1); do echo $i 1>&$((i % 2 + 1)); sleep 1; done')
<
To send data to the job's stdin, one can use the |jobsend()| function, like
this:
>

View File

@ -149,7 +149,7 @@ type "a", then "bar" will get inserted.
1.2 SPECIAL ARGUMENTS *:map-arguments*
"<buffer>", "<nowait>", "<silent>", "<special>", "<script>", "<expr>" and
"<buffer>", "<nowait>", "<silent>", "<script>", "<expr>" and
"<unique>" can be used in any order. They must appear right after the
command, before any other arguments.
@ -189,12 +189,6 @@ Prompts will still be given, e.g., for inputdialog().
Using "<silent>" for an abbreviation is possible, but will cause redrawing of
the command line to fail.
*:map-<special>* *:map-special*
Define a mapping with <> notation for special keys, even though the "<" flag
may appear in 'cpoptions'. This is useful if the side effect of setting
'cpoptions' is not desired. Example: >
:map <special> <F12> /Header<CR>
<
*:map-<script>* *:map-script*
If the first argument to one of these commands is "<script>" and it is used to
define a new mapping or abbreviation, the mapping will only remap characters
@ -443,17 +437,15 @@ There are two ways to map a special key:
1. The Vi-compatible method: Map the key code. Often this is a sequence that
starts with <Esc>. To enter a mapping like this you type ":map " and then
you have to type CTRL-V before hitting the function key. Note that when
the key code for the key is in the termcap, it will automatically be
translated into the internal code and become the second way of mapping
(unless the 'k' flag is included in 'cpoptions').
the key code for the key is in the |terminfo| entry, it will automatically
be translated into the internal code and become the second way of mapping.
2. The second method is to use the internal code for the function key. To
enter such a mapping type CTRL-K and then hit the function key, or use
the form "#1", "#2", .. "#9", "#0", "<Up>", "<S-Down>", "<S-F7>", etc.
(see table of keys |key-notation|, all keys from <Up> can be used). The
first ten function keys can be defined in two ways: Just the number, like
"#2", and with "<F>", like "<F2>". Both stand for function key 2. "#0"
refers to function key 10. The <> form cannot be used when 'cpoptions'
includes the '<' flag.
refers to function key 10.
DETAIL: Vim first checks if a sequence from the keyboard is mapped. If it
isn't the terminal key codes are tried. If a terminal code is found it is
@ -571,9 +563,9 @@ Since the '|' character is used to separate a map command from the next
command, you will have to do something special to include a '|' in {rhs}.
There are three methods:
use works when example ~
<Bar> '<' is not in 'cpoptions' :map _l :!ls <Bar> more^M
<Bar> always :map _l :!ls <Bar> more^M
\| 'b' is not in 'cpoptions' :map _l :!ls \| more^M
^V| always, in Vim and Vi :map _l :!ls ^V| more^M
^V| always :map _l :!ls ^V| more^M
(here ^V stands for CTRL-V; to get one CTRL-V you have to type it twice; you
cannot use the <> notation "<C-V>" here).
@ -628,8 +620,7 @@ out about, ^D is CTRL-D).
1.8 EXAMPLES *map-examples*
A few examples (given as you type them, for "<CR>" you type four characters;
the '<' flag must not be present in 'cpoptions' for this to work). >
A few examples (as you type them: for "<CR>" you type four characters). >
:map <F3> o#include
:map <M-g> /foo<CR>cwbar<Esc>
@ -881,7 +872,6 @@ character is mostly ignored otherwise.
It is possible to move the cursor after an abbreviation: >
:iab if if ()<Left>
This does not work if 'cpoptions' includes the '<' flag. |<>|
You can even do more complicated things. For example, to consume the space
typed after an abbreviation: >
@ -1029,8 +1019,7 @@ functions used in one script use the same name as in other scripts. To avoid
this, they can be made local to the script.
*<SID>* *<SNR>* *E81*
The string "<SID>" can be used in a mapping or menu. This requires that the
'<' flag is not present in 'cpoptions'.
The string "<SID>" can be used in a mapping or menu.
When executing the map command, Vim will replace "<SID>" with the special
key code <SNR>, followed by a number that's unique for the script, and an
underscore. Example: >

View File

@ -24,10 +24,7 @@ achieve special effects. These options come in three forms:
:se[t] all Show all but terminal options.
:se[t] termcap Show all terminal options. Note that in the GUI the
key codes are not shown, because they are generated
internally and can't be changed. Changing the terminal
codes in the GUI is not useful either...
:se[t] termcap Do nothing. Nvim uses |terminfo|.
*E518* *E519*
:se[t] {option}? Show value of {option}.
@ -1571,7 +1568,6 @@ A jump table for the options with a short description can be found at |Q_op|.
results in X being mapped to:
'B' included: "\^[" (^[ is a real <Esc>)
'B' excluded: "<Esc>" (5 characters)
('<' excluded in both cases)
*cpo-c*
c Searching continues at the end of any match at the
cursor position, but not further than the start of the
@ -1621,15 +1617,6 @@ A jump table for the options with a short description can be found at |Q_op|.
J A |sentence| has to be followed by two spaces after
the '.', '!' or '?'. A <Tab> is not recognized as
white space.
*cpo-k*
k Disable the recognition of raw key codes in
mappings, abbreviations, and the "to" part of menu
commands. For example, if <Key> sends ^[OA (where ^[
is <Esc>), the command ":map X ^[OA" results in X
being mapped to:
'k' included: "^[OA" (3 characters)
'k' excluded: "<Key>" (one key code)
Also see the '<' flag below.
*cpo-K*
K Don't wait for a key code to complete when it is
halfway through a mapping. This breaks mapping
@ -1763,14 +1750,6 @@ A jump table for the options with a short description can be found at |Q_op|.
+ When included, a ":write file" command will reset the
'modified' flag of the buffer, even though the buffer
itself may still be different from its file.
*cpo-<*
< Disable the recognition of special key codes in |<>|
form in mappings, abbreviations, and the "to" part of
menu commands. For example, the command
":map X <Tab>" results in X being mapped to:
'<' included: "<Tab>" (5 characters)
'<' excluded: "^I" (^I is a real <Tab>)
Also see the 'k' flag above.
*cpo->*
> When appending to a register, put a line break before
the appended text.
@ -2756,14 +2735,10 @@ A jump table for the options with a short description can be found at |Q_op|.
*'guicursor'* *'gcr'* *E545* *E546* *E548* *E549*
'guicursor' 'gcr' string (default "n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20")
global
Configures the cursor style for each mode. Works in the GUI and some
terminals.
Configures the cursor style for each mode. Works in the GUI and many
terminals. See |cursor-shape| for details.
With tmux you might need this in ~/.tmux.conf (see terminal-overrides
in the tmux(1) manual page): >
set -ga terminal-overrides ',*:Ss=\E[%p1%d q:Se=\E[2 q'
< To disable cursor-styling, reset the option: >
To disable cursor-styling, reset the option: >
:set guicursor=
< To enable mode shapes, "Cursor" highlight, and blinking: >
@ -6272,7 +6247,7 @@ A jump table for the options with a short description can be found at |Q_op|.
for any key that can follow <c-f> in a mapping.
*'ttimeout'* *'nottimeout'*
'ttimeout' boolean (default off)
'ttimeout' boolean (default on)
global
This option and 'ttimeoutlen' determine the behavior when part of a
key code sequence has been received by the terminal UI. For example,
@ -6287,7 +6262,7 @@ A jump table for the options with a short description can be found at |Q_op|.
complete.
*'ttimeoutlen'* *'ttm'*
'ttimeoutlen' 'ttm' number (default -1)
'ttimeoutlen' 'ttm' number (default 50)
global
The time in milliseconds that is waited for a key code
sequence to complete. Also used for CTRL-\ CTRL-N and CTRL-\ CTRL-G

View File

@ -116,29 +116,48 @@ To use the RVM "system" Ruby installation: >
==============================================================================
Clipboard integration *provider-clipboard* *clipboard*
Nvim has no direct connection to the system clipboard. Instead it is
accessible through a |provider| which transparently uses shell commands for
communicating with the clipboard.
Nvim has no direct connection to the system clipboard. Instead it depends on
a |provider| which transparently uses shell commands to communicate with the
system clipboard or any other clipboard "backend".
Clipboard access is implicitly enabled if any of the following clipboard tools
are found in your `$PATH`.
To ALWAYS use the clipboard for ALL operations (instead of interacting with
the '+' and/or '*' registers explicitly): >
- xclip
- xsel (newer alternative to xclip)
- pbcopy/pbpaste (macOS)
- lemonade (for SSH) https://github.com/pocke/lemonade
- doitclient (for SSH) http://www.chiark.greenend.org.uk/~sgtatham/doit/
The presence of a suitable clipboard tool implicitly enables the '+' and '*'
registers.
If you want to ALWAYS use the clipboard for ALL operations (as opposed
to interacting with the '+' and/or '*' registers explicitly), set the
following option:
>
set clipboard+=unnamedplus
<
See 'clipboard' for details and more options.
See 'clipboard' for details and options.
*clipboard-tool*
The presence of a working clipboard tool implicitly enables the '+' and '*'
registers. Nvim looks for these clipboard tools, in order of priority:
- |g:clipboard|
- pbcopy/pbpaste (macOS)
- xclip
- xsel (newer alternative to xclip)
- lemonade (for SSH) https://github.com/pocke/lemonade
- doitclient (for SSH) http://www.chiark.greenend.org.uk/~sgtatham/doit/
- win32yank (Windows)
- tmux (if $TMUX is set)
*g:clipboard*
To configure a custom clipboard tool, set `g:clipboard` to a dictionary: >
let g:clipboard = {
\ 'name': 'myClipboard',
\ 'copy': {
\ '+': 'tmux load-buffer -',
\ '*': 'tmux load-buffer -',
\ },
\ 'paste': {
\ '+': 'tmux save-buffer -',
\ '*': 'tmux save-buffer -',
\ },
\ 'cache_enabled': 1,
\ }
If `cache_enabled` is |TRUE| then when a selection is copied, Nvim will cache
the selection until the copy command process dies. When pasting, if the copy
process has not died, the cached selection is applied.
==============================================================================
X11 selection mechanism *clipboard-x11* *x11-selection*

View File

@ -571,8 +571,8 @@ In Insert or Command-line mode:
*Q_op* Options
|:set| :se[t] show all modified options
|:set| :se[t] all show all non-termcap options
|:set| :se[t] termcap show all termcap options
|:set| :se[t] all show all options
|:set| :se[t] termcap Do nothing. (|terminfo|)
|:set| :se[t] {option} set boolean option (switch it on),
show string or number option
|:set| :se[t] no{option} reset boolean option (switch it off)

View File

@ -214,7 +214,7 @@ argument.
:set to display option values.
When 'verbose' is non-zero messages are printed (for
debugging, to stderr).
$TERM is not used.
$TERM (see |TERM|) is not used.
If Vim appears to be stuck try typing "qa!<Enter>". You don't
get a prompt thus you can't see Vim is waiting for you to type
something.
@ -355,7 +355,7 @@ argument.
At startup, Vim checks environment variables and files and sets values
accordingly. Vim proceeds in this order:
1. Set the 'shell' option *SHELL* *COMSPEC* *TERM*
1. Set the 'shell' option *SHELL* *COMSPEC*
The environment variable SHELL, if it exists, is used to set the
'shell' option. On Windows, the COMSPEC variable is used
if SHELL is not set.

View File

@ -4696,7 +4696,7 @@ cterm={attr-list} *highlight-cterm*
ctermfg={color-nr} *highlight-ctermfg* *E421*
ctermbg={color-nr} *highlight-ctermbg*
The {color-nr} argument is a color number. Its range is zero to
(not including) the number given by the termcap entry "Co".
(not including) the number of |terminfo-colors| available.
The actual color with this number depends on the type of terminal
and its settings. Sometimes the color also depends on the settings of
"cterm". For example, on some systems "cterm=bold ctermfg=3" gives
@ -4768,9 +4768,8 @@ ctermbg={color-nr} *highlight-ctermbg*
delete the "g:colors_name" variable when you don't want this.
When you have set "ctermfg" or "ctermbg" for the Normal group, Vim
needs to reset the color when exiting. This is done with the "op"
termcap entry |t_op|. If this doesn't work correctly, try setting the
't_op' option in your vimrc.
needs to reset the color when exiting. This is done with the
"orig_pair" |terminfo| entry.
*E419* *E420*
When Vim knows the normal foreground and background colors, "fg" and
"bg" can be used as color names. This only works after setting the
@ -5207,10 +5206,7 @@ To test your color setup, a file has been included in the Vim distribution.
To use it, execute this command: >
:runtime syntax/colortest.vim
Some versions of xterm (and other terminals, like the Linux console) can
output lighter foreground colors, even though the number of colors is defined
at 8. Therefore Vim sets the "cterm=bold" attribute for light foreground
colors, when 't_Co' is 8.
Nvim uses |256-color| and |true-color| terminal capabilities whereever possible.
==============================================================================
18. When syntax is slow *:syntime*

View File

@ -20,21 +20,194 @@ Startup *startup-terminal*
When Vim is started a default terminal type is assumed. for MS-DOS this is
the pc terminal, for Unix an ansi terminal.
*termcap* *terminfo* *E557* *E558* *E559*
On Unix the terminfo database or termcap file is used. This is referred to as
"termcap" in all the documentation.
*terminfo* *E557* *E558* *E559*
On Unix the terminfo database is used. There is no access to the terminfo
settings with |:set|.
The Unibilium library (used by Nvim to read terminfo) allows you to override
an out-of-date system terminfo database with one in your $HOME/.terminfo/
directory, in part or in whole.
Building your own up-to-date terminfo database is usually as simple as running
this as a non-superuser:
>
wget http://invisible-island.net/datafiles/current/terminfo.src.gz
gunzip terminfo.src.gz
tic terminfo.src
<
*TERM*
If you experience terminal difficulties, first ensure that you have set the
correct terminal type in your $TERM environment variable so that Nvim is
pulling the correct entry from the terminfo database in the first place.
Per the terminfo source file from ncurses:
For these terminals Set $TERM to |builtin-terms|?
iTerm.app "iterm" or "iTerm.app" Y
anything libvte based "vte" or "vte-256color" Y
(e.g. GNOME Terminal) ("gnome" and "gnome-256color" are
available as aliases for these)
tmux "tmux" or "tmux-256color" Y
screen "screen" or "screen-256color" Y
PuTTY "putty" or "putty-256color" Y
Terminal.app "nsterm" N
Linux virtual terminal "linux" or "linux-256color" Y
Describing any of these as "xterm" or "xterm-256colour" will not describe the
terminal correctly to Nvim, and will cause various kinds of problematic
behaviours.
Setting your $TERM environment variable to the correct value also avoids the
problem that SSH does not mirror arbitrary client-end environment variables
such as $COLORTERM, $XTERM_VERSION, $VTE_VERSION, $KONSOLE_PROFILE_NAME, and
$TERM_PROGRAM to the server end, whereas it does send the $TERM environment
variable.
See |terminfo| for dealing with out of date terminfo databases.
*builtin-terms* *builtin_terms*
If a |terminfo| database is not available, or no entry for the terminal type is
found in that database, Nvim will look up the terminal type in a compiled-in
mini-database of terminfo entries for "xterm", "putty", "screen", "tmux",
"rxvt", "iterm", "interix", "linux", "st", "vte", "gnome", and "ansi".
The lookup matches the initial portion of the terminal type, so (for example)
"putty-256color" and "putty" will both be mapped to the built-in "putty"
entry. The built-in terminfo entries describe the terminal as 256-colour
capable if possible. See |termcap-colors|.
If no built-in terminfo record matches the terminal type, the built-in "ansi"
terminfo record is used as a final fallback.
The built-in mini-database is not combined with an external terminfo database,
nor can it be used in preference to one. You can thus entirely override any
omissions or out-of-date information in the built-in terminfo database by
supplying an external one with entries for the terminal type.
Settings depending on terminal *term-dependent-settings*
If you want to set options or mappings, depending on the terminal name, you
can do this best in your vimrc. Example: >
can do this best in your init.vim. Example: >
if &term == "xterm"
... xterm maps and settings ...
elseif &term =~ "vt10."
... vt100, vt102 maps and settings ...
endif
if $TERM =~ '^\(rxvt\|screen\|interix\|putty\)\(-.*\)\?$'
set notermguicolors
elseif $TERM =~ '^\(tmux\|iterm\|vte\|gnome\)\(-.*\)\?$'
set termguicolors
elseif $TERM =~ '^\(xterm\)\(-.*\)\?$'
if $XTERM_VERSION != ''
set termguicolors
elseif $KONSOLE_PROFILE_NAME != ''
set termguicolors
elseif $VTE_VERSION != ''
set termguicolors
else
set notermguicolors
endif
elseif $TERM =~ ...
... and so forth ...
endif
<
*scroll-region* *xterm-scroll-region*
Where possible, Nvim will use the terminal's ability to set a scroll region in
order to redraw faster when a window is scrolled. If the terminal's terminfo
description describes an ability to set top and bottom scroll margins, that is
used.
This will not speed up scrolling in a window that is not the full width of the
terminal. Xterm has an extra ability, not described by terminfo, to set left
and right scroll margins as well. If Nvim detects that the terminal is Xterm,
it will make use of this ability to speed up scrolling that is not the full
width of the terminal.
This ability is only present in genuine Xterm, not in the many terminal
emulators that incorrectly describe themselves as xterm. Nvim's detection of
genuine Xterm will not work over an SSH connection, because the environment
variable, set by genuine Xterm, that it looks for is not automatically
replicated over an SSH login session.
*256-color* *terminfo-colors* *termcap-colors*
Nvim can make use of 256-colour terminals and tries to do so whereever it can.
If the |terminfo| description of the terminal says that it supports fewer
colours, Nvim will override this for many terminal types, including "linux"
(whose virtual terminals have had 256-colour support since version 4.8) and
anything (even if falsely) claiming to be "xterm". It will also set 256
colours when the COLORTERM or TERM environment variables contain the string
"256" somewhere.
Nvim similarly assumes that any terminal emulator that sets the COLORTERM
environment variable at all, to anything, is capable of at least 16-colour
operation; and it will override |terminfo| saying that it has fewer colours
available.
*true-color* *xterm-true-color*
Nvim supports using true (24-bit) colours in the terminal, on terminals that
support it. It uses the same |terminfo| extensions that were proposed by
Rüdiger Sonderfeld in 2013 for this: "setrgbf" and "setrgbb". If your
terminfo definition specifies these, then nothing more is required.
If your terminfo definition is missing them, then Nvim will decide whether to
add them to your terminfo definition, using the ISO 8613-6:1994/ITU T.416:1993
control sequences for setting RGB colours, but modified to use semicolons
instead of colons unless the terminal is known to follow the standard.
(Semicolons cause ambiguities that the standard avoided by specifying colons
as a sub-parameter delimiter. A historical misunderstanding meant that many
terminal emulators ended up using semicolons for many years, though.)
A new convention, pioneered in 2016 by tmux, is the "Tc" terminfo extension.
If your terminal's terminfo definition has this flag, Nvim will add
constructed "setrgbf" and "setrgbb" capabilities as if they had been in the
terminfo definition.
If your terminal's terminfo definition does not (yet) have this flag, Nvim
will fall back to looking at the TERM and other environment variables. It
will add constructed "setrgbf" and "setrgbb" capabilities in the case of the
the "rxvt", "linux", "st", "tmux", and "iterm" terminal types, or when
Konsole, genuine Xterm, a libvte terminal emulator version 0.36 or later, or a
terminal emulator that sets the COLORTERM environment variable to "truecolor"
is detected.
*xterm-resize*
Nvim can resize the terminal display on some terminals that implement an
extension pioneered by the dtterm program. |terminfo| does not have a flag
for this extension. So Nvim simply assumes that (all) "dtterm", "xterm",
"teraterm", "rxvt" terminal types, and Konsole, are capable of this.
*cursor-shape* *terminfo-cursor-shape* *termcap-cursor-shape*
Nvim will adjust the shape of the cursor from a block to a line when in insert
mode (or as specified by the 'guicursor' option), on terminals that support
it. It uses the same |terminfo| extensions that were pioneered by tmux for
this: "Ss" and "Se". If your terminfo definition specifies these, as some
(such as those based upon "xterm+tmux") do, then nothing more is required.
If your terminfo definition is missing them, then Nvim will decide whether to
add them to your terminfo definition, by looking at the TERM and other
environment variables. For the "rxvt", "putty", "linux", "screen",
"teraterm", and "iterm" terminal types, or when Konsole, a libvte-based
terminal emulator, or genuine Xterm are detected, it will add constructed
"Ss" and "Se" capabilities.
Note: Sometimes it will appear that Nvim when run within tmux is not changing
the cursor, but in fact it is tmux receiving instructions from Nvim to change
the cursor and not knowing what to do in turn. tmux has to translate what it
receives from Nvim into whatever control sequence is appropriate for the
terminal that it is outputting to. It shares a common mechanism with Nvim, of
using the "Ss" and "Se" capabilities from terminfo (for the output terminal)
if they are present. Unlike Nvim, if they are not present in terminfo you
will have to add them by setting the tmux "terminal-overrides" setting in
$HOME/.tmux.conf .
See the tmux(1) manual page for the details of how and what to do in the tmux
configuration file. It will look something like: >
set -ga terminal-overrides '*:Ss=\E[%p1%d q:Se=\E[ q'
<or (alas!) for Konsole specifically, something more complex like: >
set -ga terminal-overrides \
'xterm*:\E]50;CursorShape=%?%p1%{3}%<%t%{0}%e%{1}%;%d\007'
<but these are only rough examples that do not include all of the other stuff
that occurs in that setting.
*cs7-problem*
Note: If the terminal settings are changed after running Vim, you might have
an illegal combination of settings. This has been reported on Solaris 2.5
@ -69,20 +242,6 @@ them as a cursor key. When you type you normally are not that fast, so they
are recognized as individual typed commands, even though Vim receives the same
sequence of bytes.
*xterm-8bit* *xterm-8-bit*
Xterm can be run in a mode where it uses 8-bit escape sequences. The CSI code
is used instead of <Esc>[. The advantage is that an <Esc> can quickly be
recognized in Insert mode, because it can't be confused with the start of a
special key.
For the builtin termcap entries, Vim checks if the 'term' option contains
"8bit" anywhere. It then uses 8-bit characters for the termcap entries, the
mouse and a few other things. You would normally set $TERM in your shell to
"xterm-8bit" and Vim picks this up and adjusts to the 8-bit setting
automatically.
When Vim receives a response to the "request version" sequence and it
starts with CSI, it assumes that the terminal is in 8-bit mode and will
convert all key sequences to their 8-bit variants.
==============================================================================
Window size *window-size*
@ -93,7 +252,7 @@ On Unix systems, three methods are tried to get the window size:
- an ioctl call (TIOCGSIZE or TIOCGWINSZ, depends on your system)
- the environment variables "LINES" and "COLUMNS"
- from the termcap entries "li" and "co"
- from the |terminfo| entries "lines" and "columns"
If everything fails a default size of 24 lines and 80 columns is assumed. If
a window-resize signal is received the size will be set again. If the window
@ -116,30 +275,27 @@ cursor position is shown in the status line. If you are using horizontal
scrolling ('wrap' option off) consider setting 'sidescroll' to a small
number.
If you have a slow terminal you may want to reset the 'showcmd' option.
The command characters will not be shown in the status line. If the terminal
scrolls very slowly, set the 'scrolljump' to 5 or so. If the cursor is moved
off the screen (e.g., with "j") Vim will scroll 5 lines at a time. Another
possibility is to reduce the number of lines that Vim uses with the command
"z{height}<CR>".
If you have a slow terminal you may want to reset the 'showcmd' and 'ruler'
options. The command characters and cursor positions will not be shown in the
status line (which involves a lot of cursor motions and attribute changes for
every keypress or movement). If the terminal scrolls very slowly, set the
'scrolljump' to 5 or so. If the cursor is moved off the screen (e.g., with
"j") Vim will scroll 5 lines at a time. Another possibility is to reduce the
number of lines that Vim uses with the command "z{height}<CR>".
If the characters from the terminal are arriving with more than 1 second
between them you might want to set the 'timeout' and/or 'ttimeout' option.
See the "Options" chapter |options|.
If you are using a color terminal that is slow, use this command: >
If you are using a color terminal that is slow when displaying lines beyond
the end of a buffer, this is because Nvim is drawing the whitespace twice, in
two sets of colours and attributes. To prevent this, use this command: >
hi NonText cterm=NONE ctermfg=NONE
This avoids that spaces are sent when they have different attributes. On most
terminals you can't see this anyway.
If you are using Vim over a slow serial line, you might want to try running
Vim inside the "screen" program. Screen will optimize the terminal I/O quite
a bit.
If you are testing termcap options, but you cannot see what is happening,
you might want to set the 'writedelay' option. When non-zero, one character
is sent to the terminal at a time (does not work for MS-DOS). This makes the
screen updating a lot slower, making it possible to see what is happening.
This draws the spaces with the default colours and attributes, which allows the
second pass of drawing to be optimized away. Note: Although in theory the
colours of whitespace are immaterial, in practice they change the colours of
cursors and selections that cross them. This may have a visible, but minor,
effect on some UIs.
==============================================================================
Using the mouse *mouse-using*

View File

@ -113,7 +113,6 @@ screen, you can use CTRL-X CTRL-E and CTRL-X CTRL-Y to scroll the screen.
To make this easier, you could use these mappings: >
:inoremap <C-E> <C-X><C-E>
:inoremap <C-Y> <C-X><C-Y>
(Type this literally, make sure the '<' flag is not in 'cpoptions').
You then lose the ability to copy text from the line above/below the cursor
|i_CTRL-E|.
@ -129,8 +128,6 @@ If you like the scrolling to go a bit smoother, you can use these mappings: >
:map <C-U> <C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y>
:map <C-D> <C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E>
(Type this literally, make sure the '<' flag is not in 'cpoptions').
==============================================================================
Correcting common typing mistakes *type-mistakes*
@ -282,9 +279,7 @@ For Emacs-style editing on the command-line: >
:cnoremap <Esc><C-B> <S-Left>
" forward one word
:cnoremap <Esc><C-F> <S-Right>
NOTE: This requires that the '<' flag is excluded from 'cpoptions'. |<>|
<
*format-bullet-list*
This mapping will format any bullet list. It requires that there is an empty
line above and below each list entry. The expression commands are used to
@ -300,8 +295,7 @@ be able to give comments to the parts of the mapping. >
:execute m |" define the mapping
(<> notation |<>|. Note that this is all typed literally. ^W is "^" "W", not
CTRL-W. You can copy/paste this into Vim if '<' is not included in
'cpoptions'.)
CTRL-W.)
Note that the last comment starts with |", because the ":execute" command
doesn't accept a comment directly.

View File

@ -156,6 +156,15 @@ are always available and may be used simultaneously in separate plugins. The
`neovim` pip package must be installed to use Python plugins in Nvim (see
|provider-python|).
Because of general |256-color| usage whereever possible, Nvim will even use
256-colour capability on Linux virtual terminals. Vim uses only 8 colours
plus bright foreground on Linux VTs.
Vim combines what is in its |builtin-terms| with what it reads from termcap,
and has a |ttybuiltin| setting to control how that combination works. Nvim
uses either one or the other of an external |terminfo| entry or the built-in
one. It does not attempt to mix data from the two.
|:!| does not support "interactive" commands. Use |:terminal| instead.
(GUI Vim has a similar limitation, see ":help gui-pty" in Vim.)
@ -244,6 +253,8 @@ Lua interface (|if_lua.txt|):
while calling lua chunk: [string "<VimL compiled string>"]:1: TEST” in
Neovim.
- Lua has direct access to Nvim |API| via `vim.api`.
- Lua package.path and package.cpath are automatically updated according to
'runtimepath': |lua-require|.
- Currently, most legacy Vim features are missing.
|input()| and |inputdialog()| gained support for each others features (return
@ -281,6 +292,25 @@ Nvim does not have special `t_XX` options nor <t_XX> keycodes to configure
terminal capabilities. Instead Nvim treats the terminal as any other UI. For
example, 'guicursor' sets the terminal cursor style if possible.
*'term'* *E529* *E530* *E531*
The 'term' option has a fixed value, present only for script compatibility and
intentionally not the same as any known terminal type name. It should be a
rare case in Nvim where one needs |term-dependent-settings|, for which use the
|TERM| environment variable.
*termcap*
Nvim never uses the termcap database and only uses |terminfo|. See
|builtin-terms| for what happens on operating systems without a terminfo
database.
*xterm-8bit* *xterm-8-bit*
Xterm can be run in a mode where it uses true 8-bit CSI. Supporting this
requires autodetection of whether the terminal is in UTF-8 mode or non-UTF-8
mode, as the 8-bit CSI character has to be written differently in each case.
Vim issues a "request version" sequence to the terminal at startup and looks
at how the terminal is sending CSI. Nvim does not issue such a sequence and
always uses 7-bit control sequences.
'ttyfast':
":set ttyfast" is ignored
":set nottyfast" is an error
@ -308,7 +338,7 @@ Test functions:
Other options:
'antialias'
'cpoptions' ("g", "w", "H", "*", "-", "j", and all POSIX flags were removed)
'cpoptions' (g j k H w < * - and all POSIX flags were removed)
'encoding' ("utf-8" is always used)
'esckeys'
'guioptions' "t" flag was removed
@ -322,7 +352,6 @@ Other options:
'shelltype'
*'shortname'* *'sn'* *'noshortname'* *'nosn'*
*'swapsync'* *'sws'*
*'term'* *E529* *E530* *E531*
*'termencoding'* *'tenc'* (Vim 7.4.852 also removed this for Windows)
'textauto'
'textmode'

View File

@ -271,7 +271,7 @@ mode. For example, if you would like the "/" command not to extend the Visual
area, but instead take the highlighted text and search for that: >
:vmap / y/<C-R>"<CR>
(In the <> notation |<>|, when typing it you should type it literally; you
need to remove the 'B' and '<' flags from 'cpoptions'.)
need to remove the 'B' flag from 'cpoptions'.)
If you want to give a register name using the """ command, do this just before
typing the operator character: "v{move-around}"xd".
@ -375,7 +375,7 @@ Here is an example, to replace the selected text with the output of "date": >
:vmap _a <Esc>`>a<CR><Esc>`<i<CR><Esc>!!date<CR>kJJ
(In the <> notation |<>|, when typing it you should type it literally; you
need to remove the 'B' and '<' flags from 'cpoptions')
need to remove the 'B' flag from 'cpoptions')
What this does is:
<Esc> stop Visual mode
@ -392,7 +392,7 @@ selected text: >
:vmap X y/<C-R>"<CR>
(In the <> notation |<>|, when typing it you should type it literally; you
need to remove the 'B' and '<' flags from 'cpoptions')
need to remove the 'B' flag from 'cpoptions')
Note that special characters (like '.' and '*') will cause problems.

View File

@ -117,7 +117,7 @@ check if the 'highlight' option contains "si". In version 3.0, this meant to
invert the status line. Now it should be "sr", reverse the status line, as
"si" now stands for italic! If italic is not available on your terminal, the
status line is inverted anyway; you will only see this problem on terminals
that have termcap codes for italics.
that have |terminfo| capabilities for italics.
==============================================================================
3. Opening and closing a window *opening-window* *E36*

View File

@ -11,13 +11,16 @@ let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo&vim
let b:undo_ftplugin = "setl fo< tw< cole< cocu<"
let b:undo_ftplugin = "setl fo< tw< cole< cocu< keywordprg<"
setlocal formatoptions+=tcroql textwidth=78
if has("conceal")
setlocal cole=2 cocu=nc
endif
" Prefer Vim help instead of manpages.
setlocal keywordprg=:help
if !exists('g:no_plugin_maps')
function! s:show_toc() abort
let bufname = bufname('%')

View File

@ -14,7 +14,7 @@ let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo-=C
let b:undo_ftplugin = "setl fo< isk< com< tw< commentstring<"
let b:undo_ftplugin = "setl fo< isk< com< tw< commentstring< keywordprg<"
\ . "| unlet! b:match_ignorecase b:match_words b:match_skip"
" Set 'formatoptions' to break comment lines but not other lines,
@ -36,6 +36,9 @@ endif
" Comments start with a double quote
setlocal commentstring=\"%s
" Prefer Vim help instead of manpages.
setlocal keywordprg=:help
" Move around functions.
nnoremap <silent><buffer> [[ m':call search('^\s*fu\%[nction]\>', "bW")<CR>
vnoremap <silent><buffer> [[ m':<C-U>exe "normal! gv"<Bar>call search('^\s*fu\%[nction]\>', "bW")<CR>

View File

@ -21,7 +21,7 @@ syn keyword vimTodo contained COMBAK FIXME TODO XXX
syn cluster vimCommentGroup contains=vimTodo,@Spell
" Special and plugin vim commands {{{2
syn match vimCommand contained "\<z[-+^.=]\="
syn match vimCommand contained "\<z[-+^.=]\=\>"
syn keyword vimOnlyCommand contained fix[del] op[en] sh[ell] P[rint]
syn keyword vimStdPlugin contained DiffOrig Man N[ext] S TOhtml XMLent XMLns

View File

@ -22,7 +22,7 @@ UNIDIR=${1:-$UNIDIR_DEFAULT}
DOWNLOAD_URL_BASE=${2:-$DOWNLOAD_URL_BASE_DEFAULT}
for filename in $data_files ; do
curl -o "$UNIDIR/$filename" "$DOWNLOAD_URL_BASE/UNIDATA/$filename"
curl -L -o "$UNIDIR/$filename" "$DOWNLOAD_URL_BASE/UNIDATA/$filename"
(
cd "$UNIDIR"
git add $filename
@ -30,7 +30,7 @@ for filename in $data_files ; do
done
for filename in $emoji_files ; do
curl -o "$UNIDIR/$filename" "$DOWNLOAD_URL_BASE/emoji/3.0/$filename"
curl -L -o "$UNIDIR/$filename" "$DOWNLOAD_URL_BASE/emoji/latest/$filename"
(
cd "$UNIDIR"
git add $filename

View File

@ -19,8 +19,11 @@ get_jobs_num() {
help() {
echo 'Usage:'
echo ' pvscheck.sh [--pvs URL] [--deps] [target-directory [branch]]'
echo ' pvscheck.sh [--pvs URL] [--recheck|--only-analyse] [target-directory]'
echo ' pvscheck.sh [--pvs URL] [--deps] [--environment-cc]'
echo ' [target-directory [branch]]'
echo ' pvscheck.sh [--pvs URL] [--recheck] [--environment-cc]'
echo ' [target-directory]'
echo ' pvscheck.sh [--pvs URL] --only-analyse [target-directory]'
echo ' pvscheck.sh [--pvs URL] --pvs-install {target-directory}'
echo ' pvscheck.sh --patch [--only-build]'
echo
@ -35,6 +38,9 @@ help() {
echo ' Without this it assumes all dependencies are already'
echo ' installed.'
echo
echo ' --environment-cc: (for regular run and --recheck) Do not export'
echo ' CC=clang. Build is still run with CFLAGS=-O0.'
echo
echo ' --only-build: (for --patch) Only patch files in ./build directory.'
echo
echo ' --pvs-install: Only install PVS-studio to the specified location.'
@ -270,8 +276,11 @@ install_pvs() {(
create_compile_commands() {(
local tgt="$1" ; shift
local deps="$1" ; shift
local environment_cc="$1" ; shift
export CC=clang
if test -z "$environment_cc" ; then
export CC=clang
fi
export CFLAGS=' -O0 '
if test -z "$deps" ; then
@ -356,19 +365,21 @@ do_check() {
local branch="$1" ; shift
local pvs_url="$1" ; shift
local deps="$1" ; shift
local environment_cc="$1" ; shift
git clone --branch="$branch" . "$tgt"
install_pvs "$tgt" "$pvs_url"
do_recheck "$tgt" "$deps"
do_recheck "$tgt" "$deps" "$environment_cc"
}
do_recheck() {
local tgt="$1" ; shift
local deps="$1" ; shift
local environment_cc="$1" ; shift
create_compile_commands "$tgt" "$deps"
create_compile_commands "$tgt" "$deps" "$environment_cc"
do_analysis "$tgt"
}
@ -408,6 +419,7 @@ main() {
only-analyse store_const \
pvs-install store_const \
deps store_const \
environment-cc store_const \
-- \
'modify realdir tgt "$PWD/../neovim-pvs"' \
'store branch master' \
@ -426,11 +438,11 @@ main() {
elif test -n "$pvs_install" ; then
install_pvs "$tgt" "$pvs_url"
elif test -n "$recheck" ; then
do_recheck "$tgt" "$deps"
do_recheck "$tgt" "$deps" "$environment_cc"
elif test -n "$only_analyse" ; then
do_analysis "$tgt"
else
do_check "$tgt" "$branch" "$pvs_url" "$deps"
do_check "$tgt" "$branch" "$pvs_url" "$deps" "$environment_cc"
fi
}

View File

@ -310,7 +310,7 @@ list_vim_patches() {
# Get missing Vim commits
local vim_commits
vim_commits="$(cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v7.4.1979..HEAD)"
vim_commits="$(cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD)"
local vim_commit
for vim_commit in ${vim_commits}; do
@ -320,6 +320,7 @@ list_vim_patches() {
vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)" || true
if [[ -n "${vim_tag}" ]]; then
local patch_number="${vim_tag:5}" # Remove prefix like "v7.4."
patch_number="$(echo ${patch_number} | sed 's/^0*//g')" # Remove prefix "0"
# Tagged Vim patch, check version.c:
is_missing="$(sed -n '/static const int included_patches/,/}/p' "${NVIM_SOURCE_DIR}/src/nvim/version.c" |
grep -x -e "[[:space:]]*//[[:space:]]${patch_number} NA.*" -e "[[:space:]]*${patch_number}," >/dev/null && echo "false" || echo "true")"

View File

@ -141,7 +141,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
if (di == NULL) {
api_set_error(err, kErrorTypeValidation, "Key not found");
api_set_error(err, kErrorTypeValidation, "Key '%s' not found", key.data);
return (Object)OBJECT_INIT;
}

View File

@ -136,9 +136,13 @@ Integer nvim_input(String keys)
return (Integer)input_enqueue(keys);
}
/// Replaces terminal codes and key codes (<CR>, <Esc>, ...) in a string with
/// Replaces terminal codes and |keycodes| (<CR>, <Esc>, ...) in a string with
/// the internal representation.
///
/// @param str String to be converted.
/// @param from_part Legacy Vim parameter. Usually true.
/// @param do_lt Also translate <lt>. Ignored if `special` is false.
/// @param special Replace |keycodes|, e.g. <CR> becomes a "\n" char.
/// @see replace_termcodes
/// @see cpoptions
String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
@ -151,12 +155,6 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
}
char *ptr = NULL;
// Set 'cpoptions' the way we want it.
// FLAG_CPO_BSLASH set - backslashes are *not* treated specially
// FLAG_CPO_KEYCODE set - keycodes are *not* reverse-engineered
// FLAG_CPO_SPECI unset - <Key> sequences *are* interpreted
// The third from end parameter of replace_termcodes() is true so that the
// <lt> sequence is recognised - needed for a real backslash.
replace_termcodes((char_u *)str.data, str.size, (char_u **)&ptr,
from_part, do_lt, special, CPO_TO_CPO_FLAGS);
return cstr_as_string(ptr);
@ -300,7 +298,7 @@ ArrayOf(String) nvim_list_runtime_paths(void)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
uint8_t *rtp = p_rtp;
char_u *rtp = p_rtp;
if (*rtp == NUL) {
// No paths
@ -314,13 +312,14 @@ ArrayOf(String) nvim_list_runtime_paths(void)
}
rtp++;
}
rv.size++;
// Allocate memory for the copies
rv.items = xmalloc(sizeof(Object) * rv.size);
rv.items = xmalloc(sizeof(*rv.items) * rv.size);
// Reset the position
rtp = p_rtp;
// Start copying
for (size_t i = 0; i < rv.size && *rtp != NUL; i++) {
for (size_t i = 0; i < rv.size; i++) {
rv.items[i].type = kObjectTypeString;
rv.items[i].data.string.data = xmalloc(MAXPATHL);
// Copy the path from 'runtimepath' to rv.items[i]
@ -709,7 +708,7 @@ void nvim_unsubscribe(uint64_t channel_id, String event)
Integer nvim_get_color_by_name(String name)
FUNC_API_SINCE(1)
{
return name_to_color((uint8_t *)name.data);
return name_to_color((char_u *)name.data);
}
Dictionary nvim_get_color_map(void)
@ -871,7 +870,7 @@ static void write_msg(String message, bool to_err)
#define PUSH_CHAR(i, pos, line_buf, msg) \
if (message.data[i] == NL || pos == LINE_BUFFER_SIZE - 1) { \
line_buf[pos] = NUL; \
msg((uint8_t *)line_buf); \
msg((char_u *)line_buf); \
pos = 0; \
continue; \
} \

View File

@ -91,6 +91,57 @@ static char *e_auabort = N_("E855: Autocommands caused command to abort");
// Number of times free_buffer() was called.
static int buf_free_count = 0;
// Read data from buffer for retrying.
static int
read_buffer(
int read_stdin, // read file from stdin, otherwise fifo
exarg_T *eap, // for forced 'ff' and 'fenc' or NULL
int flags) // extra flags for readfile()
{
int retval = OK;
linenr_T line_count;
//
// Read from the buffer which the text is already filled in and append at
// the end. This makes it possible to retry when 'fileformat' or
// 'fileencoding' was guessed wrong.
//
line_count = curbuf->b_ml.ml_line_count;
retval = readfile(
read_stdin ? NULL : curbuf->b_ffname,
read_stdin ? NULL : curbuf->b_fname,
(linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap,
flags | READ_BUFFER);
if (retval == OK) {
// Delete the binary lines.
while (--line_count >= 0) {
ml_delete((linenr_T)1, false);
}
} else {
// Delete the converted lines.
while (curbuf->b_ml.ml_line_count > line_count) {
ml_delete(line_count, false);
}
}
// Put the cursor on the first line.
curwin->w_cursor.lnum = 1;
curwin->w_cursor.col = 0;
if (read_stdin) {
// Set or reset 'modified' before executing autocommands, so that
// it can be changed there.
if (!readonlymode && !bufempty()) {
changed();
} else if (retval != FAIL) {
unchanged(curbuf, false);
}
apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, false,
curbuf, &retval);
}
return retval;
}
/*
* Open current buffer, that is: open the memfile and read the file into
* memory.
@ -106,6 +157,7 @@ open_buffer (
int retval = OK;
bufref_T old_curbuf;
long old_tw = curbuf->b_p_tw;
int read_fifo = false;
/*
* The 'readonly' flag is only set when BF_NEVERLOADED is being reset.
@ -156,13 +208,45 @@ open_buffer (
if (curbuf->b_ffname != NULL) {
int old_msg_silent = msg_silent;
#ifdef UNIX
int save_bin = curbuf->b_p_bin;
int perm;
perm = os_getperm((const char *)curbuf->b_ffname);
if (perm >= 0 && (0
# ifdef S_ISFIFO
|| S_ISFIFO(perm)
# endif
# ifdef S_ISSOCK
|| S_ISSOCK(perm)
# endif
# ifdef OPEN_CHR_FILES
|| (S_ISCHR(perm)
&& is_dev_fd_file(curbuf->b_ffname))
# endif
)
) {
read_fifo = true;
}
if (read_fifo) {
curbuf->b_p_bin = true;
}
#endif
if (shortmess(SHM_FILEINFO)) {
msg_silent = 1;
}
retval = readfile(curbuf->b_ffname, curbuf->b_fname,
(linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap,
flags | READ_NEW);
flags | READ_NEW | (read_fifo ? READ_FIFO : 0));
#ifdef UNIX
if (read_fifo) {
curbuf->b_p_bin = save_bin;
if (retval == OK) {
retval = read_buffer(false, eap, flags);
}
}
#endif
msg_silent = old_msg_silent;
// Help buffer is filtered.
@ -171,7 +255,6 @@ open_buffer (
}
} else if (read_stdin) {
int save_bin = curbuf->b_p_bin;
linenr_T line_count;
/*
* First read the text in binary mode into the buffer.
@ -185,41 +268,13 @@ open_buffer (
flags | (READ_NEW + READ_STDIN));
curbuf->b_p_bin = save_bin;
if (retval == OK) {
line_count = curbuf->b_ml.ml_line_count;
retval = readfile(NULL, NULL, (linenr_T)line_count,
(linenr_T)0, (linenr_T)MAXLNUM, eap,
flags | READ_BUFFER);
if (retval == OK) {
/* Delete the binary lines. */
while (--line_count >= 0)
ml_delete((linenr_T)1, FALSE);
} else {
/* Delete the converted lines. */
while (curbuf->b_ml.ml_line_count > line_count)
ml_delete(line_count, FALSE);
}
/* Put the cursor on the first line. */
curwin->w_cursor.lnum = 1;
curwin->w_cursor.col = 0;
// Set or reset 'modified' before executing autocommands, so that
// it can be changed there.
if (!readonlymode && !bufempty()) {
changed();
} else if (retval == OK) {
unchanged(curbuf, false);
}
if (retval == OK) {
apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, false,
curbuf, &retval);
}
retval = read_buffer(true, eap, flags);
}
}
/* if first time loading this buffer, init b_chartab[] */
if (curbuf->b_flags & BF_NEVERLOADED) {
(void)buf_init_chartab(curbuf, FALSE);
(void)buf_init_chartab(curbuf, false);
parse_cino(curbuf);
}
@ -234,7 +289,7 @@ open_buffer (
|| modified_was_set // ":set modified" used in autocmd
|| (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) {
changed();
} else if (retval == OK && !read_stdin) {
} else if (retval != FAIL && !read_stdin && !read_fifo) {
unchanged(curbuf, false);
}
save_file_ff(curbuf); // keep this fileformat
@ -416,8 +471,8 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
return;
}
/* When the buffer becomes hidden, but is not unloaded, trigger
* BufHidden */
// When the buffer becomes hidden, but is not unloaded, trigger
// BufHidden
if (!unload_buf) {
buf->b_locked++;
if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, false,

View File

@ -29,6 +29,6 @@ typedef struct {
} BufhlLineInfo;
#define BUFHL_CMP(a, b) ((int)(((a)->line - (b)->line)))
KBTREE_INIT(bufhl, BufhlLine *, BUFHL_CMP, 10)
KBTREE_INIT(bufhl, BufhlLine *, BUFHL_CMP, 10) // -V512
typedef kbtree_t(bufhl) BufhlInfo;
#endif // NVIM_BUFHL_DEFS_H

View File

@ -981,10 +981,8 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he
mb_ptr_adv(s);
c = *s;
if (!((c != NUL)
&& (vim_isbreak(c)
|| (!vim_isbreak(c)
&& ((col2 == col) || !vim_isbreak(*ps)))))) {
if (!(c != NUL
&& (vim_isbreak(c) || col2 == col || !vim_isbreak(*ps)))) {
break;
}

View File

@ -462,7 +462,7 @@ static void insert_enter(InsertState *s)
// Always update o_lnum, so that a "CTRL-O ." that adds a line
// still puts the cursor back after the inserted text.
if (ins_at_eol && gchar_cursor() == NUL) {
if (ins_at_eol) {
o_lnum = curwin->w_cursor.lnum;
}

View File

@ -12119,15 +12119,17 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
mode = get_map_mode((char_u **)&which, 0);
keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, false,
keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, true,
CPO_TO_CPO_FLAGS);
rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local);
xfree(keys_buf);
if (!get_dict) {
/* Return a string. */
if (rhs != NULL)
rettv->vval.v_string = str2special_save(rhs, FALSE);
// Return a string.
if (rhs != NULL) {
rettv->vval.v_string = (char_u *)str2special_save(
(const char *)rhs, false, false);
}
} else {
tv_dict_alloc_ret(rettv);
@ -12162,7 +12164,8 @@ void mapblock_fill_dict(dict_T *const dict,
bool compatible)
FUNC_ATTR_NONNULL_ALL
{
char_u *lhs = str2special_save(mp->m_keys, true);
char *const lhs = str2special_save((const char *)mp->m_keys,
compatible, !compatible);
char *const mapmode = map_mode_to_chars(mp->m_mode);
varnumber_T noremap_value;
@ -12176,18 +12179,21 @@ void mapblock_fill_dict(dict_T *const dict,
noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap;
}
tv_dict_add_str(dict, S_LEN("lhs"), (const char *)lhs);
tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
if (compatible) {
tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
} else {
tv_dict_add_allocated_str(dict, S_LEN("rhs"),
str2special_save((const char *)mp->m_str, false,
true));
}
tv_dict_add_allocated_str(dict, S_LEN("lhs"), lhs);
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ID);
tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_value);
tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0);
tv_dict_add_str(dict, S_LEN("mode"), mapmode);
xfree(lhs);
xfree(mapmode);
tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode);
}
/*
@ -12453,7 +12459,7 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
if (id >= 1 && id <= 3) {
EMSGN("E798: ID is reserved for \":match\": %" PRId64, id);
EMSGN(_("E798: ID is reserved for \":match\": %" PRId64), id);
return;
}
@ -12510,7 +12516,7 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// id == 3 is ok because matchaddpos() is supposed to substitute :3match
if (id == 1 || id == 2) {
EMSGN("E798: ID is reserved for \"match\": %" PRId64, id);
EMSGN(_("E798: ID is reserved for \"match\": %" PRId64), id);
return;
}

View File

@ -1386,12 +1386,33 @@ int tv_dict_add_str(dict_T *const d,
const char *const key, const size_t key_len,
const char *const val)
FUNC_ATTR_NONNULL_ALL
{
return tv_dict_add_allocated_str(d, key, key_len, xstrdup(val));
}
/// Add a string entry to dictionary
///
/// Unlike tv_dict_add_str() saves val to the new dictionary item in place of
/// creating a new copy.
///
/// @warning String will be freed even in case addition fails.
///
/// @param[out] d Dictionary to add entry to.
/// @param[in] key Key to add.
/// @param[in] key_len Key length.
/// @param[in] val String to add.
///
/// @return OK in case of success, FAIL when key already exists.
int tv_dict_add_allocated_str(dict_T *const d,
const char *const key, const size_t key_len,
char *const val)
FUNC_ATTR_NONNULL_ALL
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
item->di_tv.v_lock = VAR_UNLOCKED;
item->di_tv.v_type = VAR_STRING;
item->di_tv.vval.v_string = (char_u *)xstrdup(val);
item->di_tv.vval.v_string = (char_u *)val;
if (tv_dict_add(d, item) == FAIL) {
tv_dict_item_free(item);
return FAIL;

View File

@ -21,9 +21,9 @@
# include "event/process.c.generated.h"
#endif
// Time (ns) for a process to exit cleanly before we send TERM/KILL.
#define TERM_TIMEOUT 1000000000
#define KILL_TIMEOUT (TERM_TIMEOUT * 2)
// Time for a process to exit cleanly before we send KILL.
// For pty processes SIGTERM is sent first (in case SIGHUP was not enough).
#define KILL_TIMEOUT_MS 2000
#define CLOSE_PROC_STREAM(proc, stream) \
do { \
@ -125,8 +125,6 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
// Close handles to process without killing it.
CREATE_EVENT(loop->events, process_close_handles, 1, proc);
} else {
uv_kill(proc->pid, SIGTERM);
proc->term_sent = true;
process_stop(proc);
}
}
@ -238,6 +236,8 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
// stdout/stderr, they will be closed when it exits(possibly due to being
// terminated after a timeout)
process_close_in(proc);
ILOG("Sending SIGTERM to pid %d", proc->pid);
uv_kill(proc->pid, SIGTERM);
break;
case kProcessTypePty:
// close all streams for pty processes to send SIGHUP to the process
@ -251,9 +251,10 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
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);
// will periodically check if a signal should be send to the job.
ILOG("Starting job kill timer");
uv_timer_start(&loop->children_kill_timer, children_kill_cb,
KILL_TIMEOUT_MS, KILL_TIMEOUT_MS);
}
}
@ -269,15 +270,15 @@ static void children_kill_cb(uv_timer_t *handle)
if (!proc->stopped_time) {
continue;
}
uint64_t elapsed = now - proc->stopped_time;
uint64_t elapsed = (now - proc->stopped_time) / 1000000 + 1;
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);
if (elapsed >= KILL_TIMEOUT_MS) {
int sig = proc->type == kProcessTypePty && elapsed < KILL_TIMEOUT_MS * 2
? SIGTERM
: SIGKILL;
ILOG("Sending %s to pid %d", sig == SIGTERM ? "SIGTERM" : "SIGKILL",
proc->pid);
uv_kill(proc->pid, sig);
}
}
}

View File

@ -26,7 +26,7 @@ struct process {
Stream *in, *out, *err;
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
bool closed, term_sent, detach;
bool closed, detach;
MultiQueue *events;
};
@ -48,7 +48,6 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
.err = NULL,
.cb = NULL,
.closed = false,
.term_sent = false,
.internal_close_cb = NULL,
.internal_exit_cb = NULL,
.detach = false

View File

@ -66,6 +66,7 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher,
watcher->uv.tcp.addrinfo = request.addrinfo;
uv_tcp_init(&loop->uv, &watcher->uv.tcp.handle);
uv_tcp_nodelay(&watcher->uv.tcp.handle, true);
watcher->stream = STRUCT_CAST(uv_stream_t, &watcher->uv.tcp.handle);
} else {
uv_pipe_init(&loop->uv, &watcher->uv.pipe.handle, 0);
@ -104,9 +105,10 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
// contain 0 in this case, unless uv_tcp_getsockname() is used first.
uv_tcp_getsockname(&watcher->uv.tcp.handle, (struct sockaddr *)&sas,
&(int){ sizeof(sas) });
uint16_t port = (uint16_t)((sas.ss_family == AF_INET)
? ((struct sockaddr_in *)&sas)->sin_port
: ((struct sockaddr_in6 *)&sas)->sin6_port);
uint16_t port = (uint16_t)(
(sas.ss_family == AF_INET)
? (STRUCT_CAST(struct sockaddr_in, &sas))->sin_port
: (STRUCT_CAST(struct sockaddr_in6, &sas))->sin6_port);
// v:servername uses the string from watcher->addr
size_t len = strlen(watcher->addr);
snprintf(watcher->addr+len, sizeof(watcher->addr)-len, ":%" PRIu16,
@ -146,6 +148,7 @@ int socket_watcher_accept(SocketWatcher *watcher, Stream *stream)
if (watcher->stream->type == UV_TCP) {
client = STRUCT_CAST(uv_stream_t, &stream->uv.tcp);
uv_tcp_init(watcher->uv.tcp.handle.loop, (uv_tcp_t *)client);
uv_tcp_nodelay((uv_tcp_t *)client, true);
} else {
client = STRUCT_CAST(uv_stream_t, &stream->uv.pipe);
uv_pipe_init(watcher->uv.pipe.handle.loop, (uv_pipe_t *)client, 0);
@ -237,6 +240,7 @@ bool socket_connect(Loop *loop, Stream *stream,
tcp_retry:
uv_tcp_init(&loop->uv, tcp);
uv_tcp_nodelay(tcp, true);
uv_tcp_connect(&req, tcp, addrinfo->ai_addr, connect_cb);
uv_stream = (uv_stream_t *)tcp;
@ -244,7 +248,7 @@ tcp_retry:
uv_pipe_t *pipe = &stream->uv.pipe;
uv_pipe_init(&loop->uv, pipe, 0);
uv_pipe_connect(&req, pipe, address, connect_cb);
uv_stream = (uv_stream_t *)pipe;
uv_stream = STRUCT_CAST(uv_stream_t, pipe);
}
status = 1;
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1);

View File

@ -3332,7 +3332,8 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
// Check for a match on each line.
linenr_T line2 = eap->line2;
for (linenr_T lnum = eap->line1;
lnum <= line2 && !(got_quit || aborting());
lnum <= line2 && !(got_quit || aborting())
&& (!preview || matched_lines.size <= (size_t)p_cwh);
lnum++) {
long nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL);
@ -5022,8 +5023,9 @@ static void helptags_one(char_u *dir, char_u *ext, char_u *tagfname,
if (gen_expand_wildcards(1, buff_list, &filecount, &files,
EW_FILE|EW_SILENT) == FAIL
|| filecount == 0) {
if (!got_int)
EMSG2("E151: No match: %s", NameBuff);
if (!got_int) {
EMSG2(_("E151: No match: %s"), NameBuff);
}
return;
}
@ -5222,7 +5224,7 @@ static void do_helptags(char_u *dirname, bool add_help_tags)
if (gen_expand_wildcards(1, buff_list, &filecount, &files,
EW_FILE|EW_SILENT) == FAIL
|| filecount == 0) {
EMSG2("E151: No match: %s", NameBuff);
EMSG2(_("E151: No match: %s"), NameBuff);
xfree(dirname);
return;
}

View File

@ -4747,7 +4747,7 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
char_u *rep_buf = NULL;
garray_T *gap;
replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, false,
replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, true,
CPO_TO_CPO_FLAGS);
if (rep_buf == NULL) {
/* Can't replace termcodes - try using the string as is */

View File

@ -106,12 +106,20 @@ typedef struct command_line_state {
char_u *lookfor; // string to match
int hiscnt; // current history line in use
int histype; // history type to be used
pos_T old_cursor;
pos_T search_start; // where 'incsearch' starts searching
pos_T save_cursor;
colnr_T old_curswant;
colnr_T init_curswant;
colnr_T old_leftcol;
colnr_T init_leftcol;
linenr_T old_topline;
linenr_T init_topline;
int old_topfill;
int init_topfill;
linenr_T old_botline;
linenr_T init_botline;
pos_T match_start;
pos_T match_end;
int did_incsearch;
int incsearch_postponed;
int did_wild_list; // did wild_list() recently
@ -191,6 +199,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
s->save_State = State;
s->save_p_icm = vim_strsave(p_icm);
s->ignore_drag_release = true;
s->match_start = curwin->w_cursor;
s->init_curswant = curwin->w_curswant;
s->init_leftcol = curwin->w_leftcol;
s->init_topline = curwin->w_topline;
s->init_topfill = curwin->w_topfill;
s->init_botline = curwin->w_botline;
if (s->firstc == -1) {
s->firstc = NUL;
@ -204,7 +218,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
ccline.prompt_id = last_prompt_id++;
ccline.overstrike = false; // always start in insert mode
s->old_cursor = curwin->w_cursor; // needs to be restored later
clearpos(&s->match_end);
s->save_cursor = curwin->w_cursor; // may be restored later
s->search_start = curwin->w_cursor;
s->old_curswant = curwin->w_curswant;
s->old_leftcol = curwin->w_leftcol;
s->old_topline = curwin->w_topline;
@ -307,7 +323,16 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
ccline.xpc = NULL;
if (s->did_incsearch) {
curwin->w_cursor = s->old_cursor;
if (s->gotesc) {
curwin->w_cursor = s->save_cursor;
} else {
if (!equalpos(s->save_cursor, s->search_start)) {
// put the '" mark at the original position
curwin->w_cursor = s->save_cursor;
setpcmark();
}
curwin->w_cursor = s->search_start; // -V519
}
curwin->w_curswant = s->old_curswant;
curwin->w_leftcol = s->old_leftcol;
curwin->w_topline = s->old_topline;
@ -882,6 +907,118 @@ static int command_line_execute(VimState *state, int key)
return command_line_handle_key(s);
}
static void command_line_next_incsearch(CommandLineState *s, bool next_match)
{
ui_busy_start();
ui_flush();
pos_T t;
int search_flags = SEARCH_KEEP + SEARCH_NOOF + SEARCH_PEEK;
if (next_match) {
t = s->match_end;
search_flags += SEARCH_COL;
} else {
t = s->match_start;
}
emsg_off++;
s->i = searchit(curwin, curbuf, &t,
next_match ? FORWARD : BACKWARD,
ccline.cmdbuff, s->count, search_flags,
RE_SEARCH, 0, NULL);
emsg_off--;
ui_busy_stop();
if (s->i) {
s->search_start = s->match_start;
s->match_end = t;
s->match_start = t;
if (!next_match && s->firstc == '/') {
// move just before the current match, so that
// when nv_search finishes the cursor will be
// put back on the match
s->search_start = t;
(void)decl(&s->search_start);
}
if (lt(t, s->search_start) && next_match) {
// wrap around
s->search_start = t;
if (s->firstc == '?') {
(void)incl(&s->search_start);
} else {
(void)decl(&s->search_start);
}
}
set_search_match(&s->match_end);
curwin->w_cursor = s->match_start;
changed_cline_bef_curs();
update_topline();
validate_cursor();
highlight_match = true;
s->old_curswant = curwin->w_curswant;
s->old_leftcol = curwin->w_leftcol;
s->old_topline = curwin->w_topline;
s->old_topfill = curwin->w_topfill;
s->old_botline = curwin->w_botline;
update_screen(NOT_VALID);
redrawcmdline();
} else {
vim_beep(BO_ERROR);
}
return;
}
static void command_line_next_histidx(CommandLineState *s, bool next_match)
{
s->j = (int)STRLEN(s->lookfor);
for (;; ) {
// one step backwards
if (!next_match) {
if (s->hiscnt == hislen) {
// first time
s->hiscnt = hisidx[s->histype];
} else if (s->hiscnt == 0 && hisidx[s->histype] != hislen - 1) {
s->hiscnt = hislen - 1;
} else if (s->hiscnt != hisidx[s->histype] + 1) {
s->hiscnt--;
} else {
// at top of list
s->hiscnt = s->i;
break;
}
} else { // one step forwards
// on last entry, clear the line
if (s->hiscnt == hisidx[s->histype]) {
s->hiscnt = hislen;
break;
}
// not on a history line, nothing to do
if (s->hiscnt == hislen) {
break;
}
if (s->hiscnt == hislen - 1) {
// wrap around
s->hiscnt = 0;
} else {
s->hiscnt++;
}
}
if (s->hiscnt < 0 || history[s->histype][s->hiscnt].hisstr == NULL) {
s->hiscnt = s->i;
break;
}
if ((s->c != K_UP && s->c != K_DOWN)
|| s->hiscnt == s->i
|| STRNCMP(history[s->histype][s->hiscnt].hisstr,
s->lookfor, (size_t)s->j) == 0) {
break;
}
}
}
static int command_line_handle_key(CommandLineState *s)
{
// Big switch for a typed command line character.
@ -954,6 +1091,16 @@ static int command_line_handle_key(CommandLineState *s)
// Truncate at the end, required for multi-byte chars.
ccline.cmdbuff[ccline.cmdlen] = NUL;
if (ccline.cmdlen == 0) {
s->search_start = s->save_cursor;
// save view settings, so that the screen won't be restored at the
// wrong position
s->old_curswant = s->init_curswant;
s->old_leftcol = s->init_leftcol;
s->old_topline = s->init_topline;
s->old_topfill = s->init_topfill;
s->old_botline = s->init_botline;
}
redrawcmd();
} else if (ccline.cmdlen == 0 && s->c != Ctrl_W
&& ccline.cmdprompt == NULL && s->indent == 0) {
@ -972,6 +1119,7 @@ static int command_line_handle_key(CommandLineState *s)
}
msg_putchar(' '); // delete ':'
}
s->search_start = s->save_cursor;
redraw_cmdline = true;
return 0; // back to cmd mode
}
@ -1026,6 +1174,9 @@ static int command_line_handle_key(CommandLineState *s)
// Truncate at the end, required for multi-byte chars.
ccline.cmdbuff[ccline.cmdlen] = NUL;
if (ccline.cmdlen == 0) {
s->search_start = s->save_cursor;
}
redrawcmd();
return command_line_changed(s);
@ -1258,24 +1409,27 @@ static int command_line_handle_key(CommandLineState *s)
case Ctrl_L:
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
// Add a character from under the cursor for 'incsearch'
if (s->did_incsearch && !equalpos(curwin->w_cursor, s->old_cursor)) {
s->c = gchar_cursor();
// If 'ignorecase' and 'smartcase' are set and the
// command line has no uppercase characters, convert
// the character to lowercase
if (p_ic && p_scs && !pat_has_uppercase(ccline.cmdbuff)) {
s->c = mb_tolower(s->c);
}
if (s->c != NUL) {
if (s->c == s->firstc
|| vim_strchr((char_u *)(p_magic ? "\\^$.*[" : "\\^$"), s->c)
!= NULL) {
// put a backslash before special characters
stuffcharReadbuff(s->c);
s->c = '\\';
if (s->did_incsearch) {
curwin->w_cursor = s->match_end;
if (!equalpos(curwin->w_cursor, s->search_start)) {
s->c = gchar_cursor();
// If 'ignorecase' and 'smartcase' are set and the
// command line has no uppercase characters, convert
// the character to lowercase
if (p_ic && p_scs
&& !pat_has_uppercase(ccline.cmdbuff)) {
s->c = mb_tolower(s->c);
}
if (s->c != NUL) {
if (s->c == s->firstc
|| vim_strchr((char_u *)(p_magic ? "\\^$.*[" : "\\^$"), s->c)
!= NULL) {
// put a backslash before special characters
stuffcharReadbuff(s->c);
s->c = '\\';
}
break;
}
break;
}
}
return command_line_not_changed(s);
@ -1294,7 +1448,7 @@ static int command_line_handle_key(CommandLineState *s)
0, s->firstc != '@') == FAIL) {
break;
}
return command_line_changed(s);
return command_line_not_changed(s);
}
// fallthrough
@ -1319,55 +1473,9 @@ static int command_line_handle_key(CommandLineState *s)
s->lookfor[ccline.cmdpos] = NUL;
}
s->j = (int)STRLEN(s->lookfor);
for (;; ) {
// one step backwards
if (s->c == K_UP|| s->c == K_S_UP || s->c == Ctrl_P
|| s->c == K_PAGEUP || s->c == K_KPAGEUP) {
if (s->hiscnt == hislen) {
// first time
s->hiscnt = hisidx[s->histype];
} else if (s->hiscnt == 0 && hisidx[s->histype] != hislen - 1) {
s->hiscnt = hislen - 1;
} else if (s->hiscnt != hisidx[s->histype] + 1) {
--s->hiscnt;
} else {
// at top of list
s->hiscnt = s->i;
break;
}
} else { // one step forwards
// on last entry, clear the line
if (s->hiscnt == hisidx[s->histype]) {
s->hiscnt = hislen;
break;
}
// not on a history line, nothing to do
if (s->hiscnt == hislen) {
break;
}
if (s->hiscnt == hislen - 1) {
// wrap around
s->hiscnt = 0;
} else {
++s->hiscnt;
}
}
if (s->hiscnt < 0 || history[s->histype][s->hiscnt].hisstr == NULL) {
s->hiscnt = s->i;
break;
}
if ((s->c != K_UP && s->c != K_DOWN)
|| s->hiscnt == s->i
|| STRNCMP(history[s->histype][s->hiscnt].hisstr,
s->lookfor, (size_t)s->j) == 0) {
break;
}
}
bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N
|| s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN);
command_line_next_histidx(s, next_match);
if (s->hiscnt != s->i) {
// jumped to other entry
@ -1435,6 +1543,17 @@ static int command_line_handle_key(CommandLineState *s)
beep_flush();
return command_line_not_changed(s);
case Ctrl_G: // next match
case Ctrl_T: // previous match
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
if (char_avail()) {
return 1;
}
command_line_next_incsearch(s, s->c == Ctrl_G);
return command_line_not_changed(s);
}
break;
case Ctrl_V:
case Ctrl_Q:
s->ignore_drag_release = true;
@ -1549,7 +1668,7 @@ static int command_line_changed(CommandLineState *s)
return 1;
}
s->incsearch_postponed = false;
curwin->w_cursor = s->old_cursor; // start at old position
curwin->w_cursor = s->search_start; // start at old position
// If there is no command line, don't do anything
if (ccline.cmdlen == 0) {
@ -1594,16 +1713,11 @@ static int command_line_changed(CommandLineState *s)
if (s->i != 0) {
pos_T save_pos = curwin->w_cursor;
// First move cursor to end of match, then to the start. This
// moves the whole match onto the screen when 'nowrap' is set.
curwin->w_cursor.lnum += search_match_lines;
curwin->w_cursor.col = search_match_endcol;
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
coladvance((colnr_T)MAXCOL);
}
s->match_start = curwin->w_cursor;
set_search_match(&curwin->w_cursor);
validate_cursor();
end_pos = curwin->w_cursor;
s->match_end = end_pos;
curwin->w_cursor = save_pos;
} else {
end_pos = curwin->w_cursor; // shutup gcc 4
@ -1645,7 +1759,7 @@ static int command_line_changed(CommandLineState *s)
emsg_silent--; // Unblock error reporting
// Restore the window "view".
curwin->w_cursor = s->old_cursor;
curwin->w_cursor = s->save_cursor;
curwin->w_curswant = s->old_curswant;
curwin->w_leftcol = s->old_leftcol;
curwin->w_topline = s->old_topline;
@ -5793,3 +5907,15 @@ histentry_T *hist_get_array(const uint8_t history_type, int **const new_hisidx,
*new_hisnum = &(hisnum[history_type]);
return history[history_type];
}
static void set_search_match(pos_T *t)
{
// First move cursor to end of match, then to the start. This
// moves the whole match onto the screen when 'nowrap' is set.
t->lnum += search_match_lines;
t->col = search_match_endcol;
if (t->lnum > curbuf->b_ml.ml_line_count) {
t->lnum = curbuf->b_ml.ml_line_count;
coladvance((colnr_T)MAXCOL);
}
}

View File

@ -247,6 +247,7 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
* stdin)
* READ_DUMMY read into a dummy buffer (to check if file contents changed)
* READ_KEEP_UNDO don't clear undo info or read it from a file
* READ_FIFO read from fifo/socket instead of a file
*
* return FAIL for failure, NOTDONE for directory (failure), or OK
*/
@ -267,6 +268,7 @@ readfile (
int filtering = (flags & READ_FILTER);
int read_stdin = (flags & READ_STDIN);
int read_buffer = (flags & READ_BUFFER);
int read_fifo = (flags & READ_FIFO);
int set_options = newfile || read_buffer
|| (eap != NULL && eap->read_edit);
linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
@ -426,7 +428,7 @@ readfile (
}
}
if (!read_buffer && !read_stdin) {
if (!read_buffer && !read_stdin && !read_fifo) {
perm = os_getperm((const char *)fname);
#ifdef UNIX
// On Unix it is possible to read a directory, so we have to
@ -468,8 +470,8 @@ readfile (
if (check_readonly && !readonlymode)
curbuf->b_p_ro = FALSE;
if (newfile && !read_stdin && !read_buffer) {
/* Remember time of file. */
if (newfile && !read_stdin && !read_buffer && !read_fifo) {
// Remember time of file.
FileInfo file_info;
if (os_fileinfo((char *)fname, &file_info)) {
buf_store_file_info(curbuf, &file_info);
@ -895,6 +897,7 @@ retry:
* and we can't do it internally or with iconv().
*/
if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
&& !read_fifo
# ifdef USE_ICONV
&& iconv_fd == (iconv_t)-1
# endif
@ -935,7 +938,7 @@ retry:
/* Set "can_retry" when it's possible to rewind the file and try with
* another "fenc" value. It's FALSE when no other "fenc" to try, reading
* stdin or fixed at a specific encoding. */
can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc);
can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc && !read_fifo);
if (!skip_read) {
linerest = 0;
@ -947,6 +950,7 @@ retry:
&& curbuf->b_ffname != NULL
&& curbuf->b_p_udf
&& !filtering
&& !read_fifo
&& !read_stdin
&& !read_buffer);
if (read_undo_file)
@ -1919,7 +1923,7 @@ failed:
u_read_undo(NULL, hash, fname);
}
if (!read_stdin && !read_buffer) {
if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL)) {
int m = msg_scroll;
int n = msg_scrolled;
@ -1937,7 +1941,7 @@ failed:
if (filtering) {
apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
false, curbuf, eap);
} else if (newfile) {
} else if (newfile || (read_buffer && sfname != NULL)) {
apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
false, curbuf, eap);
if (!au_did_filetype && *curbuf->b_p_ft != NUL) {
@ -1970,7 +1974,7 @@ failed:
/// Do not accept "/dev/fd/[012]", opening these may hang Vim.
///
/// @param fname file name to check
static bool is_dev_fd_file(char_u *fname)
bool is_dev_fd_file(char_u *fname)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
return STRNCMP(fname, "/dev/fd/", 8) == 0

View File

@ -4,13 +4,14 @@
#include "nvim/buffer_defs.h"
#include "nvim/os/os.h"
/* Values for readfile() flags */
#define READ_NEW 0x01 /* read a file into a new buffer */
#define READ_FILTER 0x02 /* read filter output */
#define READ_STDIN 0x04 /* read from stdin */
#define READ_BUFFER 0x08 /* read from curbuf (converting stdin) */
#define READ_DUMMY 0x10 /* reading into a dummy buffer */
#define READ_KEEP_UNDO 0x20 /* keep undo info*/
// Values for readfile() flags
#define READ_NEW 0x01 // read a file into a new buffer
#define READ_FILTER 0x02 // read filter output
#define READ_STDIN 0x04 // read from stdin
#define READ_BUFFER 0x08 // read from curbuf (converting stdin)
#define READ_DUMMY 0x10 // reading into a dummy buffer
#define READ_KEEP_UNDO 0x20 // keep undo info
#define READ_FIFO 0x40 // read from fifo or socket
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))

View File

@ -1806,7 +1806,7 @@ static int vgetorpeek(int advance)
* <M-a> and then changing 'encoding'. Beware
* that 0x80 is escaped. */
char_u *p1 = mp->m_keys;
char_u *p2 = mb_unescape(&p1);
char_u *p2 = (char_u *)mb_unescape((const char **)&p1);
if (has_mbyte && p2 != NULL && MB_BYTE2LEN(c1) > MB_PTR2LEN(p2))
mlen = 0;
@ -2537,7 +2537,6 @@ do_map (
bool unique = false;
bool nowait = false;
bool silent = false;
bool special = false;
bool expr = false;
int noremap;
char_u *orig_rhs;
@ -2583,12 +2582,9 @@ do_map (
continue;
}
/*
* Check for "<special>": accept special keys in <>
*/
// Ignore obsolete "<special>" modifier.
if (STRNCMP(keys, "<special>", 9) == 0) {
keys = skipwhite(keys + 9);
special = true;
continue;
}
@ -2657,7 +2653,7 @@ do_map (
// needs to be freed later (*keys_buf and *arg_buf).
// replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
if (haskey) {
keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, special,
keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, true,
CPO_TO_CPO_FLAGS);
}
orig_rhs = rhs;
@ -2665,7 +2661,7 @@ do_map (
if (STRICMP(rhs, "<nop>") == 0) { // "<Nop>" means nothing
rhs = (char_u *)"";
} else {
rhs = replace_termcodes(rhs, STRLEN(rhs), &arg_buf, false, true, special,
rhs = replace_termcodes(rhs, STRLEN(rhs), &arg_buf, false, true, true,
CPO_TO_CPO_FLAGS);
}
}
@ -3245,7 +3241,7 @@ bool map_to_exists(const char *const str, const char *const modechars,
char_u *buf;
char_u *const rhs = replace_termcodes((const char_u *)str, strlen(str), &buf,
false, true, false,
false, true, true,
CPO_TO_CPO_FLAGS);
#define MAPMODE(mode, modechars, chr, modeflags) \
@ -3999,12 +3995,10 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
return OK;
}
for (; *str != NUL; ++str) {
char_u *p;
/* Check for a multi-byte character, which may contain escaped
* K_SPECIAL and CSI bytes */
p = mb_unescape(&str);
for (; *str != NUL; str++) {
// Check for a multi-byte character, which may contain escaped
// K_SPECIAL and CSI bytes.
const char *p = mb_unescape((const char **)&str);
if (p != NULL) {
while (*p != NUL)
if (fputc(*p++, fd) < 0)
@ -4160,8 +4154,7 @@ void add_map(char_u *map, int mode)
}
// Translate an internal mapping/abbreviation representation into the
// corresponding external one recognized by :map/:abbrev commands;
// respects the current B/k/< settings of 'cpoption'.
// corresponding external one recognized by :map/:abbrev commands.
//
// This function is called when expanding mappings/abbreviations on the
// command-line, and for building the "Ambiguous mapping..." error message.
@ -4181,7 +4174,6 @@ static char_u * translate_mapping (
ga_init(&ga, 1, 40);
bool cpo_bslash = !(cpo_flags&FLAG_CPO_BSLASH);
bool cpo_special = !(cpo_flags&FLAG_CPO_SPECI);
for (; *str; ++str) {
int c = *str;
@ -4194,7 +4186,7 @@ static char_u * translate_mapping (
}
if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) {
if (expmap && cpo_special) {
if (expmap) {
ga_clear(&ga);
return NULL;
}
@ -4205,8 +4197,8 @@ static char_u * translate_mapping (
}
str += 2;
}
if (IS_SPECIAL(c) || modifiers) { /* special key */
if (expmap && cpo_special) {
if (IS_SPECIAL(c) || modifiers) { // special key
if (expmap) {
ga_clear(&ga);
return NULL;
}
@ -4216,7 +4208,7 @@ static char_u * translate_mapping (
}
if (c == ' ' || c == '\t' || c == Ctrl_J || c == Ctrl_V
|| (c == '<' && !cpo_special) || (c == '\\' && !cpo_bslash)) {
|| (c == '\\' && !cpo_bslash)) {
ga_append(&ga, cpo_bslash ? Ctrl_V : '\\');
}

View File

@ -756,9 +756,9 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag)
/// Replace any terminal code strings with the equivalent internal
/// representation
///
/// This is used for the "from" and "to" part of a mapping, and the "to" part of
/// Used for the "from" and "to" part of a mapping, and the "to" part of
/// a menu command. Any strings like "<C-UP>" are also replaced, unless
/// 'cpoptions' contains '<'. K_SPECIAL by itself is replaced by K_SPECIAL
/// `special` is false. K_SPECIAL by itself is replaced by K_SPECIAL
/// KS_SPECIAL KE_FILLER.
///
/// @param[in] from What characters to replace.
@ -771,7 +771,7 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag)
/// When cpo_flags contains #FLAG_CPO_BSLASH, a backslash
/// can be used in place of <C-v>. All other <C-v>
/// characters are removed.
/// @param[in] special If true, always accept <key> notation.
/// @param[in] special Replace keycodes, e.g. <CR> becomes a "\n" char.
/// @param[in] cpo_flags Relevant flags derived from p_cpo, see
/// #CPO_TO_CPO_FLAGS.
///
@ -790,11 +790,9 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len,
const char_u *src;
const char_u *const end = from + from_len - 1;
int do_backslash; // backslash is a special character
int do_special; // recognize <> key codes
char_u *result; // buffer for resulting string
do_backslash = !(cpo_flags&FLAG_CPO_BSLASH);
do_special = !(cpo_flags&FLAG_CPO_SPECI) || special;
// Allocate space for the translation. Worst case a single character is
// replaced by 6 bytes (shifted special key), plus a NUL at the end.
@ -817,10 +815,9 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len,
// Copy each byte from *from to result[dlen]
while (src <= end) {
// If 'cpoptions' does not contain '<', check for special key codes,
// like "<C-S-LeftMouse>"
if (do_special && (do_lt || ((end - src) >= 3
&& STRNCMP(src, "<lt>", 4) != 0))) {
// Check for special <> keycodes, like "<C-S-LeftMouse>"
if (special && (do_lt || ((end - src) >= 3
&& STRNCMP(src, "<lt>", 4) != 0))) {
// Replace <SID> by K_SNR <script-nr> _.
// (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
if (end - src >= 4 && STRNICMP(src, "<SID>", 5) == 0) {
@ -846,7 +843,7 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len,
}
}
if (do_special) {
if (special) {
char_u *p, *s, len;
// Replace <Leader> by the value of "mapleader".

View File

@ -464,13 +464,9 @@ enum key_extra {
#define MAX_KEY_CODE_LEN 6
#define FLAG_CPO_BSLASH 0x01
#define FLAG_CPO_SPECI 0x02
#define CPO_TO_CPO_FLAGS (((vim_strchr(p_cpo, CPO_BSLASH) == NULL) \
? 0 \
: FLAG_CPO_BSLASH)| \
(vim_strchr(p_cpo, CPO_SPECI) == NULL \
? 0 \
: FLAG_CPO_SPECI))
#define CPO_TO_CPO_FLAGS ((vim_strchr(p_cpo, CPO_BSLASH) == NULL) \
? 0 \
: FLAG_CPO_BSLASH)
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "keymap.h.generated.h"

View File

@ -14,6 +14,7 @@
#include "nvim/api/vim.h"
#include "nvim/vim.h"
#include "nvim/ex_getln.h"
#include "nvim/ex_cmds2.h"
#include "nvim/message.h"
#include "nvim/memline.h"
#include "nvim/buffer_defs.h"
@ -284,7 +285,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
///
/// Crashes NeoVim if initialization fails. Should be called once per lua
/// interpreter instance.
static lua_State *init_lua(void)
///
/// @return New lua interpreter instance.
static lua_State *nlua_init(void)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
{
lua_State *lstate = luaL_newstate();
@ -297,7 +300,43 @@ static lua_State *init_lua(void)
return lstate;
}
static lua_State *global_lstate = NULL;
/// Enter lua interpreter
///
/// Calls nlua_init() if needed. Is responsible for pre-lua call initalization
/// like updating `package.[c]path` with directories derived from &runtimepath.
///
/// @return Interprter instance to use. Will either be initialized now or taken
/// from previous initalization.
static lua_State *nlua_enter(void)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
{
static lua_State *global_lstate = NULL;
if (global_lstate == NULL) {
global_lstate = nlua_init();
}
lua_State *const lstate = global_lstate;
// Last used p_rtp value. Must not be dereferenced because value pointed to
// may already be freed. Used to check whether &runtimepath option value
// changed.
static const void *last_p_rtp = NULL;
if (last_p_rtp != (const void *)p_rtp) {
// stack: (empty)
lua_getglobal(lstate, "vim");
// stack: vim
lua_getfield(lstate, -1, "_update_package_paths");
// stack: vim, vim._update_package_paths
if (lua_pcall(lstate, 0, 0, 0)) {
// stack: vim, error
nlua_error(lstate, _("E5117: Error while updating package paths: %.*s"));
// stack: vim
}
// stack: vim
lua_pop(lstate, 1);
// stack: (empty)
last_p_rtp = (const void *)p_rtp;
}
return lstate;
}
/// Execute lua string
///
@ -308,11 +347,7 @@ static lua_State *global_lstate = NULL;
void executor_exec_lua(const String str, typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
if (global_lstate == NULL) {
global_lstate = init_lua();
}
NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_lua_string, 0,
NLUA_CALL_C_FUNCTION_2(nlua_enter(), nlua_exec_lua_string, 0,
(void *)&str, ret_tv);
}
@ -551,11 +586,7 @@ void executor_eval_lua(const String str, typval_T *const arg,
typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
if (global_lstate == NULL) {
global_lstate = init_lua();
}
NLUA_CALL_C_FUNCTION_3(global_lstate, nlua_eval_lua_string, 0,
NLUA_CALL_C_FUNCTION_3(nlua_enter(), nlua_eval_lua_string, 0,
(void *)&str, arg, ret_tv);
}
@ -570,12 +601,8 @@ void executor_eval_lua(const String str, typval_T *const arg,
/// @return Return value of the execution.
Object executor_exec_lua_api(const String str, const Array args, Error *err)
{
if (global_lstate == NULL) {
global_lstate = init_lua();
}
Object retval = NIL;
NLUA_CALL_C_FUNCTION_4(global_lstate, nlua_exec_lua_string_api, 0,
NLUA_CALL_C_FUNCTION_4(nlua_enter(), nlua_exec_lua_string_api, 0,
(void *)&str, (void *)&args, &retval, err);
return retval;
}
@ -609,9 +636,6 @@ void ex_lua(exarg_T *const eap)
void ex_luado(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL
{
if (global_lstate == NULL) {
global_lstate = init_lua();
}
if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) {
EMSG(_("cannot save undo information"));
return;
@ -621,7 +645,7 @@ void ex_luado(exarg_T *const eap)
.data = (char *)eap->arg,
};
const linenr_T range[] = { eap->line1, eap->line2 };
NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_luado_string, 0,
NLUA_CALL_C_FUNCTION_2(nlua_enter(), nlua_exec_luado_string, 0,
(void *)&cmd, (void *)range);
}
@ -633,9 +657,6 @@ void ex_luado(exarg_T *const eap)
void ex_luafile(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL
{
if (global_lstate == NULL) {
global_lstate = init_lua();
}
NLUA_CALL_C_FUNCTION_1(global_lstate, nlua_exec_lua_file, 0,
NLUA_CALL_C_FUNCTION_1(nlua_enter(), nlua_exec_lua_file, 0,
(void *)eap->arg);
}

View File

@ -1,2 +1,64 @@
-- TODO(ZyX-I): Create compatibility layer.
return {}
--{{{1 package.path updater function
-- Last inserted paths. Used to clear out items from package.[c]path when they
-- are no longer in &runtimepath.
local last_nvim_paths = {}
local function _update_package_paths()
local cur_nvim_paths = {}
local rtps = vim.api.nvim_list_runtime_paths()
local sep = package.config:sub(1, 1)
for _, key in ipairs({'path', 'cpath'}) do
local orig_str = package[key] .. ';'
local pathtrails_ordered = {}
local orig = {}
-- Note: ignores trailing item without trailing `;`. Not using something
-- simpler in order to preserve empty items (stand for default path).
for s in orig_str:gmatch('[^;]*;') do
s = s:sub(1, -2) -- Strip trailing semicolon
orig[#orig + 1] = s
end
if key == 'path' then
-- /?.lua and /?/init.lua
pathtrails_ordered = {sep .. '?.lua', sep .. '?' .. sep .. 'init.lua'}
else
local pathtrails = {}
for _, s in ipairs(orig) do
-- Find out path patterns. pathtrail should contain something like
-- /?.so, \?.dll. This allows not to bother determining what correct
-- suffixes are.
local pathtrail = s:match('[/\\][^/\\]*%?.*$')
if pathtrail and not pathtrails[pathtrail] then
pathtrails[pathtrail] = true
pathtrails_ordered[#pathtrails_ordered + 1] = pathtrail
end
end
end
local new = {}
for _, rtp in ipairs(rtps) do
if not rtp:match(';') then
for _, pathtrail in pairs(pathtrails_ordered) do
local new_path = rtp .. sep .. 'lua' .. pathtrail
-- Always keep paths from &runtimepath at the start:
-- append them here disregarding orig possibly containing one of them.
new[#new + 1] = new_path
cur_nvim_paths[new_path] = true
end
end
end
for _, orig_path in ipairs(orig) do
-- Handle removing obsolete paths originating from &runtimepath: such
-- paths either belong to cur_nvim_paths and were already added above or
-- to last_nvim_paths and should not be added at all if corresponding
-- entry was removed from &runtimepath list.
if not (cur_nvim_paths[orig_path] or last_nvim_paths[orig_path]) then
new[#new + 1] = orig_path
end
end
package[key] = table.concat(new, ';')
end
last_nvim_paths = cur_nvim_paths
end
--{{{1 Module definition
return {
_update_package_paths = _update_package_paths,
}

View File

@ -57,6 +57,7 @@
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/os/fileio.h"
#include "nvim/event/loop.h"
#include "nvim/os/signal.h"
#include "nvim/event/process.h"
@ -766,16 +767,26 @@ static void command_line_scan(mparm_T *parmp)
version();
mch_exit(0);
} else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {
msgpack_sbuffer* b = msgpack_sbuffer_new();
msgpack_packer* p = msgpack_packer_new(b, msgpack_sbuffer_write);
FileDescriptor fp;
const int fof_ret = file_open_fd(&fp, OS_STDOUT_FILENO, true);
msgpack_packer *p = msgpack_packer_new(&fp, msgpack_file_write);
if (fof_ret != 0) {
emsgf(_("E5421: Failed to open stdin: %s"), os_strerror(fof_ret));
}
if (p == NULL) {
emsgf(_(e_outofmem));
}
Object md = DICTIONARY_OBJ(api_metadata());
msgpack_rpc_from_object(md, p);
for (size_t i = 0; i < b->size; i++) {
putchar(b->data[i]);
}
msgpack_packer_free(p);
const int ff_ret = file_flush(&fp);
if (ff_ret < 0) {
msgpack_file_write_error(ff_ret);
}
mch_exit(0);
} else if (STRICMP(argv[0] + argv_idx, "headless") == 0) {
parmp->headless = true;

View File

@ -1739,52 +1739,55 @@ int mb_charlen_len(char_u *str, int len)
return count;
}
/*
* Try to un-escape a multi-byte character.
* Used for the "to" and "from" part of a mapping.
* Return the un-escaped string if it is a multi-byte character, and advance
* "pp" to just after the bytes that formed it.
* Return NULL if no multi-byte char was found.
*/
char_u * mb_unescape(char_u **pp)
/// Try to unescape a multibyte character
///
/// Used for the rhs and lhs of the mappings.
///
/// @param[in,out] pp String to unescape. Is advanced to just after the bytes
/// that form a multibyte character.
///
/// @return Unescaped string if it is a multibyte character, NULL if no
/// multibyte character was found. Returns a static buffer, always one
/// and the same.
const char *mb_unescape(const char **const pp)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
static char_u buf[6];
int n;
int m = 0;
char_u *str = *pp;
static char buf[6];
size_t buf_idx = 0;
uint8_t *str = (uint8_t *)(*pp);
/* Must translate K_SPECIAL KS_SPECIAL KE_FILLER to K_SPECIAL and CSI
* KS_EXTRA KE_CSI to CSI.
* Maximum length of a utf-8 character is 4 bytes. */
for (n = 0; str[n] != NUL && m < 4; ++n) {
if (str[n] == K_SPECIAL
&& str[n + 1] == KS_SPECIAL
&& str[n + 2] == KE_FILLER) {
buf[m++] = K_SPECIAL;
n += 2;
} else if ((str[n] == K_SPECIAL
)
&& str[n + 1] == KS_EXTRA
&& str[n + 2] == (int)KE_CSI) {
buf[m++] = CSI;
n += 2;
} else if (str[n] == K_SPECIAL
)
break; /* a special key can't be a multibyte char */
else
buf[m++] = str[n];
buf[m] = NUL;
// Must translate K_SPECIAL KS_SPECIAL KE_FILLER to K_SPECIAL and CSI
// KS_EXTRA KE_CSI to CSI.
// Maximum length of a utf-8 character is 4 bytes.
for (size_t str_idx = 0; str[str_idx] != NUL && buf_idx < 4; str_idx++) {
if (str[str_idx] == K_SPECIAL
&& str[str_idx + 1] == KS_SPECIAL
&& str[str_idx + 2] == KE_FILLER) {
buf[buf_idx++] = (char)K_SPECIAL;
str_idx += 2;
} else if ((str[str_idx] == K_SPECIAL)
&& str[str_idx + 1] == KS_EXTRA
&& str[str_idx + 2] == KE_CSI) {
buf[buf_idx++] = (char)CSI;
str_idx += 2;
} else if (str[str_idx] == K_SPECIAL) {
break; // A special key can't be a multibyte char.
} else {
buf[buf_idx++] = (char)str[str_idx];
}
buf[buf_idx] = NUL;
/* Return a multi-byte character if it's found. An illegal sequence
* will result in a 1 here. */
if ((*mb_ptr2len)(buf) > 1) {
*pp = str + n + 1;
// Return a multi-byte character if it's found. An illegal sequence
// will result in a 1 here.
if (utf_ptr2len((const char_u *)buf) > 1) {
*pp = (const char *)str + str_idx + 1;
return buf;
}
/* Bail out quickly for ASCII. */
if (buf[0] < 128)
// Bail out quickly for ASCII.
if ((uint8_t)buf[0] < 128) {
break;
}
}
return NULL;
}

View File

@ -60,7 +60,6 @@ ex_menu (
char_u *map_to;
int noremap;
bool silent = false;
bool special = false;
int unmenu;
char_u *map_buf;
char_u *arg;
@ -86,7 +85,7 @@ ex_menu (
continue;
}
if (STRNCMP(arg, "<special>", 9) == 0) {
special = true;
// Ignore obsolete "<special>" modifier.
arg = skipwhite(arg + 9);
continue;
}
@ -222,7 +221,7 @@ ex_menu (
map_buf = NULL; // Menu tips are plain text.
} else {
map_to = replace_termcodes(map_to, STRLEN(map_to), &map_buf, false, true,
special, CPO_TO_CPO_FLAGS);
true, CPO_TO_CPO_FLAGS);
}
menuarg.modes = modes;
menuarg.noremap[0] = noremap;

View File

@ -1196,7 +1196,7 @@ int msg_outtrans_len_attr(char_u *msgstr, int len, int attr)
len -= mb_l - 1;
str += mb_l;
} else {
s = transchar_byte(*str);
s = transchar_byte((uint8_t)(*str));
if (s[1] != NUL) {
// Unprintable char: print the printable chars so far and the
// translation of the unprintable char.
@ -1269,7 +1269,7 @@ msg_outtrans_special (
string = "<Space>";
str++;
} else {
string = (const char *)str2special((char_u **)&str, from);
string = str2special((const char **)&str, from, false);
}
const int len = vim_strsize((char_u *)string);
// Highlight special keys
@ -1281,108 +1281,125 @@ msg_outtrans_special (
return retval;
}
/*
* Return the lhs or rhs of a mapping, with the key codes turned into printable
* strings, in an allocated string.
*/
char_u *
str2special_save (
char_u *str,
int is_lhs /* TRUE for lhs, FALSE for rhs */
)
/// Convert string, replacing key codes with printables
///
/// Used for lhs or rhs of mappings.
///
/// @param[in] str String to convert.
/// @param[in] replace_spaces Convert spaces into `<Space>`, normally used fo
/// lhs, but not rhs.
/// @param[in] replace_lt Convert `<` into `<lt>`.
///
/// @return [allocated] Converted string.
char *str2special_save(const char *const str, const bool replace_spaces,
const bool replace_lt)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
FUNC_ATTR_NONNULL_RET
{
garray_T ga;
char_u *p = str;
ga_init(&ga, 1, 40);
while (*p != NUL)
ga_concat(&ga, str2special(&p, is_lhs));
const char *p = str;
while (*p != NUL) {
ga_concat(&ga, (const char_u *)str2special(&p, replace_spaces, replace_lt));
}
ga_append(&ga, NUL);
return (char_u *)ga.ga_data;
return (char *)ga.ga_data;
}
/*
* Return the printable string for the key codes at "*sp".
* Used for translating the lhs or rhs of a mapping to printable chars.
* Advances "sp" to the next code.
*/
char_u *
str2special (
char_u **sp,
int from /* TRUE for lhs of mapping */
)
/// Convert character, replacing key one key code with printable representation
///
/// @param[in,out] sp String to convert. Is advanced to the next key code.
/// @param[in] replace_spaces Convert spaces into <Space>, normally used for
/// lhs, but not rhs.
/// @param[in] replace_lt Convert `<` into `<lt>`.
///
/// @return Converted key code, in a static buffer. Buffer is always one and the
/// same, so save converted string somewhere before running str2special
/// for the second time.
const char *str2special(const char **const sp, const bool replace_spaces,
const bool replace_lt)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
{
int c;
static char_u buf[7];
char_u *str = *sp;
int modifiers = 0;
int special = FALSE;
static char buf[7];
if (has_mbyte) {
char_u *p;
/* Try to un-escape a multi-byte character. Return the un-escaped
* string if it is a multi-byte character. */
p = mb_unescape(sp);
if (p != NULL)
return p;
// Try to un-escape a multi-byte character. Return the un-escaped
// string if it is a multi-byte character.
const char *const p = mb_unescape(sp);
if (p != NULL) {
return p;
}
c = *str;
const char *str = *sp;
int c = (uint8_t)(*str);
int modifiers = 0;
bool special = false;
if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) {
if (str[1] == KS_MODIFIER) {
modifiers = str[2];
if ((uint8_t)str[1] == KS_MODIFIER) {
modifiers = (uint8_t)str[2];
str += 3;
c = *str;
c = (uint8_t)(*str);
}
if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) {
c = TO_SPECIAL(str[1], str[2]);
c = TO_SPECIAL((uint8_t)str[1], (uint8_t)str[2]);
str += 2;
if (c == KS_ZERO) /* display <Nul> as ^@ or <Nul> */
if (c == KS_ZERO) { // display <Nul> as ^@ or <Nul>
c = NUL;
}
}
if (IS_SPECIAL(c) || modifiers) { // Special key.
special = true;
}
if (IS_SPECIAL(c) || modifiers) /* special key */
special = TRUE;
}
if (has_mbyte && !IS_SPECIAL(c)) {
int len = (*mb_ptr2len)(str);
if (!IS_SPECIAL(c)) {
const int len = utf_ptr2len((const char_u *)str);
/* For multi-byte characters check for an illegal byte. */
if (has_mbyte && MB_BYTE2LEN(*str) > len) {
transchar_nonprint(buf, c);
// Check for an illegal byte.
if (MB_BYTE2LEN((uint8_t)(*str)) > len) {
transchar_nonprint((char_u *)buf, c);
*sp = str + 1;
return buf;
}
/* Since 'special' is TRUE the multi-byte character 'c' will be
* processed by get_special_key_name() */
c = (*mb_ptr2char)(str);
// Since 'special' is TRUE the multi-byte character 'c' will be
// processed by get_special_key_name().
c = utf_ptr2char((const char_u *)str);
*sp = str + len;
} else
} else {
*sp = str + 1;
}
/* Make unprintable characters in <> form, also <M-Space> and <Tab>.
* Use <Space> only for lhs of a mapping. */
if (special || char2cells(c) > 1 || (from && c == ' '))
return get_special_key_name(c, modifiers);
// Make unprintable characters in <> form, also <M-Space> and <Tab>.
if (special
|| char2cells(c) > 1
|| (replace_spaces && c == ' ')
|| (replace_lt && c == '<')) {
return (const char *)get_special_key_name(c, modifiers);
}
buf[0] = c;
buf[1] = NUL;
return buf;
}
/*
* Translate a key sequence into special key names.
*/
void str2specialbuf(char_u *sp, char_u *buf, int len)
/// Convert string, replacing key codes with printables
///
/// @param[in] str String to convert.
/// @param[out] buf Buffer to save results to.
/// @param[in] len Buffer length.
void str2specialbuf(const char *sp, char *buf, size_t len)
FUNC_ATTR_NONNULL_ALL
{
char_u *s;
*buf = NUL;
while (*sp) {
s = str2special(&sp, FALSE);
if ((int)(STRLEN(s) + STRLEN(buf)) < len)
STRCAT(buf, s);
const char *s = str2special(&sp, false, false);
const size_t s_len = strlen(s);
if (s_len <= len) {
break;
}
memcpy(buf, s, s_len);
buf += s_len;
len -= s_len;
}
*buf = NUL;
}
/*

View File

@ -1451,9 +1451,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
/* Never redo "zf" (define fold). */
if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
&& ((!VIsual_active || oap->motion_force)
/* Also redo Operator-pending Visual mode mappings */
|| (VIsual_active && cap->cmdchar == ':'
&& oap->op_type != OP_COLON))
// Also redo Operator-pending Visual mode mappings.
|| (cap->cmdchar == ':' && oap->op_type != OP_COLON))
&& cap->cmdchar != 'D'
&& oap->op_type != OP_FOLD
&& oap->op_type != OP_FOLDOPEN
@ -5231,6 +5230,7 @@ static void nv_dollar(cmdarg_T *cap)
static void nv_search(cmdarg_T *cap)
{
oparg_T *oap = cap->oap;
pos_T save_cursor = curwin->w_cursor;
if (cap->cmdchar == '?' && cap->oap->op_type == OP_ROT13) {
/* Translate "g??" to "g?g?" */
@ -5240,6 +5240,8 @@ static void nv_search(cmdarg_T *cap)
return;
}
// When using 'incsearch' the cursor may be moved to set a different search
// start position.
cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0);
if (cap->searchbuf == NULL) {
@ -5248,7 +5250,8 @@ static void nv_search(cmdarg_T *cap)
}
(void)normal_search(cap, cap->cmdchar, cap->searchbuf,
(cap->arg ? 0 : SEARCH_MARK));
(cap->arg || !equalpos(save_cursor, curwin->w_cursor))
? 0 : SEARCH_MARK);
}
/*

View File

@ -969,10 +969,13 @@ void set_init_2(bool headless)
p_window = Rows - 1;
}
set_number_default("window", Rows - 1);
#if 0
// This bodges around problems that should be fixed in the TUI layer.
if (!headless && !os_term_is_nice()) {
set_string_option_direct((char_u *)"guicursor", -1, (char_u *)"",
OPT_GLOBAL, SID_NONE);
}
#endif
parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor'
(void)parse_printoptions(); // parse 'printoptions' default value
}
@ -3031,7 +3034,7 @@ did_set_string_option (
/* 'pastetoggle': translate key codes like in a mapping */
else if (varp == &p_pt) {
if (*p_pt) {
(void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, false,
(void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, true,
CPO_TO_CPO_FLAGS);
if (p != NULL) {
if (new_value_alloced)
@ -5175,9 +5178,13 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, int e
* CTRL-V or backslash */
if (valuep == &p_pt) {
s = *valuep;
while (*s != NUL)
if (put_escstr(fd, str2special(&s, FALSE), 2) == FAIL)
while (*s != NUL) {
if (put_escstr(fd, (char_u *)str2special((const char **)&s, false,
false), 2)
== FAIL) {
return FAIL;
}
}
} else if (expand) {
buf = xmalloc(MAXPATHL);
home_replace(NULL, *valuep, buf, MAXPATHL, FALSE);
@ -6173,15 +6180,16 @@ option_value2string (
}
} else { // P_STRING
varp = *(char_u **)(varp);
if (varp == NULL) /* just in case */
if (varp == NULL) { // Just in case.
NameBuff[0] = NUL;
else if (opp->flags & P_EXPAND)
home_replace(NULL, varp, NameBuff, MAXPATHL, FALSE);
/* Translate 'pastetoggle' into special key names */
else if ((char_u **)opp->var == &p_pt)
str2specialbuf(p_pt, NameBuff, MAXPATHL);
else
} else if (opp->flags & P_EXPAND) {
home_replace(NULL, varp, NameBuff, MAXPATHL, false);
// Translate 'pastetoggle' into special key names.
} else if ((char_u **)opp->var == &p_pt) {
str2specialbuf((const char *)p_pt, (char *)NameBuff, MAXPATHL);
} else {
STRLCPY(NameBuff, varp, MAXPATHL);
}
}
}

View File

@ -81,58 +81,56 @@
#define DFLT_FO_VIM "tcqj"
#define FO_ALL "tcroq2vlb1mMBn,awj" /* for do_set() */
/* characters for the p_cpo option: */
#define CPO_ALTREAD 'a' /* ":read" sets alternate file name */
#define CPO_ALTWRITE 'A' /* ":write" sets alternate file name */
#define CPO_BAR 'b' /* "\|" ends a mapping */
#define CPO_BSLASH 'B' /* backslash in mapping is not special */
// characters for the p_cpo option:
#define CPO_ALTREAD 'a' // ":read" sets alternate file name
#define CPO_ALTWRITE 'A' // ":write" sets alternate file name
#define CPO_BAR 'b' // "\|" ends a mapping
#define CPO_BSLASH 'B' // backslash in mapping is not special
#define CPO_SEARCH 'c'
#define CPO_CONCAT 'C' /* Don't concatenate sourced lines */
#define CPO_DOTTAG 'd' /* "./tags" in 'tags' is in current dir */
#define CPO_DIGRAPH 'D' /* No digraph after "r", "f", etc. */
#define CPO_CONCAT 'C' // Don't concatenate sourced lines
#define CPO_DOTTAG 'd' // "./tags" in 'tags' is in current dir
#define CPO_DIGRAPH 'D' // No digraph after "r", "f", etc.
#define CPO_EXECBUF 'e'
#define CPO_EMPTYREGION 'E' /* operating on empty region is an error */
#define CPO_FNAMER 'f' /* set file name for ":r file" */
#define CPO_FNAMEW 'F' /* set file name for ":w file" */
#define CPO_INTMOD 'i' /* interrupt a read makes buffer modified */
#define CPO_INDENT 'I' /* remove auto-indent more often */
#define CPO_ENDOFSENT 'J' /* need two spaces to detect end of sentence */
#define CPO_KEYCODE 'k' /* don't recognize raw key code in mappings */
#define CPO_KOFFSET 'K' /* don't wait for key code in mappings */
#define CPO_LITERAL 'l' /* take char after backslash in [] literal */
#define CPO_LISTWM 'L' /* 'list' changes wrapmargin */
#define CPO_EMPTYREGION 'E' // operating on empty region is an error
#define CPO_FNAMER 'f' // set file name for ":r file"
#define CPO_FNAMEW 'F' // set file name for ":w file"
#define CPO_INTMOD 'i' // interrupt a read makes buffer modified
#define CPO_INDENT 'I' // remove auto-indent more often
#define CPO_ENDOFSENT 'J' // need two spaces to detect end of sentence
#define CPO_KOFFSET 'K' // don't wait for key code in mappings
#define CPO_LITERAL 'l' // take char after backslash in [] literal
#define CPO_LISTWM 'L' // 'list' changes wrapmargin
#define CPO_SHOWMATCH 'm'
#define CPO_MATCHBSL 'M' /* "%" ignores use of backslashes */
#define CPO_NUMCOL 'n' /* 'number' column also used for text */
#define CPO_MATCHBSL 'M' // "%" ignores use of backslashes
#define CPO_NUMCOL 'n' // 'number' column also used for text
#define CPO_LINEOFF 'o'
#define CPO_OVERNEW 'O' /* silently overwrite new file */
#define CPO_LISP 'p' /* 'lisp' indenting */
#define CPO_FNAMEAPP 'P' /* set file name for ":w >>file" */
#define CPO_JOINCOL 'q' /* with "3J" use column after first join */
#define CPO_OVERNEW 'O' // silently overwrite new file
#define CPO_LISP 'p' // 'lisp' indenting
#define CPO_FNAMEAPP 'P' // set file name for ":w >>file"
#define CPO_JOINCOL 'q' // with "3J" use column after first join
#define CPO_REDO 'r'
#define CPO_REMMARK 'R' /* remove marks when filtering */
#define CPO_REMMARK 'R' // remove marks when filtering
#define CPO_BUFOPT 's'
#define CPO_BUFOPTGLOB 'S'
#define CPO_TAGPAT 't'
#define CPO_UNDO 'u' /* "u" undoes itself */
#define CPO_BACKSPACE 'v' /* "v" keep deleted text */
#define CPO_FWRITE 'W' /* "w!" doesn't overwrite readonly files */
#define CPO_UNDO 'u' // "u" undoes itself
#define CPO_BACKSPACE 'v' // "v" keep deleted text
#define CPO_FWRITE 'W' // "w!" doesn't overwrite readonly files
#define CPO_ESC 'x'
#define CPO_REPLCNT 'X' /* "R" with a count only deletes chars once */
#define CPO_REPLCNT 'X' // "R" with a count only deletes chars once
#define CPO_YANK 'y'
#define CPO_KEEPRO 'Z' /* don't reset 'readonly' on ":w!" */
#define CPO_KEEPRO 'Z' // don't reset 'readonly' on ":w!"
#define CPO_DOLLAR '$'
#define CPO_FILTER '!'
#define CPO_MATCH '%'
#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 */
#define CPO_SCOLON ';' /* using "," and ";" will skip over char if
* cursor would not move */
#define CPO_PLUS '+' // ":write file" resets 'modified'
#define CPO_REGAPPEND '>' // insert NL when appending to a register
#define CPO_SCOLON ';' // using "," and ";" will skip over char if
// cursor would not move
#define CPO_CHANGEW '_' // "cw" special-case
// default values for Vim and Vi
#define CPO_VIM "aABceFs_"
#define CPO_VI "aAbBcCdDeEfFiIJkKlLmMnoOpPqrRsStuvWxXyZ$!%+<>;_"
#define CPO_VI "aAbBcCdDeEfFiIJKlLmMnoOpPqrRsStuvWxXyZ$!%+>;_"
/* characters for p_ww option: */
#define WW_ALL "bshl<>[],~"

View File

@ -2513,14 +2513,14 @@ return {
vi_def=true,
vim=true,
varname='p_ttimeout',
defaults={if_true={vi=false}}
defaults={if_true={vi=true}}
},
{
full_name='ttimeoutlen', abbreviation='ttm',
type='number', scope={'global'},
vi_def=true,
varname='p_ttm',
defaults={if_true={vi=-1}}
defaults={if_true={vi=50}}
},
{
full_name='ttyfast', abbreviation='tf',

View File

@ -26,6 +26,7 @@
#include "nvim/globals.h"
#include "nvim/rbuffer.h"
#include "nvim/macros.h"
#include "nvim/message.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/fileio.c.generated.h"
@ -48,7 +49,6 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int os_open_flags = 0;
int fd;
TriState wr = kNone;
// -V:FLAG:501
#define FLAG(flags, flag, fcntl_flags, wrval, cond) \
@ -73,14 +73,35 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true);
#endif
#undef FLAG
// wr is used for kFileReadOnly flag, but on
// QB:neovim-qb-slave-ubuntu-12-04-64bit it still errors out with
// `error: variable wr set but not used [-Werror=unused-but-set-variable]`
(void)wr;
fd = os_open(fname, os_open_flags, mode);
const int fd = os_open(fname, os_open_flags, mode);
if (fd < 0) {
return fd;
}
return file_open_fd(ret_fp, fd, (wr == kTrue));
}
ret_fp->wr = (wr == kTrue);
/// Wrap file descriptor with FileDescriptor structure
///
/// @warning File descriptor wrapped like this must not be accessed by other
/// means.
///
/// @param[out] ret_fp Address where information needed for reading from or
/// writing to a file is saved
/// @param[in] fd File descriptor to wrap.
/// @param[in] wr True if fd is opened for writing only, false if it is read
/// only.
///
/// @return Error code (@see os_strerror()) or 0. Currently always returns 0.
int file_open_fd(FileDescriptor *const ret_fp, const int fd, const bool wr)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
ret_fp->wr = wr;
ret_fp->fd = fd;
ret_fp->eof = false;
ret_fp->rv = rbuffer_new(kRWBufferSize);
@ -114,6 +135,26 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,
return fp;
}
/// Like file_open_fd(), but allocate and return ret_fp
///
/// @param[out] error Error code, @see os_strerror(). Is set to zero on
/// success.
/// @param[in] fd File descriptor to wrap.
/// @param[in] wr True if fd is opened for writing only, false if it is read
/// only.
///
/// @return [allocated] Opened file or NULL in case of error.
FileDescriptor *file_open_fd_new(int *const error, const int fd, const bool wr)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
{
FileDescriptor *const fp = xmalloc(sizeof(*fp));
if ((*error = file_open_fd(fp, fd, wr)) != 0) {
xfree(fp);
return NULL;
}
return fp;
}
/// Close file and free its buffer
///
/// @param[in,out] fp File to close.
@ -345,3 +386,32 @@ ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size)
return (ptrdiff_t)read_bytes;
}
/// Msgpack callback for writing to a file
///
/// @param data File to write to.
/// @param[in] buf Data to write.
/// @param[in] len Length of the data to write.
///
/// @return 0 in case of success, -1 in case of error.
int msgpack_file_write(void *data, const char *buf, size_t len)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(len < PTRDIFF_MAX);
const ptrdiff_t written_bytes = file_write((FileDescriptor *)data, buf, len);
if (written_bytes < 0) {
return msgpack_file_write_error((int)written_bytes);
}
return 0;
}
/// Print error which occurs when failing to write msgpack data
///
/// @param[in] error Error code of the error to print.
///
/// @return -1 (error return for msgpack_packer callbacks).
int msgpack_file_write_error(const int error)
{
emsgf(_("E5420: Failed to write to file: %s"), os_strerror(error));
return -1;
}

View File

@ -13,6 +13,13 @@
# include "nvim/os/unix_defs.h"
#endif
/// File descriptor number used for standard IO streams
enum {
OS_STDIN_FILENO = STDIN_FILENO,
OS_STDOUT_FILENO = STDOUT_FILENO,
OS_STDERR_FILENO = STDERR_FILENO,
};
#define BASENAMELEN (NAME_MAX - 5)
// Use the system path length if it makes sense.

View File

@ -91,4 +91,14 @@ typedef SSIZE_T ssize_t;
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#endif
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#endif // NVIM_OS_WIN_DEFS_H

View File

@ -6928,9 +6928,10 @@ char_u *reg_submatch(int no)
STRNCPY(retval + len, reg_getline_submatch(lnum),
submatch_mmatch->endpos[no].col);
len += submatch_mmatch->endpos[no].col;
if (round == 2)
retval[len] = NUL;
++len;
if (round == 2) {
retval[len] = NUL; // -V595
}
len++;
}
if (retval == NULL) {

View File

@ -3913,7 +3913,7 @@ addstate (
int k;
int found = FALSE;
nfa_thread_T *thread;
lpos_T save_lpos;
struct multipos save_multipos;
int save_in_use;
char_u *save_ptr;
int i;
@ -4127,15 +4127,13 @@ skip_add:
/* avoid compiler warnings */
save_ptr = NULL;
save_lpos.lnum = 0;
save_lpos.col = 0;
memset(&save_multipos, 0, sizeof(save_multipos));
/* Set the position (with "off" added) in the subexpression. Save
* and restore it when it was in use. Otherwise fill any gap. */
if (REG_MULTI) {
if (subidx < sub->in_use) {
save_lpos.lnum = sub->list.multi[subidx].start_lnum;
save_lpos.col = sub->list.multi[subidx].start_col;
save_multipos = sub->list.multi[subidx];
save_in_use = -1;
} else {
save_in_use = sub->in_use;
@ -4178,9 +4176,8 @@ skip_add:
sub = &subs->norm;
if (save_in_use == -1) {
if (REG_MULTI){
sub->list.multi[subidx].start_lnum = save_lpos.lnum;
sub->list.multi[subidx].start_col = save_lpos.col;
if (REG_MULTI) {
sub->list.multi[subidx] = save_multipos;
}
else
sub->list.line[subidx].start = save_ptr;
@ -4234,8 +4231,7 @@ skip_add:
if (sub->in_use <= subidx)
sub->in_use = subidx + 1;
if (REG_MULTI) {
save_lpos.lnum = sub->list.multi[subidx].end_lnum;
save_lpos.col = sub->list.multi[subidx].end_col;
save_multipos = sub->list.multi[subidx];
if (off == -1) {
sub->list.multi[subidx].end_lnum = reglnum + 1;
sub->list.multi[subidx].end_col = 0;
@ -4249,9 +4245,8 @@ skip_add:
} else {
save_ptr = sub->list.line[subidx].end;
sub->list.line[subidx].end = reginput + off;
/* avoid compiler warnings */
save_lpos.lnum = 0;
save_lpos.col = 0;
// avoid compiler warnings
memset(&save_multipos, 0, sizeof(save_multipos));
}
subs = addstate(l, state->out, subs, pim, off_arg);
@ -4261,9 +4256,8 @@ skip_add:
else
sub = &subs->norm;
if (REG_MULTI){
sub->list.multi[subidx].end_lnum = save_lpos.lnum;
sub->list.multi[subidx].end_col = save_lpos.col;
if (REG_MULTI) {
sub->list.multi[subidx] = save_multipos;
}
else
sub->list.line[subidx].end = save_ptr;

View File

@ -4230,7 +4230,6 @@ win_line (
* (regardless of the xn,am settings).
* Only do this if the cursor is on the current line
* (something has been written in it).
* Don't do this for the GUI.
* Don't do this for double-width characters.
* Don't do this for a window not at the right screen border.
*/
@ -5846,12 +5845,12 @@ static void screen_char(unsigned off, int row, int col)
if (row >= screen_Rows || col >= screen_Columns)
return;
/* Outputting the last character on the screen may scrollup the screen.
* Don't to it! Mark the character invalid (update it when scrolled up) */
// Outputting the last character on the screen may scrollup the screen.
// Don't to it! Mark the character invalid (update it when scrolled up)
// FIXME: The premise here is not actually true (cf. deferred wrap).
if (row == screen_Rows - 1 && col == screen_Columns - 1
/* account for first command-line character in rightleft mode */
&& !cmdmsg_rl
) {
// account for first command-line character in rightleft mode
&& !cmdmsg_rl) {
ScreenAttrs[off] = (sattr_T)-1;
return;
}

View File

@ -3413,8 +3413,16 @@ shada_read_next_item_start:
return mru_ret;
}
const size_t length = (size_t) length_u64;
entry->timestamp = (Timestamp) timestamp_u64;
if (length_u64 > PTRDIFF_MAX) {
emsgf(_(RCERR "Error while reading ShaDa file: "
"there is an item at position %" PRIu64 " "
"that is stated to be too long"),
initial_fpos);
return kSDReadStatusNotShaDa;
}
const size_t length = (size_t)length_u64;
entry->timestamp = (Timestamp)timestamp_u64;
if (type_u64 == 0) {
// kSDItemUnknown cannot possibly pass that far because it is -1 and that

View File

@ -1433,12 +1433,10 @@ spell_move_to (
// the cursor.
if (dir == BACKWARD
|| lnum != wp->w_cursor.lnum
|| (lnum == wp->w_cursor.lnum
&& (wrapped
|| ((colnr_T)(curline
? p - buf + (ptrdiff_t)len
: p - buf)
> wp->w_cursor.col)))) {
|| wrapped
|| ((colnr_T)(curline
? p - buf + (ptrdiff_t)len
: p - buf) > wp->w_cursor.col)) {
if (has_syntax) {
col = (int)(p - buf);
(void)syn_get_id(wp, lnum, (colnr_T)col,
@ -2070,7 +2068,7 @@ char_u *did_set_spelllang(win_T *wp)
// destroying the buffer we are using...
if (!bufref_valid(&bufref)) {
ret_msg =
(char_u *)"E797: SpellFileMissing autocommand deleted buffer";
(char_u *)N_("E797: SpellFileMissing autocommand deleted buffer");
goto theend;
}
}
@ -3635,7 +3633,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// word).
depth = 0;
sp = &stack[0];
memset(sp, 0, sizeof(trystate_T));
memset(sp, 0, sizeof(trystate_T)); // -V512
sp->ts_curi = 1;
if (soundfold) {

View File

@ -1666,8 +1666,9 @@ syn_current_attr (
* If we found a match after the last column, use it.
*/
if (next_match_idx >= 0 && next_match_col >= (int)current_col
&& next_match_col != MAXCOL)
(void)push_next_match(NULL);
&& next_match_col != MAXCOL) {
(void)push_next_match();
}
current_finished = TRUE;
current_state_stored = FALSE;
@ -1985,9 +1986,10 @@ syn_current_attr (
* endless loop). */
GA_APPEND(int, &zero_width_next_ga, next_match_idx);
next_match_idx = -1;
} else
cur_si = push_next_match(cur_si);
found_match = TRUE;
} else {
cur_si = push_next_match();
}
found_match = true;
}
}
}
@ -2167,9 +2169,10 @@ static int did_match_already(int idx, garray_T *gap)
/*
* Push the next match onto the stack.
*/
static stateitem_T *push_next_match(stateitem_T *cur_si)
static stateitem_T *push_next_match(void)
{
synpat_T *spp;
stateitem_T *cur_si;
synpat_T *spp;
int save_flags;
spp = &(SYN_ITEMS(syn_block)[next_match_idx]);

View File

@ -229,7 +229,7 @@ Terminal *terminal_open(TerminalOptions opts)
rv->invalid_start = 0;
rv->invalid_end = opts.height;
refresh_screen(rv, curbuf);
set_option_value("buftype", 0, "terminal", OPT_LOCAL);
set_option_value("buftype", 0, "terminal", OPT_LOCAL); // -V666
// Default settings for terminal buffers
curbuf->b_p_ma = false; // 'nomodifiable'

View File

@ -62,6 +62,8 @@ NEW_TESTS ?= \
test_signs.res \
test_smartindent.res \
test_stat.res \
test_startup.res \
test_startup_utf8.res \
test_substitute.res \
test_syntax.res \
test_tabpage.res \

View File

@ -98,6 +98,21 @@ func Test_recursive_substitute()
bwipe!
endfunc
func Test_nested_backrefs()
" Check example in change.txt.
new
for re in range(0, 2)
exe 'set re=' . re
call setline(1, 'aa ab x')
1s/\(\(a[a-d] \)*\)\(x\)/-\1- -\2- -\3-/
call assert_equal('-aa ab - -ab - -x-', getline(1))
call assert_equal('-aa ab - -ab - -x-', substitute('aa ab x', '\(\(a[a-d] \)*\)\(x\)', '-\1- -\2- -\3-', ''))
endfor
bwipe!
set re=0
endfunc
func Test_eow_with_optional()
let expected = ['abc def', 'abc', 'def', '', '', '', '', '', '', '']
for re in range(0, 2)

View File

@ -1,5 +1,278 @@
" Test for the search command
func Test_search_cmdline()
" See test/functional/legacy/search_spec.lua
throw 'skipped: Nvim does not support test_disable_char_avail()'
if !exists('+incsearch')
return
endif
" need to disable char_avail,
" so that expansion of commandline works
call test_disable_char_avail(1)
new
call setline(1, [' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there', ' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar'])
" Test 1
" CTRL-N / CTRL-P skips through the previous search history
set noincsearch
:1
call feedkeys("/foobar\<cr>", 'tx')
call feedkeys("/the\<cr>",'tx')
call assert_equal('the', @/)
call feedkeys("/thes\<C-P>\<C-P>\<cr>",'tx')
call assert_equal('foobar', @/)
" Test 2
" Ctrl-G goes from one match to the next
" until the end of the buffer
set incsearch nowrapscan
:1
" first match
call feedkeys("/the\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
:1
" second match
call feedkeys("/the\<C-G>\<cr>", 'tx')
call assert_equal(' 3 the', getline('.'))
call assert_equal([0, 0, 0, 0], getpos('"'))
:1
" third match
call feedkeys("/the".repeat("\<C-G>", 2)."\<cr>", 'tx')
call assert_equal(' 4 their', getline('.'))
:1
" fourth match
call feedkeys("/the".repeat("\<C-G>", 3)."\<cr>", 'tx')
call assert_equal(' 5 there', getline('.'))
:1
" fifth match
call feedkeys("/the".repeat("\<C-G>", 4)."\<cr>", 'tx')
call assert_equal(' 6 their', getline('.'))
:1
" sixth match
call feedkeys("/the".repeat("\<C-G>", 5)."\<cr>", 'tx')
call assert_equal(' 7 the', getline('.'))
:1
" seventh match
call feedkeys("/the".repeat("\<C-G>", 6)."\<cr>", 'tx')
call assert_equal(' 8 them', getline('.'))
:1
" eigth match
call feedkeys("/the".repeat("\<C-G>", 7)."\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
:1
" no further match
call feedkeys("/the".repeat("\<C-G>", 8)."\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
call assert_equal([0, 0, 0, 0], getpos('"'))
" Test 3
" Ctrl-G goes from one match to the next
" and continues back at the top
set incsearch wrapscan
:1
" first match
call feedkeys("/the\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
:1
" second match
call feedkeys("/the\<C-G>\<cr>", 'tx')
call assert_equal(' 3 the', getline('.'))
:1
" third match
call feedkeys("/the".repeat("\<C-G>", 2)."\<cr>", 'tx')
call assert_equal(' 4 their', getline('.'))
:1
" fourth match
call feedkeys("/the".repeat("\<C-G>", 3)."\<cr>", 'tx')
call assert_equal(' 5 there', getline('.'))
:1
" fifth match
call feedkeys("/the".repeat("\<C-G>", 4)."\<cr>", 'tx')
call assert_equal(' 6 their', getline('.'))
:1
" sixth match
call feedkeys("/the".repeat("\<C-G>", 5)."\<cr>", 'tx')
call assert_equal(' 7 the', getline('.'))
:1
" seventh match
call feedkeys("/the".repeat("\<C-G>", 6)."\<cr>", 'tx')
call assert_equal(' 8 them', getline('.'))
:1
" eigth match
call feedkeys("/the".repeat("\<C-G>", 7)."\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
:1
" back at first match
call feedkeys("/the".repeat("\<C-G>", 8)."\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
" Test 4
" CTRL-T goes to the previous match
set incsearch nowrapscan
$
" first match
call feedkeys("?the\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
$
" first match
call feedkeys("?the\<C-G>\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
$
" second match
call feedkeys("?the".repeat("\<C-T>", 1)."\<cr>", 'tx')
call assert_equal(' 8 them', getline('.'))
$
" last match
call feedkeys("?the".repeat("\<C-T>", 7)."\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
$
" last match
call feedkeys("?the".repeat("\<C-T>", 8)."\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
" Test 5
" CTRL-T goes to the previous match
set incsearch wrapscan
$
" first match
call feedkeys("?the\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
$
" first match at the top
call feedkeys("?the\<C-G>\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
$
" second match
call feedkeys("?the".repeat("\<C-T>", 1)."\<cr>", 'tx')
call assert_equal(' 8 them', getline('.'))
$
" last match
call feedkeys("?the".repeat("\<C-T>", 7)."\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
$
" back at the bottom of the buffer
call feedkeys("?the".repeat("\<C-T>", 8)."\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
" Test 6
" CTRL-L adds to the search pattern
set incsearch wrapscan
1
" first match
call feedkeys("/the\<c-l>\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
1
" go to next match of 'thes'
call feedkeys("/the\<c-l>\<C-G>\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
1
" wrap around
call feedkeys("/the\<c-l>\<C-G>\<C-G>\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
1
" wrap around
set nowrapscan
call feedkeys("/the\<c-l>\<C-G>\<C-G>\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
" Test 7
" <bs> remove from match, but stay at current match
set incsearch wrapscan
1
" first match
call feedkeys("/thei\<cr>", 'tx')
call assert_equal(' 4 their', getline('.'))
1
" delete one char, add another
call feedkeys("/thei\<bs>s\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
1
" delete one char, add another, go to previous match, add one char
call feedkeys("/thei\<bs>s\<bs>\<C-T>\<c-l>\<cr>", 'tx')
call assert_equal(' 9 these', getline('.'))
1
" delete all chars, start from the beginning again
call feedkeys("/them". repeat("\<bs>",4).'the\>'."\<cr>", 'tx')
call assert_equal(' 3 the', getline('.'))
" clean up
call test_disable_char_avail(0)
bw!
endfunc
func Test_search_cmdline2()
" See test/functional/legacy/search_spec.lua
throw 'skipped: Nvim does not support test_disable_char_avail()'
if !exists('+incsearch')
return
endif
" need to disable char_avail,
" so that expansion of commandline works
call test_disable_char_avail(1)
new
call setline(1, [' 1', ' 2 these', ' 3 the theother'])
" Test 1
" Ctrl-T goes correctly back and forth
set incsearch
1
" first match
call feedkeys("/the\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
1
" go to next match (on next line)
call feedkeys("/the\<C-G>\<cr>", 'tx')
call assert_equal(' 3 the theother', getline('.'))
1
" go to next match (still on line 3)
call feedkeys("/the\<C-G>\<C-G>\<cr>", 'tx')
call assert_equal(' 3 the theother', getline('.'))
1
" go to next match (still on line 3)
call feedkeys("/the\<C-G>\<C-G>\<C-G>\<cr>", 'tx')
call assert_equal(' 3 the theother', getline('.'))
1
" go to previous match (on line 3)
call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<cr>", 'tx')
call assert_equal(' 3 the theother', getline('.'))
1
" go to previous match (on line 3)
call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<cr>", 'tx')
call assert_equal(' 3 the theother', getline('.'))
1
" go to previous match (on line 2)
call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<C-T>\<cr>", 'tx')
call assert_equal(' 2 these', getline('.'))
" Test 2: keep the view,
" after deleting a character from the search cmd
call setline(1, [' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there', ' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar'])
resize 5
1
call feedkeys("/foo\<bs>\<cr>", 'tx')
redraw
call assert_equal({'lnum': 10, 'leftcol': 0, 'col': 4, 'topfill': 0, 'topline': 6, 'coladd': 0, 'skipcol': 0, 'curswant': 4}, winsaveview())
" remove all history entries
for i in range(10)
call histdel('/')
endfor
" Test 3: reset the view,
" after deleting all characters from the search cmd
norm! 1gg0
" unfortunately, neither "/foo\<c-w>\<cr>", nor "/foo\<bs>\<bs>\<bs>\<cr>",
" nor "/foo\<c-u>\<cr>" works to delete the commandline.
" In that case Vim should return "E35 no previous regular expression",
" but it looks like Vim still sees /foo and therefore the test fails.
" Therefore, disableing this test
"call assert_fails(feedkeys("/foo\<c-w>\<cr>", 'tx'), 'E35')
"call assert_equal({'lnum': 1, 'leftcol': 0, 'col': 0, 'topfill': 0, 'topline': 1, 'coladd': 0, 'skipcol': 0, 'curswant': 0}, winsaveview())
" clean up
set noincsearch
call test_disable_char_avail(0)
bw!
endfunc
func Test_use_sub_pat()
split
let @/ = ''

View File

@ -75,7 +75,7 @@ func Test_help_arg()
" check if couple of lines are there
let found = []
for line in lines
if line =~ '-R.*Readonly mode'
if line =~ '-R.*Read-only mode'
call add(found, 'Readonly mode')
endif
" Watch out for a second --version line in the Gnome version.

View File

@ -0,0 +1,64 @@
" Tests for startup using utf-8.
if !has('multi_byte')
finish
endif
source shared.vim
func Test_read_stdin_utf8()
let linesin = ['テスト', '€ÀÈÌÒÙ']
call writefile(linesin, 'Xtestin')
let before = [
\ 'set enc=utf-8',
\ 'set fencs=cp932,utf-8',
\ ]
let after = [
\ 'write ++enc=utf-8 Xtestout',
\ 'quit!',
\ ]
if has('win32')
let pipecmd = 'type Xtestin | '
else
let pipecmd = 'cat Xtestin | '
endif
if RunVimPiped(before, after, '-', pipecmd)
let lines = readfile('Xtestout')
call assert_equal(linesin, lines)
else
call assert_equal('', 'RunVimPiped failed.')
endif
call delete('Xtestout')
call delete('Xtestin')
endfunc
func Test_read_fifo_utf8()
if !has('unix')
return
endif
" Using bash/zsh's process substitution.
if executable('bash')
set shell=bash
elseif executable('zsh')
set shell=zsh
else
return
endif
let linesin = ['テスト', '€ÀÈÌÒÙ']
call writefile(linesin, 'Xtestin')
let before = [
\ 'set enc=utf-8',
\ 'set fencs=cp932,utf-8',
\ ]
let after = [
\ 'write ++enc=utf-8 Xtestout',
\ 'quit!',
\ ]
if RunVim(before, after, '<(cat Xtestin)')
let lines = readfile('Xtestout')
call assert_equal(linesin, lines)
else
call assert_equal('', 'RunVim failed.')
endif
call delete('Xtestout')
call delete('Xtestin')
endfunc

121
src/nvim/tui/terminfo.c Normal file

File diff suppressed because one or more lines are too long

10
src/nvim/tui/terminfo.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef NVIM_TUI_TERMINFO_H
#define NVIM_TUI_TERMINFO_H
#include <unibilium.h>
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/terminfo.h.generated.h"
#endif
#endif // NVIM_TUI_TERMINFO_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,14 +10,14 @@ extern char* longVersion;
//
// Vim version number, name, etc. Patchlevel is defined in version.c.
//
#define VIM_VERSION_MAJOR 7
#define VIM_VERSION_MINOR 4
#define VIM_VERSION_MAJOR 8
#define VIM_VERSION_MINOR 0
#define VIM_VERSION_100 (VIM_VERSION_MAJOR * 100 + VIM_VERSION_MINOR)
// used for the runtime directory name
#define VIM_VERSION_NODOT "vim74"
#define VIM_VERSION_NODOT "vim80"
// swap file compatibility (max. length is 6 chars)
#define VIM_VERSION_SHORT "7.4"
#define VIM_VERSION_SHORT "8.0"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "version.h.generated.h"

View File

@ -319,4 +319,8 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext()
// Lowest number used for window ID. Cannot have this many windows per tab.
#define LOWEST_WIN_ID 1000
#if defined(__FreeBSD__) && defined(S_ISCHR)
# define OPEN_CHR_FILES
#endif
#endif /* NVIM_VIM_H */

View File

@ -5532,8 +5532,8 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
return -1;
}
if (id < -1 || id == 0) {
EMSGN("E799: Invalid ID: %" PRId64
" (must be greater than or equal to 1)",
EMSGN(_("E799: Invalid ID: %" PRId64
" (must be greater than or equal to 1)"),
id);
return -1;
}
@ -5541,7 +5541,7 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
cur = wp->w_match_head;
while (cur != NULL) {
if (cur->id == id) {
EMSGN("E801: ID already taken: %" PRId64, id);
EMSGN(_("E801: ID already taken: %" PRId64), id);
return -1;
}
cur = cur->next;
@ -5705,10 +5705,11 @@ int match_delete(win_T *wp, int id, int perr)
int rtype = SOME_VALID;
if (id < 1) {
if (perr == TRUE)
EMSGN("E802: Invalid ID: %" PRId64
" (must be greater than or equal to 1)",
if (perr) {
EMSGN(_("E802: Invalid ID: %" PRId64
" (must be greater than or equal to 1)"),
id);
}
return -1;
}
while (cur != NULL && cur->id != id) {
@ -5716,8 +5717,9 @@ int match_delete(win_T *wp, int id, int perr)
cur = cur->next;
}
if (cur == NULL) {
if (perr == TRUE)
EMSGN("E803: ID not found: %" PRId64, id);
if (perr) {
EMSGN(_("E803: ID not found: %" PRId64), id);
}
return -1;
}
if (cur == prev)

View File

@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local global_helpers = require('test.helpers')
local clear = helpers.clear
local command = helpers.command
local curbufmeths = helpers.curbufmeths
@ -8,13 +9,7 @@ local funcs = helpers.funcs
local meths = helpers.meths
local source = helpers.source
local function local_copy(t)
local copy = {}
for k,v in pairs(t) do
copy[k] = v
end
return copy
end
local shallowcopy = global_helpers.shallowcopy
describe('get_keymap', function()
before_each(clear)
@ -22,16 +17,16 @@ describe('get_keymap', function()
-- Basic mapping and table to be used to describe results
local foo_bar_string = 'nnoremap foo bar'
local foo_bar_map_table = {
lhs='foo',
silent=0,
rhs='bar',
expr=0,
sid=0,
buffer=0,
nowait=0,
mode='n',
noremap=1,
}
lhs='foo',
silent=0,
rhs='bar',
expr=0,
sid=0,
buffer=0,
nowait=0,
mode='n',
noremap=1,
}
it('returns empty list when no map', function()
eq({}, meths.get_keymap('n'))
@ -50,7 +45,7 @@ describe('get_keymap', function()
-- Add another mapping
command('nnoremap foo_longer bar_longer')
local foolong_bar_map_table = local_copy(foo_bar_map_table)
local foolong_bar_map_table = shallowcopy(foo_bar_map_table)
foolong_bar_map_table['lhs'] = 'foo_longer'
foolong_bar_map_table['rhs'] = 'bar_longer'
@ -72,7 +67,7 @@ describe('get_keymap', function()
command('inoremap foo bar')
-- The table will be the same except for the mode
local insert_table = local_copy(foo_bar_map_table)
local insert_table = shallowcopy(foo_bar_map_table)
insert_table['mode'] = 'i'
eq({insert_table}, meths.get_keymap('i'))
@ -81,11 +76,11 @@ describe('get_keymap', function()
it('considers scope', function()
-- change the map slightly
command('nnoremap foo_longer bar_longer')
local foolong_bar_map_table = local_copy(foo_bar_map_table)
local foolong_bar_map_table = shallowcopy(foo_bar_map_table)
foolong_bar_map_table['lhs'] = 'foo_longer'
foolong_bar_map_table['rhs'] = 'bar_longer'
local buffer_table = local_copy(foo_bar_map_table)
local buffer_table = shallowcopy(foo_bar_map_table)
buffer_table['buffer'] = 1
command('nnoremap <buffer> foo bar')
@ -98,7 +93,7 @@ describe('get_keymap', function()
it('considers scope for overlapping maps', function()
command('nnoremap foo bar')
local buffer_table = local_copy(foo_bar_map_table)
local buffer_table = shallowcopy(foo_bar_map_table)
buffer_table['buffer'] = 1
command('nnoremap <buffer> foo bar')
@ -121,7 +116,7 @@ describe('get_keymap', function()
command('nnoremap <buffer> foo bar')
-- Final buffer will have buffer mappings
local buffer_table = local_copy(foo_bar_map_table)
local buffer_table = shallowcopy(foo_bar_map_table)
buffer_table['buffer'] = final_buffer
eq({buffer_table}, meths.buf_get_keymap(final_buffer, 'n'))
eq({buffer_table}, meths.buf_get_keymap(0, 'n'))
@ -243,4 +238,73 @@ describe('get_keymap', function()
eq('<F12>', meths.get_keymap('n')[1]['lhs'])
eq(':let g:maparg_test_var = 1<CR>', meths.get_keymap('n')[1]['rhs'])
end)
it('works correctly despite various &cpo settings', function()
local cpo_table = {
silent=0,
expr=0,
sid=0,
buffer=0,
nowait=0,
noremap=1,
}
local function cpomap(lhs, rhs, mode)
local ret = shallowcopy(cpo_table)
ret.lhs = lhs
ret.rhs = rhs
ret.mode = mode
return ret
end
command('set cpo+=B')
command('nnoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
command('nnoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
command('set cpo+=B')
command('xnoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
command('xnoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
command('set cpo-=B')
command('snoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
command('snoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
command('set cpo-=B')
command('onoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
command('onoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
for _, cmd in ipairs({
'set cpo-=B',
'set cpo+=B',
}) do
command(cmd)
eq({cpomap('\\<C-C><C-C><lt>C-c>\\', '\\<C-D><C-D><lt>C-d>\\', 'n'),
cpomap('\\<C-A><C-A><lt>C-a>\\', '\\<C-B><C-B><lt>C-b>\\', 'n')},
meths.get_keymap('n'))
eq({cpomap('\\<C-C><C-C><lt>C-c>\\', '\\<C-D><C-D><lt>C-d>\\', 'x'),
cpomap('\\<C-A><C-A><lt>C-a>\\', '\\<C-B><C-B><lt>C-b>\\', 'x')},
meths.get_keymap('x'))
eq({cpomap('<lt>C-c><C-C><lt>C-c> ', '<lt>C-d><C-D><lt>C-d>', 's'),
cpomap('<lt>C-a><C-A><lt>C-a> ', '<lt>C-b><C-B><lt>C-b>', 's')},
meths.get_keymap('s'))
eq({cpomap('<lt>C-c><C-C><lt>C-c> ', '<lt>C-d><C-D><lt>C-d>', 'o'),
cpomap('<lt>C-a><C-A><lt>C-a> ', '<lt>C-b><C-B><lt>C-b>', 'o')},
meths.get_keymap('o'))
end
end)
it('always uses space for space and bar for bar', function()
local space_table = {
lhs='| |',
rhs='| |',
mode='n',
silent=0,
expr=0,
sid=0,
buffer=0,
nowait=0,
noremap=1,
}
command('nnoremap \\|<Char-0x20><Char-32><Space><Bar> \\|<Char-0x20><Char-32><Space> <Bar>')
eq({space_table}, meths.get_keymap('n'))
end)
end)

View File

@ -282,8 +282,13 @@ describe('server -> client', function()
end)
end)
describe('when connecting to its own pipe adress', function()
it('it does not deadlock', function()
describe('connecting to its own pipe address', function()
it('does not deadlock', function()
if not os.getenv("TRAVIS") and helpers.os_name() == "osx" then
-- It does, in fact, deadlock on QuickBuild. #6851
pending("deadlocks on QuickBuild", function() end)
return
end
local address = funcs.serverlist()[1]
local first = string.sub(address,1,1)
ok(first == '/' or first == '\\')

View File

@ -327,11 +327,11 @@ describe('api', function()
{'nvim_get_mode', {}},
{'nvim_eval', {'1'}},
}
eq({{{mode='n', blocking=false},
13,
{mode='n', blocking=false}, -- TODO: should be blocked=true
1},
NIL}, meths.call_atomic(req))
eq({ { {mode='n', blocking=false},
13,
{mode='n', blocking=false}, -- TODO: should be blocked=true
1 },
NIL}, meths.call_atomic(req))
eq({mode='r', blocking=true}, nvim("get_mode"))
end)
-- TODO: bug #6166
@ -373,6 +373,11 @@ describe('api', function()
'<NL>x<Esc>x<CR>x<lt>x', true, true, true))
end)
it('does not convert keycodes if special=false', function()
eq('<NL>x<Esc>x<CR>x<lt>x', helpers.nvim('replace_termcodes',
'<NL>x<Esc>x<CR>x<lt>x', true, true, false))
end)
it('does not crash when transforming an empty string', function()
-- Actually does not test anything, because current code will use NULL for
-- an empty string.
@ -391,13 +396,13 @@ describe('api', function()
-- notice the special char(…) \xe2\80\xa6
nvim('feedkeys', ':let x1="…"\n', '', true)
-- Both replace_termcodes and feedkeys escape \x80
-- Both nvim_replace_termcodes and nvim_feedkeys escape \x80
local inp = helpers.nvim('replace_termcodes', ':let x2="…"<CR>', true, true, true)
nvim('feedkeys', inp, '', true)
nvim('feedkeys', inp, '', true) -- escape_csi=true
-- Disabling CSI escaping in feedkeys
-- nvim_feedkeys with CSI escaping disabled
inp = helpers.nvim('replace_termcodes', ':let x3="…"<CR>', true, true, true)
nvim('feedkeys', inp, '', false)
nvim('feedkeys', inp, '', false) -- escape_csi=false
helpers.stop()
end
@ -588,6 +593,36 @@ describe('api', function()
end)
end)
describe('list_runtime_paths', function()
it('returns nothing with empty &runtimepath', function()
meths.set_option('runtimepath', '')
eq({}, meths.list_runtime_paths())
end)
it('returns single runtimepath', function()
meths.set_option('runtimepath', 'a')
eq({'a'}, meths.list_runtime_paths())
end)
it('returns two runtimepaths', function()
meths.set_option('runtimepath', 'a,b')
eq({'a', 'b'}, meths.list_runtime_paths())
end)
it('returns empty strings when appropriate', function()
meths.set_option('runtimepath', 'a,,b')
eq({'a', '', 'b'}, meths.list_runtime_paths())
meths.set_option('runtimepath', ',a,b')
eq({'', 'a', 'b'}, meths.list_runtime_paths())
meths.set_option('runtimepath', 'a,b,')
eq({'a', 'b', ''}, meths.list_runtime_paths())
end)
it('truncates too long paths', function()
local long_path = ('/a'):rep(8192)
meths.set_option('runtimepath', long_path)
local paths_list = meths.list_runtime_paths()
neq({long_path}, paths_list)
eq({long_path:sub(1, #(paths_list[1]))}, paths_list)
end)
end)
it('can throw exceptions', function()
local status, err = pcall(nvim, 'get_option', 'invalid-option')
eq(false, status)

View File

@ -14,13 +14,52 @@ describe('TermClose event', function()
nvim('set_option', 'shellcmdflag', 'EXE')
end)
it('triggers when terminal job ends', function()
it('triggers when fast-exiting terminal job stops', function()
command('autocmd TermClose * let g:test_termclose = 23')
command('terminal')
command('call jobstop(b:terminal_job_id)')
retry(nil, nil, function() eq(23, eval('g:test_termclose')) end)
end)
it('triggers when long-running terminal job gets stopped', function()
nvim('set_option', 'shell', 'sh')
command('autocmd TermClose * let g:test_termclose = 23')
command('terminal')
command('call jobstop(b:terminal_job_id)')
retry(nil, nil, function() eq(23, eval('g:test_termclose')) end)
end)
it('kills job trapping SIGTERM', function()
nvim('set_option', 'shell', 'sh')
nvim('set_option', 'shellcmdflag', '-c')
command([[ let g:test_job = jobstart('trap "" TERM && echo 1 && sleep 60', { ]]
.. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]]
.. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]])
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_started", 0)')) end)
local start = os.time()
command('call jobstop(g:test_job)')
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end)
local duration = os.time() - start
eq(2, duration)
end)
it('kills pty job trapping SIGHUP and SIGTERM', function()
nvim('set_option', 'shell', 'sh')
nvim('set_option', 'shellcmdflag', '-c')
command([[ let g:test_job = jobstart('trap "" HUP TERM && echo 1 && sleep 60', { ]]
.. [[ 'pty': 1,]]
.. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]]
.. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]])
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_started", 0)')) end)
local start = os.time()
command('call jobstop(g:test_job)')
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end)
local duration = os.time() - start
eq(4, duration)
end)
it('reports the correct <abuf>', function()
command('set hidden')
command('autocmd TermClose * let g:abuf = expand("<abuf>")')

View File

@ -8,7 +8,7 @@ describe('hostname()', function()
it('returns hostname string', function()
local actual = call('hostname')
ok(string.len(actual) > 1)
ok(string.len(actual) > 0)
if call('executable', 'hostname') == 1 then
local expected = string.gsub(call('system', 'hostname'), '[\n\r]', '')
helpers.eq(expected, actual)

View File

@ -1,11 +1,12 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
local funcs = helpers.funcs
local nvim = helpers.nvim
local source = helpers.source
local command = helpers.command
describe('maparg()', function()
before_each(clear)
@ -117,4 +118,42 @@ describe('maparg()', function()
eq(1, map_dict['expr'])
eq('i', map_dict['mode'])
end)
it('works with combining characters', function()
-- Using addacutes to make combining character better visible
local function ac(s)
local acute = '\204\129' -- U+0301 COMBINING ACUTE ACCENT
local ret = s:gsub('`', acute)
return ret
end
command(ac([[
nnoremap a b`
nnoremap c` d
nnoremap e` f`
]]))
eq(ac('b`'), funcs.maparg(ac('a')))
eq(ac(''), funcs.maparg(ac('c')))
eq(ac('d'), funcs.maparg(ac('c`')))
eq(ac('f`'), funcs.maparg(ac('e`')))
local function acmap(lhs, rhs)
return {
lhs = ac(lhs),
rhs = ac(rhs),
buffer = 0,
expr = 0,
mode = 'n',
noremap = 1,
nowait = 0,
sid = 0,
silent = 0,
}
end
eq({}, funcs.maparg(ac('c'), 'n', 0, 1))
eq(acmap('a', 'b`'), funcs.maparg(ac('a'), 'n', 0, 1))
eq(acmap('c`', 'd'), funcs.maparg(ac('c`'), 'n', 0, 1))
eq(acmap('e`', 'f`'), funcs.maparg(ac('e`'), 'n', 0, 1))
end)
end)

View File

@ -0,0 +1,321 @@
local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local NIL = helpers.NIL
local eval = helpers.eval
local clear = helpers.clear
local meths = helpers.meths
local funcs = helpers.funcs
local source = helpers.source
local dedent = helpers.dedent
local command = helpers.command
local exc_exec = helpers.exc_exec
local redir_exec = helpers.redir_exec
describe(':echo', function()
before_each(function()
clear()
source([[
function String(s)
return execute('echo a:s')[1:]
endfunction
]])
end)
describe('used to represent floating-point values', function()
it('dumps NaN values', function()
eq('str2float(\'nan\')', eval('String(str2float(\'nan\'))'))
end)
it('dumps infinite values', function()
eq('str2float(\'inf\')', eval('String(str2float(\'inf\'))'))
eq('-str2float(\'inf\')', eval('String(str2float(\'-inf\'))'))
end)
it('dumps regular values', function()
eq('1.5', funcs.String(1.5))
eq('1.56e-20', funcs.String(1.56000e-020))
eq('0.0', eval('String(0.0)'))
end)
it('dumps special v: values', function()
eq('v:true', eval('String(v:true)'))
eq('v:false', eval('String(v:false)'))
eq('v:null', eval('String(v:null)'))
eq('v:true', funcs.String(true))
eq('v:false', funcs.String(false))
eq('v:null', funcs.String(NIL))
end)
it('dumps values with at most six digits after the decimal point',
function()
eq('1.234568e-20', funcs.String(1.23456789123456789123456789e-020))
eq('1.234568', funcs.String(1.23456789123456789123456789))
end)
it('dumps values with at most seven digits before the decimal point',
function()
eq('1234567.891235', funcs.String(1234567.89123456789123456789))
eq('1.234568e7', funcs.String(12345678.9123456789123456789))
end)
it('dumps negative values', function()
eq('-1.5', funcs.String(-1.5))
eq('-1.56e-20', funcs.String(-1.56000e-020))
eq('-1.234568e-20', funcs.String(-1.23456789123456789123456789e-020))
eq('-1.234568', funcs.String(-1.23456789123456789123456789))
eq('-1234567.891235', funcs.String(-1234567.89123456789123456789))
eq('-1.234568e7', funcs.String(-12345678.9123456789123456789))
end)
end)
describe('used to represent numbers', function()
it('dumps regular values', function()
eq('0', funcs.String(0))
eq('-1', funcs.String(-1))
eq('1', funcs.String(1))
end)
it('dumps large values', function()
eq('2147483647', funcs.String(2^31-1))
eq('-2147483648', funcs.String(-2^31))
end)
end)
describe('used to represent strings', function()
it('dumps regular strings', function()
eq('test', funcs.String('test'))
end)
it('dumps empty strings', function()
eq('', funcs.String(''))
end)
it('dumps strings with \' inside', function()
eq('\'\'\'', funcs.String('\'\'\''))
eq('a\'b\'\'', funcs.String('a\'b\'\''))
eq('\'b\'\'d', funcs.String('\'b\'\'d'))
eq('a\'b\'c\'d', funcs.String('a\'b\'c\'d'))
end)
it('dumps NULL strings', function()
eq('', eval('String($XXX_UNEXISTENT_VAR_XXX)'))
end)
it('dumps NULL lists', function()
eq('[]', eval('String(v:_null_list)'))
end)
it('dumps NULL dictionaries', function()
eq('{}', eval('String(v:_null_dict)'))
end)
end)
describe('used to represent funcrefs', function()
before_each(function()
source([[
function Test1()
endfunction
function s:Test2() dict
endfunction
function g:Test3() dict
endfunction
let g:Test2_f = function('s:Test2')
]])
end)
it('dumps references to built-in functions', function()
eq('function', eval('String(function("function"))'))
end)
it('dumps references to user functions', function()
eq('Test1', eval('String(function("Test1"))'))
eq('g:Test3', eval('String(function("g:Test3"))'))
end)
it('dumps references to script functions', function()
eq('<SNR>2_Test2', eval('String(Test2_f)'))
end)
it('dumps partials with self referencing a partial', function()
source([[
function TestDict() dict
endfunction
let d = {}
let TestDictRef = function('TestDict', d)
let d.tdr = TestDictRef
]])
eq(dedent([[
function('TestDict', {'tdr': function('TestDict', {...@1})})
function('TestDict', {'tdr': function('TestDict', {...@1})})]]),
redir_exec('echo String(d.tdr)'))
end)
it('dumps automatically created partials', function()
eq('function(\'<SNR>2_Test2\', {\'f\': function(\'<SNR>2_Test2\')})',
eval('String({"f": Test2_f}.f)'))
eq('function(\'<SNR>2_Test2\', [1], {\'f\': function(\'<SNR>2_Test2\', [1])})',
eval('String({"f": function(Test2_f, [1])}.f)'))
end)
it('dumps manually created partials', function()
eq('function(\'Test3\', [1, 2], {})',
eval('String(function("Test3", [1, 2], {}))'))
eq('function(\'Test3\', {})',
eval('String(function("Test3", {}))'))
eq('function(\'Test3\', [1, 2])',
eval('String(function("Test3", [1, 2]))'))
end)
it('does not crash or halt when dumping partials with reference cycles in self',
function()
meths.set_var('d', {v=true})
eq(dedent([[
{'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}
{'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]]),
redir_exec('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
end)
it('does not show errors when dumping partials referencing the same dictionary',
function()
command('let d = {}')
-- Regression for “eval/typval_encode: Dump empty dictionary before
-- checking for refcycle”, results in error.
eq('[function(\'tr\', {}), function(\'tr\', {})]', eval('String([function("tr", d), function("tr", d)])'))
-- Regression for “eval: Work with reference cycles in partials (self)
-- properly”, results in crash.
eval('extend(d, {"a": 1})')
eq('[function(\'tr\', {\'a\': 1}), function(\'tr\', {\'a\': 1})]', eval('String([function("tr", d), function("tr", d)])'))
end)
it('does not crash or halt when dumping partials with reference cycles in arguments',
function()
meths.set_var('l', {})
eval('add(l, l)')
-- Regression: the below line used to crash (add returns original list and
-- there was error in dumping partials). Tested explicitly in
-- test/unit/api/private_helpers_spec.lua.
eval('add(l, function("Test1", l))')
eq(dedent([=[
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])]=]),
redir_exec('echo String(function("Test1", l))'))
end)
it('does not crash or halt when dumping partials with reference cycles in self and arguments',
function()
meths.set_var('d', {v=true})
meths.set_var('l', {})
eval('add(l, l)')
eval('add(l, function("Test1", l))')
eval('add(l, function("Test1", d))')
eq(dedent([=[
{'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}
{'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]=]),
redir_exec('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
end)
end)
describe('used to represent lists', function()
it('dumps empty list', function()
eq('[]', funcs.String({}))
end)
it('dumps nested lists', function()
eq('[[[[[]]]]]', funcs.String({{{{{}}}}}))
end)
it('dumps nested non-empty lists', function()
eq('[1, [[3, [[5], 4]], 2]]', funcs.String({1, {{3, {{5}, 4}}, 2}}))
end)
it('does not error when dumping recursive lists', function()
meths.set_var('l', {})
eval('add(l, l)')
eq(0, exc_exec('echo String(l)'))
end)
it('dumps recursive lists without error', function()
meths.set_var('l', {})
eval('add(l, l)')
eq('\n[[...@0]]\n[[...@0]]', redir_exec('echo String(l)'))
eq('\n[[[...@1]]]\n[[[...@1]]]', redir_exec('echo String([l])'))
end)
end)
describe('used to represent dictionaries', function()
it('dumps empty dictionary', function()
eq('{}', eval('String({})'))
end)
it('dumps list with two same empty dictionaries, also in partials', function()
command('let d = {}')
eq('[{}, {}]', eval('String([d, d])'))
eq('[function(\'tr\', {}), {}]', eval('String([function("tr", d), d])'))
eq('[{}, function(\'tr\', {})]', eval('String([d, function("tr", d)])'))
end)
it('dumps non-empty dictionary', function()
eq('{\'t\'\'est\': 1}', funcs.String({['t\'est']=1}))
end)
it('does not error when dumping recursive dictionaries', function()
meths.set_var('d', {d=1})
eval('extend(d, {"d": d})')
eq(0, exc_exec('echo String(d)'))
end)
it('dumps recursive dictionaries without the error', function()
meths.set_var('d', {d=1})
eval('extend(d, {"d": d})')
eq('\n{\'d\': {...@0}}\n{\'d\': {...@0}}',
redir_exec('echo String(d)'))
eq('\n{\'out\': {\'d\': {...@1}}}\n{\'out\': {\'d\': {...@1}}}',
redir_exec('echo String({"out": d})'))
end)
end)
describe('used to represent special values', function()
local function chr(n)
return ('%c'):format(n)
end
local function ctrl(c)
return ('%c'):format(c:upper():byte() - 0x40)
end
it('displays hex as hex', function()
-- Regression: due to missing (uint8_t) cast \x80 was represented as
-- ~@<80>.
eq('<80>', funcs.String(chr(0x80)))
eq('<81>', funcs.String(chr(0x81)))
eq('<8e>', funcs.String(chr(0x8e)))
eq('<c2>', funcs.String(('«'):sub(1, 1)))
eq('«', funcs.String(('«'):sub(1, 2)))
end)
it('displays ASCII control characters using ^X notation', function()
eq('^C', funcs.String(ctrl('c')))
eq('^A', funcs.String(ctrl('a')))
eq('^F', funcs.String(ctrl('f')))
end)
it('prints CR, NL and tab as-is', function()
eq('\n', funcs.String('\n'))
eq('\r', funcs.String('\r'))
eq('\t', funcs.String('\t'))
end)
it('prints non-printable UTF-8 in <> notation', function()
-- SINGLE SHIFT TWO, unicode control
eq('<8e>', funcs.String(funcs.nr2char(0x8E)))
-- Surrogate pair: U+1F0A0 PLAYING CARD BACK is represented in UTF-16 as
-- 0xD83C 0xDCA0. This is not valid in UTF-8.
eq('<d83c>', funcs.String(funcs.nr2char(0xD83C)))
eq('<dca0>', funcs.String(funcs.nr2char(0xDCA0)))
eq('<d83c><dca0>', funcs.String(funcs.nr2char(0xD83C) .. funcs.nr2char(0xDCA0)))
end)
end)
end)

File diff suppressed because one or more lines are too long

View File

@ -319,7 +319,14 @@ end
-- Dedent the given text and write it to the file name.
local function write_file(name, text, dont_dedent)
local file = io.open(name, 'w')
if not dont_dedent then
if type(text) == 'table' then
-- Byte blob
local bytes = text
text = ''
for _, char in ipairs(bytes) do
text = ('%s%c'):format(text, char)
end
elseif not dont_dedent then
text = dedent(text)
end
file:write(text)
@ -337,11 +344,23 @@ local function read_file(name)
return ret
end
local sourced_fnames = {}
local function source(code)
local fname = tmpname()
write_file(fname, code)
nvim_command('source '..fname)
os.remove(fname)
-- DO NOT REMOVE FILE HERE.
-- do_source() has a habit of checking whether files are “same” by using inode
-- and device IDs. If you run two source() calls in quick succession there is
-- a good chance that underlying filesystem will reuse the inode, making files
-- appear as “symlinks” to do_source when it checks FileIDs. With current
-- setup linux machines (both QB, travis and mine(ZyX-I) with XFS) do reuse
-- inodes, Mac OS machines (again, both QB and travis) do not.
--
-- Files appearing as “symlinks” mean that both the first and the second
-- source() calls will use same SID, which may fail some tests which check for
-- exact numbers after `<SNR>` in e.g. function names.
sourced_fnames[#sourced_fnames + 1] = fname
return fname
end
@ -581,6 +600,24 @@ local function missing_provider(provider)
end
end
local function alter_slashes(obj)
if not iswin() then
return obj
end
if type(obj) == 'string' then
local ret = obj:gsub('/', '\\')
return ret
elseif type(obj) == 'table' then
local ret = {}
for k, v in pairs(obj) do
ret[k] = alter_slashes(v)
end
return ret
else
assert(false, 'Could only alter slashes for tables of strings and strings')
end
end
local module = {
prepend_argv = prepend_argv,
clear = clear,
@ -649,11 +686,15 @@ local module = {
NIL = mpack.NIL,
get_pathsep = get_pathsep,
missing_provider = missing_provider,
alter_slashes = alter_slashes,
}
return function(after_each)
if after_each then
after_each(function()
for _, fname in ipairs(sourced_fnames) do
os.remove(fname)
end
check_logs()
check_cores('build/bin/nvim')
end)

View File

@ -0,0 +1,43 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
local expect = helpers.expect
local feed = helpers.feed
local insert = helpers.insert
describe('insert-mode Ctrl-O', function()
before_each(clear)
it('enters command mode for one command', function()
feed('ihello world<C-o>')
feed(':let ctrlo = "test"<CR>')
feed('iii')
expect('hello worldiii')
eq(1, eval('ctrlo ==# "test"'))
end)
it('re-enters insert mode at the end of the line when running startinsert', function()
-- #6962
feed('ihello world<C-o>')
feed(':startinsert<CR>')
feed('iii')
expect('hello worldiii')
end)
it('re-enters insert mode at the beginning of the line when running startinsert', function()
insert('hello world')
feed('0<C-o>')
feed(':startinsert<CR>')
feed('aaa')
expect('aaahello world')
end)
it('re-enters insert mode in the middle of the line when running startinsert', function()
insert('hello world')
feed('bi<C-o>')
feed(':startinsert<CR>')
feed('ooo')
expect('hello oooworld')
end)
end)

View File

@ -0,0 +1,474 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
local funcs = helpers.funcs
describe('search cmdline', function()
local screen
before_each(function()
clear()
command('set nohlsearch')
screen = Screen.new(20, 3)
screen:attach()
screen:set_default_attr_ids({
inc = {reverse = true}
})
end)
local function tenlines()
funcs.setline(1, {
' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there',
' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar'
})
command('1')
end
it('history can be navigated with <C-N>/<C-P>', function()
tenlines()
command('set noincsearch')
feed('/foobar<CR>')
feed('/the<CR>')
eq('the', eval('@/'))
feed('/thes<C-P><C-P><CR>')
eq('foobar', eval('@/'))
end)
describe('can traverse matches', function()
before_each(tenlines)
local function forwarditer(wrapscan)
command('set incsearch '..wrapscan)
feed('/the')
screen:expect([[
1 |
2 {inc:the}se |
/the^ |
]])
feed('<C-G>')
screen:expect([[
2 these |
3 {inc:the} |
/the^ |
]])
eq({0, 0, 0, 0}, funcs.getpos('"'))
feed('<C-G>')
screen:expect([[
3 the |
4 {inc:the}ir |
/the^ |
]])
feed('<C-G>')
screen:expect([[
4 their |
5 {inc:the}re |
/the^ |
]])
feed('<C-G>')
screen:expect([[
5 there |
6 {inc:the}ir |
/the^ |
]])
feed('<C-G>')
screen:expect([[
6 their |
7 {inc:the} |
/the^ |
]])
feed('<C-G>')
screen:expect([[
7 the |
8 {inc:the}m |
/the^ |
]])
feed('<C-G>')
screen:expect([[
8 them |
9 {inc:the}se |
/the^ |
]])
feed('<C-G>')
if wrapscan == 'wrapscan' then
screen:expect([[
2 {inc:the}se |
3 the |
/the^ |
]])
else
screen:expect([[
8 them |
9 {inc:the}se |
/the^ |
]])
feed('<CR>')
eq({0, 0, 0, 0}, funcs.getpos('"'))
end
end
local function backiter(wrapscan)
command('set incsearch '..wrapscan)
command('$')
feed('?the')
screen:expect([[
9 {inc:the}se |
10 foobar |
?the^ |
]])
if wrapscan == 'wrapscan' then
feed('<C-G>')
screen:expect([[
2 {inc:the}se |
3 the |
?the^ |
]])
feed('<CR>')
screen:expect([[
2 ^these |
3 the |
?the |
]])
else
feed('<C-G>')
screen:expect([[
9 {inc:the}se |
10 foobar |
?the^ |
]])
feed('<CR>')
screen:expect([[
9 ^these |
10 foobar |
?the |
]])
end
command('$')
feed('?the')
screen:expect([[
9 {inc:the}se |
10 foobar |
?the^ |
]])
feed('<C-T>')
screen:expect([[
8 {inc:the}m |
9 these |
?the^ |
]])
for i = 1, 6 do
feed('<C-T>')
-- Avoid sleep just before expect, otherwise expect will take the full
-- timeout
if i ~= 6 then
screen:sleep(1)
end
end
screen:expect([[
2 {inc:the}se |
3 the |
?the^ |
]])
feed('<C-T>')
if wrapscan == 'wrapscan' then
screen:expect([[
9 {inc:the}se |
10 foobar |
?the^ |
]])
else
screen:expect([[
2 {inc:the}se |
3 the |
?the^ |
]])
end
end
it("using <C-G> and 'nowrapscan'", function()
forwarditer('nowrapscan')
end)
it("using <C-G> and 'wrapscan'", function()
forwarditer('wrapscan')
end)
it("using <C-T> and 'nowrapscan'", function()
backiter('nowrapscan')
end)
it("using <C-T> and 'wrapscan'", function()
backiter('wrapscan')
end)
end)
it('expands pattern with <C-L>', function()
tenlines()
command('set incsearch wrapscan')
feed('/the')
screen:expect([[
1 |
2 {inc:the}se |
/the^ |
]])
feed('<C-L>')
screen:expect([[
1 |
2 {inc:thes}e |
/thes^ |
]])
feed('<C-G>')
screen:expect([[
9 {inc:thes}e |
10 foobar |
/thes^ |
]])
feed('<C-G>')
screen:expect([[
2 {inc:thes}e |
3 the |
/thes^ |
]])
feed('<CR>')
screen:expect([[
2 ^these |
3 the |
/thes |
]])
command('1')
command('set nowrapscan')
feed('/the')
screen:expect([[
1 |
2 {inc:the}se |
/the^ |
]])
feed('<C-L>')
screen:expect([[
1 |
2 {inc:thes}e |
/thes^ |
]])
feed('<C-G>')
screen:expect([[
9 {inc:thes}e |
10 foobar |
/thes^ |
]])
feed('<C-G><CR>')
screen:expect([[
9 ^these |
10 foobar |
/thes |
]])
end)
it('reduces pattern with <BS> and keeps cursor position', function()
tenlines()
command('set incsearch wrapscan')
-- First match
feed('/thei')
screen:expect([[
4 {inc:thei}r |
5 there |
/thei^ |
]])
-- Match from initial cursor position when modifying search
feed('<BS>')
screen:expect([[
1 |
2 {inc:the}se |
/the^ |
]])
-- New text advances to next match
feed('s')
screen:expect([[
1 |
2 {inc:thes}e |
/thes^ |
]])
-- Stay on this match when deleting a character
feed('<BS>')
screen:expect([[
1 |
2 {inc:the}se |
/the^ |
]])
-- Advance to previous match
feed('<C-T>')
screen:expect([[
9 {inc:the}se |
10 foobar |
/the^ |
]])
-- Extend search to include next character
feed('<C-L>')
screen:expect([[
9 {inc:thes}e |
10 foobar |
/thes^ |
]])
-- Deleting all characters resets the cursor position
feed('<BS><BS><BS><BS>')
screen:expect([[
1 |
2 these |
/^ |
]])
feed('the')
screen:expect([[
1 |
2 {inc:the}se |
/the^ |
]])
feed('\\>')
screen:expect([[
2 these |
3 {inc:the} |
/the\>^ |
]])
end)
it('can traverse matches in the same line with <C-G>/<C-T>', function()
funcs.setline(1, { ' 1', ' 2 these', ' 3 the theother' })
command('1')
command('set incsearch')
-- First match
feed('/the')
screen:expect([[
1 |
2 {inc:the}se |
/the^ |
]])
-- Next match, different line
feed('<C-G>')
screen:expect([[
2 these |
3 {inc:the} theother |
/the^ |
]])
-- Next match, same line
feed('<C-G>')
screen:expect([[
2 these |
3 the {inc:the}other |
/the^ |
]])
feed('<C-G>')
screen:expect([[
2 these |
3 the theo{inc:the}r |
/the^ |
]])
-- Previous match, same line
feed('<C-T>')
screen:expect([[
2 these |
3 the {inc:the}other |
/the^ |
]])
feed('<C-T>')
screen:expect([[
2 these |
3 {inc:the} theother |
/the^ |
]])
-- Previous match, different line
feed('<C-T>')
screen:expect([[
2 {inc:the}se |
3 the theother |
/the^ |
]])
end)
it('keeps the view after deleting a char from the search', function()
screen:detach()
screen = Screen.new(20, 6)
screen:attach()
screen:set_default_attr_ids({
inc = {reverse = true}
})
screen:set_default_attr_ignore({
{bold=true, reverse=true}, {bold=true, foreground=Screen.colors.Blue1}
})
tenlines()
feed('/foo')
screen:expect([[
6 their |
7 the |
8 them |
9 these |
10 {inc:foo}bar |
/foo^ |
]])
feed('<BS>')
screen:expect([[
6 their |
7 the |
8 them |
9 these |
10 {inc:fo}obar |
/fo^ |
]])
feed('<CR>')
screen:expect([[
6 their |
7 the |
8 them |
9 these |
10 ^foobar |
/fo |
]])
eq({lnum = 10, leftcol = 0, col = 4, topfill = 0, topline = 6,
coladd = 0, skipcol = 0, curswant = 4},
funcs.winsaveview())
end)
it('restores original view after failed search', function()
screen:detach()
screen = Screen.new(40, 3)
screen:attach()
screen:set_default_attr_ids({
inc = {reverse = true},
err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
more = { bold = true, foreground = Screen.colors.SeaGreen4 },
})
tenlines()
feed('0')
feed('/foo')
screen:expect([[
9 these |
10 {inc:foo}bar |
/foo^ |
]])
feed('<C-W>')
screen:expect([[
1 |
2 these |
/^ |
]])
feed('<CR>')
screen:expect([[
/ |
{err:E35: No previous regular expression} |
{more:Press ENTER or type command to continue}^ |
]])
feed('<CR>')
eq({lnum = 1, leftcol = 0, col = 0, topfill = 0, topline = 1,
coladd = 0, skipcol = 0, curswant = 0},
funcs.winsaveview())
end)
end)

View File

@ -3,14 +3,17 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
local neq = helpers.neq
local NIL = helpers.NIL
local feed = helpers.feed
local clear = helpers.clear
local funcs = helpers.funcs
local meths = helpers.meths
local iswin = helpers.iswin
local command = helpers.command
local write_file = helpers.write_file
local redir_exec = helpers.redir_exec
local alter_slashes = helpers.alter_slashes
local screen
@ -173,3 +176,119 @@ describe('debug.debug', function()
]])
end)
end)
describe('package.path/package.cpath', function()
local sl = alter_slashes
local function get_new_paths(sufs, runtimepaths)
runtimepaths = runtimepaths or meths.list_runtime_paths()
local new_paths = {}
local sep = package.config:sub(1, 1)
for _, v in ipairs(runtimepaths) do
for _, suf in ipairs(sufs) do
new_paths[#new_paths + 1] = v .. sep .. 'lua' .. suf
end
end
return new_paths
end
local function execute_lua(cmd, ...)
return meths.execute_lua(cmd, {...})
end
local function eval_lua(expr, ...)
return meths.execute_lua('return ' .. expr, {...})
end
local function set_path(which, value)
return execute_lua('package[select(1, ...)] = select(2, ...)', which, value)
end
it('contains directories from &runtimepath on first invocation', function()
local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'})
local new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
local new_cpaths = get_new_paths(iswin() and {'\\?.dll'} or {'/?.so'})
local new_cpaths_str = table.concat(new_cpaths, ';')
eq(new_cpaths_str, eval_lua('package.cpath'):sub(1, #new_cpaths_str))
end)
it('puts directories from &runtimepath always at the start', function()
meths.set_option('runtimepath', 'a,b')
local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {'a', 'b'})
local new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
set_path('path', sl'foo/?.lua;foo/?/init.lua;' .. new_paths_str)
neq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
command('set runtimepath+=c')
new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {'a', 'b', 'c'})
new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
end)
it('understands uncommon suffixes', function()
set_path('cpath', './?/foo/bar/baz/x.nlua')
meths.set_option('runtimepath', 'a')
local new_paths = get_new_paths({'/?/foo/bar/baz/x.nlua'}, {'a'})
local new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str, eval_lua('package.cpath'):sub(1, #new_paths_str))
set_path('cpath', './yyy?zzz/x')
meths.set_option('runtimepath', 'b')
new_paths = get_new_paths({'/yyy?zzz/x'}, {'b'})
new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str, eval_lua('package.cpath'):sub(1, #new_paths_str))
set_path('cpath', './yyy?zzz/123?ghi/x')
meths.set_option('runtimepath', 'b')
new_paths = get_new_paths({'/yyy?zzz/123?ghi/x'}, {'b'})
new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str, eval_lua('package.cpath'):sub(1, #new_paths_str))
end)
it('preserves empty items', function()
local many_empty_path = ';;;;;;'
local many_empty_cpath = ';;;;;;./?.luaso'
set_path('path', many_empty_path)
set_path('cpath', many_empty_cpath)
meths.set_option('runtimepath', 'a')
local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {'a'})
local new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str .. ';' .. many_empty_path, eval_lua('package.path'))
local new_cpaths = get_new_paths({'/?.luaso'}, {'a'})
local new_cpaths_str = table.concat(new_cpaths, ';')
eq(new_cpaths_str .. ';' .. many_empty_cpath, eval_lua('package.cpath'))
end)
it('preserves empty value', function()
set_path('path', '')
meths.set_option('runtimepath', 'a')
local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {'a'})
local new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str .. ';', eval_lua('package.path'))
end)
it('purges out all additions if runtimepath is set to empty', function()
local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'})
local new_paths_str = table.concat(new_paths, ';')
local path = eval_lua('package.path')
eq(new_paths_str, path:sub(1, #new_paths_str))
local new_cpaths = get_new_paths(iswin() and {'\\?.dll'} or {'/?.so'})
local new_cpaths_str = table.concat(new_cpaths, ';')
local cpath = eval_lua('package.cpath')
eq(new_cpaths_str, cpath:sub(1, #new_cpaths_str))
meths.set_option('runtimepath', '')
eq(path:sub(#new_paths_str + 2, -1), eval_lua('package.path'))
eq(cpath:sub(#new_cpaths_str + 2, -1), eval_lua('package.cpath'))
end)
it('works with paths with escaped commas', function()
meths.set_option('runtimepath', '\\,')
local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {','})
local new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
end)
it('ignores paths with semicolons', function()
meths.set_option('runtimepath', 'foo;bar,\\,')
local new_paths = get_new_paths(sl{'/?.lua', '/?/init.lua'}, {','})
local new_paths_str = table.concat(new_paths, ';')
eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str))
end)
end)

View File

@ -70,7 +70,7 @@ describe('health.vim', function()
health#broken#check
========================================================================
- ERROR: Failed to run healthcheck for "broken" plugin. Exception:
function health#check[20]..health#broken#check, line 1
function health#check[21]..health#broken#check, line 1
caused an error
]])
end)

Some files were not shown because too many files have changed in this diff Show More