mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge branch 'master' into colored-cmdline
This commit is contained in:
commit
69719e658c
@ -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")
|
||||
|
@ -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
|
||||
|
||||
|
7
Makefile
7
Makefile
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
22
cmake/RunLuacheck.cmake
Normal 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()
|
@ -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()
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 it’s 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}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
>
|
||||
|
@ -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: >
|
||||
|
@ -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
|
||||
|
@ -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*
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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*
|
||||
|
@ -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 ...
|
||||
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*
|
||||
|
@ -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.
|
||||
|
@ -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 other’s 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'
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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*
|
||||
|
@ -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('%')
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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")"
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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; \
|
||||
} \
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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(®match, 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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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,15 +1409,17 @@ 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)) {
|
||||
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)) {
|
||||
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)
|
||||
@ -1278,6 +1431,7 @@ static int command_line_handle_key(CommandLineState *s)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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 : '\\');
|
||||
}
|
||||
|
||||
|
@ -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,9 +815,8 @@ 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
|
||||
// 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)
|
||||
@ -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".
|
||||
|
@ -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) \
|
||||
#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))
|
||||
: FLAG_CPO_BSLASH)
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "keymap.h.generated.h"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -1739,53 +1739,56 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
// 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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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,16 +6180,17 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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<>[],~"
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -1433,12 +1433,10 @@ spell_move_to (
|
||||
// the cursor.
|
||||
if (dir == BACKWARD
|
||||
|| lnum != wp->w_cursor.lnum
|
||||
|| (lnum == wp->w_cursor.lnum
|
||||
&& (wrapped
|
||||
|| wrapped
|
||||
|| ((colnr_T)(curline
|
||||
? p - buf + (ptrdiff_t)len
|
||||
: p - buf)
|
||||
> wp->w_cursor.col)))) {
|
||||
: 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) {
|
||||
|
@ -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,8 +2169,9 @@ 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)
|
||||
{
|
||||
stateitem_T *cur_si;
|
||||
synpat_T *spp;
|
||||
int save_flags;
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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 \
|
||||
|
@ -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)
|
||||
|
@ -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 @/ = ''
|
||||
|
@ -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.
|
||||
|
64
src/nvim/testdir/test_startup_utf8.vim
Normal file
64
src/nvim/testdir/test_startup_utf8.vim
Normal 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
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
10
src/nvim/tui/terminfo.h
Normal 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
2846
src/nvim/version.c
2846
src/nvim/version.c
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
@ -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)
|
||||
|
@ -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 == '\\')
|
||||
|
@ -327,10 +327,10 @@ describe('api', function()
|
||||
{'nvim_get_mode', {}},
|
||||
{'nvim_eval', {'1'}},
|
||||
}
|
||||
eq({{{mode='n', blocking=false},
|
||||
eq({ { {mode='n', blocking=false},
|
||||
13,
|
||||
{mode='n', blocking=false}, -- TODO: should be blocked=true
|
||||
1},
|
||||
1 },
|
||||
NIL}, meths.call_atomic(req))
|
||||
eq({mode='r', blocking=true}, nvim("get_mode"))
|
||||
end)
|
||||
@ -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)
|
||||
|
@ -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>")')
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
321
test/functional/ex_cmds/echo_spec.lua
Normal file
321
test/functional/ex_cmds/echo_spec.lua
Normal 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)
|
593
test/functional/fixtures/bigfile_oneline.txt
Normal file
593
test/functional/fixtures/bigfile_oneline.txt
Normal file
File diff suppressed because one or more lines are too long
@ -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)
|
||||
|
43
test/functional/insert/ctrl_o_spec.lua
Normal file
43
test/functional/insert/ctrl_o_spec.lua
Normal 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)
|
474
test/functional/legacy/search_spec.lua
Normal file
474
test/functional/legacy/search_spec.lua
Normal 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)
|
@ -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)
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user