mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge branch 'master' into expression-parser
This commit is contained in:
commit
76f0466536
@ -7,6 +7,10 @@ end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf_8
|
||||
|
||||
[runtime/doc/*.txt]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
tab_width = 4
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
# Build/deps dir
|
||||
/build/
|
||||
/cmake-build-debug/
|
||||
/dist/
|
||||
/.deps/
|
||||
/tmp/
|
||||
|
4
BSDmakefile
Normal file
4
BSDmakefile
Normal file
@ -0,0 +1,4 @@
|
||||
.DONE:
|
||||
@echo "Please use GNU Make (gmake) to build neovim"
|
||||
.DEFAULT:
|
||||
@echo "Please use GNU Make (gmake) to build neovim"
|
@ -254,7 +254,10 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.5")
|
||||
# Array-bounds testing is broken in some GCC versions before 4.8.5.
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273
|
||||
add_definitions(-Wno-array-bounds)
|
||||
check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG)
|
||||
if(HAS_NO_ARRAY_BOUNDS_FLAG)
|
||||
add_definitions(-Wno-array-bounds)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -344,6 +347,21 @@ if(FEAT_TUI)
|
||||
find_package(Unibilium REQUIRED)
|
||||
include_directories(SYSTEM ${UNIBILIUM_INCLUDE_DIRS})
|
||||
|
||||
list(APPEND CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}")
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}")
|
||||
check_c_source_compiles("
|
||||
#include <unibilium.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
return unibi_num_from_var(unibi_var_from_num(0));
|
||||
}
|
||||
" UNIBI_HAS_VAR_FROM)
|
||||
if(UNIBI_HAS_VAR_FROM)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNVIM_UNIBI_HAS_VAR_FROM")
|
||||
endif()
|
||||
|
||||
find_package(LibTermkey REQUIRED)
|
||||
include_directories(SYSTEM ${LIBTERMKEY_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
27
README.md
27
README.md
@ -48,17 +48,24 @@ and [more](https://github.com/neovim/neovim/wiki/Installing-Neovim)!
|
||||
Project layout
|
||||
--------------
|
||||
|
||||
├─ ci/ Build server scripts
|
||||
├─ cmake/ Build scripts
|
||||
├─ runtime/ User plugins/docs
|
||||
├─ src/ Source code
|
||||
├─ third-party/ CMake subproject to build dependencies
|
||||
└─ test/ Test code
|
||||
├─ ci/ build automation
|
||||
├─ cmake/ build scripts
|
||||
├─ runtime/ user plugins/docs
|
||||
├─ src/ application source code (see src/nvim/README.md)
|
||||
│ ├─ api/ API subsystem
|
||||
│ ├─ eval/ VimL subsystem
|
||||
│ ├─ event/ event-loop subsystem
|
||||
│ ├─ generators/ code generation (pre-compilation)
|
||||
│ ├─ lib/ generic data structures
|
||||
│ ├─ lua/ lua subsystem
|
||||
│ ├─ msgpack_rpc/ RPC subsystem
|
||||
│ ├─ os/ low-level platform code
|
||||
│ └─ tui/ built-in UI
|
||||
├─ third-party/ cmake subproject to build dependencies
|
||||
└─ test/ tests (see test/README.md)
|
||||
|
||||
- `third-party/` is activated if `USE_BUNDLED_DEPS` is undefined or the
|
||||
`USE_BUNDLED` CMake option is true.
|
||||
- [Source README](src/nvim/README.md)
|
||||
- [Test README](test/README.md)
|
||||
- To disable `third-party/` specify `USE_BUNDLED_DEPS=NO` or `USE_BUNDLED=NO`
|
||||
(CMake option).
|
||||
|
||||
Features
|
||||
--------
|
||||
|
@ -1,4 +1,6 @@
|
||||
version: '{build}'
|
||||
environment:
|
||||
APPVEYOR_CACHE_ENTRY_ZIP_ARGS: "-t7z -m0=lzma -mx=9"
|
||||
configuration:
|
||||
- MINGW_64
|
||||
- MINGW_32
|
||||
|
@ -11,6 +11,18 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
|
||||
brew update
|
||||
fi
|
||||
|
||||
echo 'python info:'
|
||||
(
|
||||
2>&1 python --version || true
|
||||
2>&1 python2 --version || true
|
||||
2>&1 python3 --version || true
|
||||
2>&1 pip --version || true
|
||||
2>&1 pip2 --version || true
|
||||
2>&1 pip3 --version || true
|
||||
echo 'pyenv versions:'
|
||||
2>&1 pyenv versions || true
|
||||
) | sed 's/^/ /'
|
||||
|
||||
echo "Upgrade Python 2 pip."
|
||||
pip2.7 -q install --user --upgrade pip
|
||||
|
||||
@ -21,5 +33,7 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
|
||||
pip3 -q install --user --upgrade pip
|
||||
else
|
||||
echo "Upgrade Python 3 pip."
|
||||
pip3 -q install --user --upgrade pip
|
||||
# Allow failure. pyenv pip3 on travis is broken:
|
||||
# https://github.com/travis-ci/travis-ci/issues/8363
|
||||
pip3 -q install --user --upgrade pip || true
|
||||
fi
|
||||
|
@ -17,7 +17,9 @@ echo "Install neovim module and coveralls for Python 2."
|
||||
CC=cc pip2.7 -q install --user --upgrade neovim cpp-coveralls
|
||||
|
||||
echo "Install neovim module for Python 3."
|
||||
CC=cc pip3 -q install --user --upgrade neovim
|
||||
# Allow failure. pyenv pip3 on travis is broken:
|
||||
# https://github.com/travis-ci/travis-ci/issues/8363
|
||||
CC=cc pip3 -q install --user --upgrade neovim || true
|
||||
|
||||
echo "Install neovim RubyGem."
|
||||
gem install --no-document --version ">= 0.2.0" neovim
|
||||
|
@ -46,6 +46,7 @@ check_c_source_compiles("
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gettext(\"foo\");
|
||||
ngettext(\"foo\", \"bar\", 1);
|
||||
bindtextdomain(\"foo\", \"bar\");
|
||||
bind_textdomain_codeset(\"foo\", \"bar\");
|
||||
textdomain(\"foo\");
|
||||
|
@ -71,6 +71,7 @@ foreach(DF ${DOCFILES})
|
||||
endforeach()
|
||||
|
||||
add_custom_target(helptags
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${GENERATED_RUNTIME_DIR}/doc
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc
|
||||
COMMAND "${PROJECT_BINARY_DIR}/bin/nvim"
|
||||
|
@ -1,15 +1,15 @@
|
||||
function! s:enhance_syntax() abort
|
||||
syntax case match
|
||||
|
||||
syntax keyword healthError ERROR
|
||||
syntax keyword healthError ERROR[:]
|
||||
\ containedin=markdownCodeBlock,mkdListItemLine
|
||||
highlight link healthError Error
|
||||
|
||||
syntax keyword healthWarning WARNING
|
||||
syntax keyword healthWarning WARNING[:]
|
||||
\ containedin=markdownCodeBlock,mkdListItemLine
|
||||
highlight link healthWarning WarningMsg
|
||||
|
||||
syntax keyword healthSuccess SUCCESS
|
||||
syntax keyword healthSuccess OK[:]
|
||||
\ containedin=markdownCodeBlock,mkdListItemLine
|
||||
highlight healthSuccess guibg=#5fff00 guifg=#080808 ctermbg=82 ctermfg=232
|
||||
|
||||
@ -90,27 +90,27 @@ endfunction
|
||||
|
||||
" Changes ':h clipboard' to ':help |clipboard|'.
|
||||
function! s:help_to_link(s) abort
|
||||
return substitute(a:s, '\v:h%[elp] ([^|][^"\r\n]+)', ':help |\1|', 'g')
|
||||
return substitute(a:s, '\v:h%[elp] ([^|][^"\r\n ]+)', ':help |\1|', 'g')
|
||||
endfunction
|
||||
|
||||
" Format a message for a specific report item
|
||||
function! s:format_report_message(status, msg, ...) abort " {{{
|
||||
let output = ' - ' . a:status . ': ' . s:indent_after_line1(a:msg, 4)
|
||||
let suggestions = []
|
||||
let advice = []
|
||||
|
||||
" Optional parameters
|
||||
if a:0 > 0
|
||||
let suggestions = type(a:1) == type("") ? [a:1] : a:1
|
||||
if type(suggestions) != type([])
|
||||
echoerr "Expected String or List"
|
||||
let advice = type(a:1) == type("") ? [a:1] : a:1
|
||||
if type(advice) != type([])
|
||||
throw "Expected String or List"
|
||||
endif
|
||||
endif
|
||||
|
||||
" Report each suggestion
|
||||
if len(suggestions) > 0
|
||||
let output .= "\n - SUGGESTIONS:"
|
||||
if len(advice) > 0
|
||||
let output .= "\n - ADVICE:"
|
||||
endif
|
||||
for suggestion in suggestions
|
||||
for suggestion in advice
|
||||
let output .= "\n - " . s:indent_after_line1(suggestion, 10)
|
||||
endfor
|
||||
|
||||
@ -124,7 +124,7 @@ endfunction " }}}
|
||||
|
||||
" Reports a successful healthcheck.
|
||||
function! health#report_ok(msg) abort " {{{
|
||||
echo s:format_report_message('SUCCESS', a:msg)
|
||||
echo s:format_report_message('OK', a:msg)
|
||||
endfunction " }}}
|
||||
|
||||
" Reports a health warning.
|
||||
|
@ -10,6 +10,12 @@ function! s:check_config() abort
|
||||
\ [ "Use the 'guicursor' option to configure cursor shape. :help 'guicursor'",
|
||||
\ 'https://github.com/neovim/neovim/wiki/Following-HEAD#20170402' ])
|
||||
endif
|
||||
if &paste
|
||||
let ok = v:false
|
||||
call health#report_error("'paste' is enabled. This option is only for pasting text.\nIt should not be set in your config.",
|
||||
\ [ 'Remove `set paste` from your init.vim, if applicable.',
|
||||
\ 'Check `:verbose set paste?` to see if a plugin or script set the option.', ])
|
||||
endif
|
||||
|
||||
if ok
|
||||
call health#report_ok('no issues found')
|
||||
|
@ -121,14 +121,14 @@ function! s:check_clipboard() abort
|
||||
call health#report_start('Clipboard (optional)')
|
||||
|
||||
let clipboard_tool = provider#clipboard#Executable()
|
||||
if empty(clipboard_tool)
|
||||
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'))
|
||||
if exists('g:clipboard') && empty(clipboard_tool)
|
||||
call health#report_error(
|
||||
\ 'g:clipboard exists but is malformed. It must be a dictionary with the keys documented at :help g:clipboard')
|
||||
\ provider#clipboard#Error(),
|
||||
\ ["Use the example in :help g:clipboard as a template, or don't set g:clipboard at all."])
|
||||
elseif empty(clipboard_tool)
|
||||
call health#report_warn(
|
||||
\ 'No clipboard tool found. Clipboard registers (`"+` and `"*`) will not work.',
|
||||
\ [':help clipboard'])
|
||||
else
|
||||
call health#report_ok('Clipboard tool found: '. clipboard_tool)
|
||||
endif
|
||||
@ -239,7 +239,7 @@ function! s:check_python(version) abort
|
||||
|
||||
let pyname = 'python'.(a:version == 2 ? '' : '3')
|
||||
let pyenv = resolve(exepath('pyenv'))
|
||||
let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : 'n'
|
||||
let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : ''
|
||||
let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
|
||||
let host_prog_var = pyname.'_host_prog'
|
||||
let loaded_var = 'g:loaded_'.pyname.'_provider'
|
||||
@ -251,6 +251,19 @@ function! s:check_python(version) abort
|
||||
return
|
||||
endif
|
||||
|
||||
if !empty(pyenv)
|
||||
if empty(pyenv_root)
|
||||
call health#report_warn(
|
||||
\ 'pyenv was found, but $PYENV_ROOT is not set.',
|
||||
\ ['Did you follow the final install instructions?',
|
||||
\ 'If you use a shell "framework" like Prezto or Oh My Zsh, try without.',
|
||||
\ 'Try a different shell (bash).']
|
||||
\ )
|
||||
else
|
||||
call health#report_ok(printf('pyenv found: "%s"', pyenv))
|
||||
endif
|
||||
endif
|
||||
|
||||
if exists('g:'.host_prog_var)
|
||||
call health#report_info(printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var)))
|
||||
endif
|
||||
@ -282,15 +295,6 @@ function! s:check_python(version) abort
|
||||
endif
|
||||
|
||||
if !empty(pyenv)
|
||||
if empty(pyenv_root)
|
||||
call health#report_warn(
|
||||
\ 'pyenv was found, but $PYENV_ROOT is not set.',
|
||||
\ ['Did you follow the final install instructions?']
|
||||
\ )
|
||||
else
|
||||
call health#report_ok(printf('pyenv found: "%s"', pyenv))
|
||||
endif
|
||||
|
||||
let python_bin = s:trim(s:system([pyenv, 'which', pyname], '', 1))
|
||||
|
||||
if empty(python_bin)
|
||||
@ -320,9 +324,8 @@ function! s:check_python(version) abort
|
||||
|
||||
if python_bin =~# '\<shims\>'
|
||||
call health#report_warn(printf('`%s` appears to be a pyenv shim.', python_bin), [
|
||||
\ 'The `pyenv` executable is not in $PATH,',
|
||||
\ 'Your pyenv installation is broken. You should set '
|
||||
\ . '`g:'.host_prog_var.'` to avoid surprises.',
|
||||
\ '`pyenv` is not in $PATH, your pyenv installation is broken. '
|
||||
\ .'Set `g:'.host_prog_var.'` to avoid surprises.',
|
||||
\ ])
|
||||
endif
|
||||
endif
|
||||
@ -335,7 +338,7 @@ function! s:check_python(version) abort
|
||||
call health#report_warn('pyenv is not set up optimally.', [
|
||||
\ printf('Create a virtualenv specifically '
|
||||
\ . 'for Neovim using pyenv, and set `g:%s`. This will avoid '
|
||||
\ . 'the need to install Neovim''s Python module in each '
|
||||
\ . 'the need to install the Neovim Python module in each '
|
||||
\ . 'version/virtualenv.', host_prog_var)
|
||||
\ ])
|
||||
elseif !empty(venv) && exists('g:'.host_prog_var)
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
let s:stderr = {}
|
||||
|
||||
function! provider#stderr_collector(chan_id, data, event) dict
|
||||
function! provider#stderr_collector(chan_id, data, event)
|
||||
let stderr = get(s:stderr, a:chan_id, [''])
|
||||
let stderr[-1] .= a:data[0]
|
||||
call extend(stderr, a:data[1:])
|
||||
@ -10,7 +10,9 @@ function! provider#stderr_collector(chan_id, data, event) dict
|
||||
endfunction
|
||||
|
||||
function! provider#clear_stderr(chan_id)
|
||||
silent! call delete(s:stderr, a:chan_id)
|
||||
if has_key(s:stderr, a:chan_id)
|
||||
call remove(s:stderr, a:chan_id)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! provider#get_stderr(chan_id)
|
||||
|
@ -3,6 +3,7 @@
|
||||
" available.
|
||||
let s:copy = {}
|
||||
let s:paste = {}
|
||||
let s:clipboard = {}
|
||||
|
||||
" When caching is enabled, store the jobid of the xclip/xsel process keeping
|
||||
" ownership of the selection, so we know how long the cache is valid.
|
||||
@ -23,7 +24,7 @@ function! s:selection.on_exit(jobid, data, event) abort
|
||||
call provider#clear_stderr(a:jobid)
|
||||
endfunction
|
||||
|
||||
let s:selections = { '*': s:selection, '+': copy(s:selection)}
|
||||
let s:selections = { '*': s:selection, '+': copy(s:selection) }
|
||||
|
||||
function! s:try_cmd(cmd, ...) abort
|
||||
let argv = split(a:cmd, " ")
|
||||
@ -31,7 +32,7 @@ function! s:try_cmd(cmd, ...) abort
|
||||
if v:shell_error
|
||||
if !exists('s:did_error_try_cmd')
|
||||
echohl WarningMsg
|
||||
echomsg "clipboard: error: ".(len(out) ? out[0] : '')
|
||||
echomsg "clipboard: error: ".(len(out) ? out[0] : v:shell_error)
|
||||
echohl None
|
||||
let s:did_error_try_cmd = 1
|
||||
endif
|
||||
@ -55,9 +56,15 @@ endfunction
|
||||
|
||||
function! provider#clipboard#Executable() abort
|
||||
if exists('g:clipboard')
|
||||
if type({}) isnot# type(g:clipboard)
|
||||
\ || type({}) isnot# type(get(g:clipboard, 'copy', v:null))
|
||||
\ || type({}) isnot# type(get(g:clipboard, 'paste', v:null))
|
||||
let s:err = 'clipboard: invalid g:clipboard'
|
||||
return ''
|
||||
endif
|
||||
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)
|
||||
let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0)
|
||||
return get(g:clipboard, 'name', 'g:clipboard')
|
||||
elseif has('mac') && executable('pbcopy')
|
||||
let s:copy['+'] = 'pbcopy'
|
||||
@ -104,16 +111,17 @@ function! provider#clipboard#Executable() abort
|
||||
return 'tmux'
|
||||
endif
|
||||
|
||||
let s:err = 'clipboard: No clipboard tool available. :help clipboard'
|
||||
let s:err = 'clipboard: No clipboard tool. :help clipboard'
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
if empty(provider#clipboard#Executable())
|
||||
" provider#clipboard#Call() *must not* be defined if the provider is broken.
|
||||
" Otherwise eval_has_provider() thinks the clipboard provider is
|
||||
" functioning, and eval_call_provider() will happily call it.
|
||||
finish
|
||||
endif
|
||||
|
||||
let s:clipboard = {}
|
||||
|
||||
function! s:clipboard.get(reg) abort
|
||||
if s:selections[a:reg].owner > 0
|
||||
return s:selections[a:reg].data
|
||||
@ -154,9 +162,19 @@ function! s:clipboard.set(lines, regtype, reg) abort
|
||||
echohl WarningMsg
|
||||
echomsg 'clipboard: failed to execute: '.(s:copy[a:reg])
|
||||
echohl None
|
||||
return 0
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! provider#clipboard#Call(method, args) abort
|
||||
return call(s:clipboard[a:method],a:args,s:clipboard)
|
||||
if get(s:, 'here', v:false) " Clipboard provider must not recurse. #7184
|
||||
return 0
|
||||
endif
|
||||
let s:here = v:true
|
||||
try
|
||||
return call(s:clipboard[a:method],a:args,s:clipboard)
|
||||
finally
|
||||
let s:here = v:false
|
||||
endtry
|
||||
endfunction
|
||||
|
@ -89,7 +89,8 @@ endfunction
|
||||
|
||||
function! remote#define#AutocmdOnHost(host, method, sync, name, opts)
|
||||
let group = s:GetNextAutocmdGroup()
|
||||
let forward = '"doau '.group.' '.a:name.' ".'.'expand("<amatch>")'
|
||||
let forward = '"doau '.group.' '.a:name.' ".'
|
||||
\ . 'fnameescape(expand("<amatch>"))'
|
||||
let a:opts.group = group
|
||||
let bootstrap_def = s:GetAutocmdPrefix(a:name, a:opts)
|
||||
\ .' call remote#define#AutocmdBootstrap("'.a:host.'"'
|
||||
|
@ -171,8 +171,8 @@ nvim_replace_termcodes({str}, {from_part}, {do_lt}, {special})
|
||||
Parameters:~
|
||||
{str} String to be converted.
|
||||
{from_part} Legacy Vim parameter. Usually true.
|
||||
{do_lt} Also translate <lt>. Does nothing if
|
||||
`special` is false.
|
||||
{do_lt} Also translate <lt>. Ignored if `special` is
|
||||
false.
|
||||
{special} Replace |keycodes|, e.g. <CR> becomes a "\n"
|
||||
char.
|
||||
|
||||
@ -309,20 +309,24 @@ nvim_set_option({name}, {value}) *nvim_set_option()*
|
||||
{value} New option value
|
||||
|
||||
nvim_out_write({str}) *nvim_out_write()*
|
||||
Writes a message to vim output buffer
|
||||
Writes a message to the Vim output buffer. Does not append
|
||||
"\n", the message is buffered (won't display) until a linefeed
|
||||
is written.
|
||||
|
||||
Parameters:~
|
||||
{str} Message
|
||||
|
||||
nvim_err_write({str}) *nvim_err_write()*
|
||||
Writes a message to vim error buffer
|
||||
Writes a message to the Vim error buffer. Does not append
|
||||
"\n", the message is buffered (won't display) until a linefeed
|
||||
is written.
|
||||
|
||||
Parameters:~
|
||||
{str} Message
|
||||
|
||||
nvim_err_writeln({str}) *nvim_err_writeln()*
|
||||
Writes a message to vim error buffer. Appends a linefeed to
|
||||
ensure all contents are written.
|
||||
Writes a message to the Vim error buffer. Appends "\n", so the
|
||||
buffer is flushed (and displayed).
|
||||
|
||||
Parameters:~
|
||||
{str} Message
|
||||
|
@ -1271,7 +1271,7 @@ Commands for changing the working directory can be suffixed with a bang "!"
|
||||
|
||||
*:lcd-*
|
||||
:lcd[!] - Change to the previous current directory (before the
|
||||
previous ":tcd {path}" command).
|
||||
previous ":lcd {path}" command).
|
||||
|
||||
*:pw* *:pwd* *E187*
|
||||
:pw[d] Print the current directory name.
|
||||
|
@ -1522,14 +1522,16 @@ v:errors Errors found by assert functions, such as |assert_true()|.
|
||||
|
||||
*v:event* *event-variable*
|
||||
v:event Dictionary of event data for the current |autocommand|. Valid
|
||||
only during the autocommand lifetime: storing or passing
|
||||
`v:event` is invalid. Copy it instead: >
|
||||
only during the event lifetime; storing or passing v:event is
|
||||
invalid! Copy it instead: >
|
||||
au TextYankPost * let g:foo = deepcopy(v:event)
|
||||
< Keys vary by event; see the documentation for the specific
|
||||
event, e.g. |TextYankPost|.
|
||||
event, e.g. |DirChanged| or |TextYankPost|.
|
||||
KEY DESCRIPTION ~
|
||||
operator The current |operator|. Also set for
|
||||
Ex commands (unlike |v:operator|). For
|
||||
cwd Current working directory
|
||||
scope Event-specific scope name.
|
||||
operator Current |operator|. Also set for Ex
|
||||
commands (unlike |v:operator|). For
|
||||
example if |TextYankPost| is triggered
|
||||
by the |:yank| Ex command then
|
||||
`v:event['operator']` is "y".
|
||||
@ -4726,7 +4728,8 @@ input({opts})
|
||||
"-complete=" argument. Refer to |:command-completion| for
|
||||
more information. Example: >
|
||||
let fname = input("File: ", "", "file")
|
||||
< *E5400* *E5402*
|
||||
|
||||
< *input()-highlight* *E5400* *E5402*
|
||||
The optional `highlight` key allows specifying function which
|
||||
will be used for highlighting user input. This function
|
||||
receives user input as its only argument and must return
|
||||
@ -4744,6 +4747,30 @@ input({opts})
|
||||
sections must be ordered so that next hl_start_col is greater
|
||||
then or equal to previous hl_end_col.
|
||||
|
||||
Example (try some input with parentheses): >
|
||||
highlight RBP1 guibg=Red ctermbg=red
|
||||
highlight RBP2 guibg=Yellow ctermbg=yellow
|
||||
highlight RBP3 guibg=Green ctermbg=green
|
||||
highlight RBP4 guibg=Blue ctermbg=blue
|
||||
let g:rainbow_levels = 4
|
||||
function! RainbowParens(cmdline)
|
||||
let ret = []
|
||||
let i = 0
|
||||
let lvl = 0
|
||||
while i < len(a:cmdline)
|
||||
if a:cmdline[i] is# '('
|
||||
call add(ret, [i, i + 1, 'RBP' . ((lvl % g:rainbow_levels) + 1)])
|
||||
let lvl += 1
|
||||
elseif a:cmdline[i] is# ')'
|
||||
let lvl -= 1
|
||||
call add(ret, [i, i + 1, 'RBP' . ((lvl % g:rainbow_levels) + 1)])
|
||||
endif
|
||||
let i += 1
|
||||
endwhile
|
||||
return ret
|
||||
endfunction
|
||||
call input({'prompt':'>','highlight':'RainbowParens'})
|
||||
<
|
||||
Highlight function is called at least once for each new
|
||||
displayed input string, before command-line is redrawn. It is
|
||||
expected that function is pure for the duration of one input()
|
||||
|
@ -449,12 +449,6 @@ changed. To avoid the message reset the 'warn' option.
|
||||
Something inside Vim went wrong and resulted in a NULL pointer. If you know
|
||||
how to reproduce this problem, please report it. |bugs|
|
||||
|
||||
*E172* >
|
||||
Only one file name allowed
|
||||
|
||||
The ":edit" command only accepts one file name. When you want to specify
|
||||
several files for editing use ":next" |:next|.
|
||||
|
||||
*E41* *E82* *E83* *E342* >
|
||||
Out of memory!
|
||||
Out of memory! (allocating {number} bytes)
|
||||
|
@ -6267,11 +6267,11 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
when part of a command has been typed.
|
||||
|
||||
*'title'* *'notitle'*
|
||||
'title' boolean (default off, on when title can be restored)
|
||||
'title' boolean (default off)
|
||||
global
|
||||
When on, the title of the window will be set to the value of
|
||||
'titlestring' (if it is not empty), or to:
|
||||
filename [+=-] (path) - VIM
|
||||
filename [+=-] (path) - NVIM
|
||||
Where:
|
||||
filename the name of the file being edited
|
||||
- indicates the file cannot be modified, 'ma' off
|
||||
@ -6279,7 +6279,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
= indicates the file is read-only
|
||||
=+ indicates the file is read-only and modified
|
||||
(path) is the path of the file being edited
|
||||
- VIM the server name |v:servername| or "VIM"
|
||||
- NVIM the server name |v:servername| or "NVIM"
|
||||
|
||||
*'titlelen'*
|
||||
'titlelen' number (default 85)
|
||||
@ -6295,11 +6295,10 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
'titlelen' is also used for the 'titlestring' option.
|
||||
|
||||
*'titleold'*
|
||||
'titleold' string (default "Thanks for flying Vim")
|
||||
'titleold' string (default "")
|
||||
global
|
||||
This option will be used for the window title when exiting Vim if the
|
||||
original title cannot be restored. Only happens if 'title' is on or
|
||||
'titlestring' is not empty.
|
||||
If not empty, this option will be used to set the window title when
|
||||
exiting. Only if 'title' is enabled.
|
||||
This option cannot be set from a |modeline| or in the |sandbox|, for
|
||||
security reasons.
|
||||
*'titlestring'*
|
||||
@ -6748,19 +6747,19 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
*'winhighlight'* *'winhl'*
|
||||
'winhighlight' 'winhl' string (default empty)
|
||||
local to window
|
||||
Window-local highlights. Comma-delimited list of |group-name| pairs
|
||||
"{hl-builtin}:{hl-group},..." where each {hl-builtin} is a group (from
|
||||
|highlight-groups|) to be overridden by {hl-group} in the window where
|
||||
this option was set. Only builting ui highlights are supported, not
|
||||
syntax highlighting. For that purpose, use |:ownsyntax|.
|
||||
Window-local highlights. Comma-delimited list of highlight
|
||||
|group-name| pairs "{hl-builtin}:{hl},..." where each {hl-builtin} is
|
||||
a built-in |highlight-groups| item to be overridden by {hl} group in
|
||||
the window. Only built-in |highlight-groups| are supported, not
|
||||
syntax highlighting (use |:ownsyntax| for that).
|
||||
|
||||
Most highlights occuring within the frame of a window are supported.
|
||||
Highlights of vertical separators are determined by the window to the
|
||||
left of the separator. The highlight of a tabpage in |tabline| is
|
||||
determined by the last focused window in the tabpage. Highlights of
|
||||
determine by the last-focused window of the tabpage. Highlights of
|
||||
the popupmenu are determined by the current window. Highlights in the
|
||||
message area are not overridable. Example for overriding the
|
||||
backgrond color: >
|
||||
message area cannot be overridden.
|
||||
|
||||
Example: show a different color for non-current windows: >
|
||||
set winhighlight=Normal:MyNormal,NormalNC:MyNormalNC
|
||||
<
|
||||
*'winfixheight'* *'wfh'* *'nowinfixheight'* *'nowfh'*
|
||||
|
@ -64,11 +64,11 @@ health#report_info({msg}) *health#report_info*
|
||||
health#report_ok({msg}) *health#report_ok*
|
||||
Displays a "success" message.
|
||||
|
||||
health#report_warn({msg}, [{suggestions}]) *health#report_warn*
|
||||
Displays a warning. {suggestions} is an optional List of suggestions.
|
||||
health#report_warn({msg}, [{advice}]) *health#report_warn*
|
||||
Displays a warning. {advice} is an optional List of suggestions.
|
||||
|
||||
health#report_error({msg}, [{suggestions}]) *health#report_error*
|
||||
Displays an error. {suggestions} is an optional List of suggestions.
|
||||
health#report_error({msg}, [{advice}]) *health#report_error*
|
||||
Displays an error. {advice} is an optional List of suggestions.
|
||||
|
||||
health#{plugin}#check() *health.user_checker*
|
||||
This is the form of a healthcheck definition. Call the above functions
|
||||
|
@ -3270,11 +3270,10 @@ improve screen updating rates (see |:syn-sync| for more on this). >
|
||||
The g:vimsyn_embed option allows users to select what, if any, types of
|
||||
embedded script highlighting they wish to have. >
|
||||
|
||||
g:vimsyn_embed == 0 : don't embed any scripts
|
||||
g:vimsyn_embed =~ 'P' : support embedded python
|
||||
g:vimsyn_embed == 0 : disable (don't embed any scripts)
|
||||
g:vimsyn_embed == 'lPr' : support embedded lua, python and ruby
|
||||
<
|
||||
By default, g:vimsyn_embed is a string supporting interpreters that your vim
|
||||
itself supports.
|
||||
This option is disabled by default.
|
||||
*g:vimsyn_folding*
|
||||
|
||||
Some folding is now supported with syntax/vim.vim: >
|
||||
|
@ -41,16 +41,17 @@ $TERM is also important because it is mirrored by SSH to the remote session,
|
||||
unlike other common client-end environment variables ($COLORTERM,
|
||||
$XTERM_VERSION, $VTE_VERSION, $KONSOLE_PROFILE_NAME, $TERM_PROGRAM, ...).
|
||||
|
||||
For this terminal Set $TERM to |builtin-terms|?
|
||||
|
||||
iTerm.app "iterm" or "iTerm.app" Y
|
||||
anything libvte based "vte" or "vte-256color" Y
|
||||
(e.g. GNOME Terminal) (aliases: "gnome", "gnome-256color")
|
||||
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
|
||||
For this terminal Set $TERM to |builtin-terms|
|
||||
-------------------------------------------------------------------------
|
||||
iTerm (original) iterm, iTerm.app N
|
||||
iTerm2 (new capabilities) iterm2, iTerm2.app Y
|
||||
anything libvte-based vte, vte-256color Y
|
||||
(e.g. GNOME Terminal) (aliases: gnome, gnome-256color)
|
||||
tmux tmux, tmux-256color Y
|
||||
screen screen, screen-256color Y
|
||||
PuTTY putty, putty-256color Y
|
||||
Terminal.app nsterm N
|
||||
Linux virtual terminal linux, linux-256color Y
|
||||
|
||||
*builtin-terms* *builtin_terms*
|
||||
If a |terminfo| database is not available, or no entry for the terminal type is
|
||||
|
@ -212,7 +212,6 @@ g8 Print the hex values of the bytes used in the
|
||||
Equivalent to: >
|
||||
:enew
|
||||
:call termopen('{cmd}')
|
||||
:startinsert
|
||||
<
|
||||
See |termopen()|.
|
||||
|
||||
|
@ -6,9 +6,8 @@
|
||||
|
||||
Differences between Nvim and Vim *vim-differences*
|
||||
|
||||
Throughout the help files, differences between Nvim and Vim are indicated via
|
||||
the "{Nvim}" tag. This document is a complete and centralized list of all
|
||||
these differences.
|
||||
Nvim differs from Vim in many ways, big and small. This document is
|
||||
a complete and centralized reference of those differences.
|
||||
|
||||
Type <M-]> to see the table of contents.
|
||||
|
||||
@ -72,12 +71,18 @@ Clipboard integration |provider-clipboard|
|
||||
|
||||
USER EXPERIENCE ~
|
||||
|
||||
Working intuitively and consistently is a major goal of Nvim. Examples:
|
||||
Working intuitively and consistently is a major goal of Nvim.
|
||||
|
||||
- Nvim does not have `-X`, a platform-specific option "sometimes" available in
|
||||
Vim (with potential surprises: http://stackoverflow.com/q/14635295). Nvim
|
||||
avoids features that cannot be provided on all platforms--instead that is
|
||||
delegated to external plugins/extensions.
|
||||
*feature-compile*
|
||||
- Nvim always includes ALL features, in contrast to Vim (which ships with
|
||||
various combinations of 100+ optional features). Think of it as a leaner
|
||||
version of Vim's "HUGE" build. This reduces surface area for bugs, and
|
||||
removes a common source of confusion and friction for users.
|
||||
|
||||
- Nvim avoids features that cannot be provided on all platforms; instead that
|
||||
is delegated to external plugins/extensions. E.g. the `-X` platform-specific
|
||||
option is "sometimes" available in Vim (with potential surprises:
|
||||
http://stackoverflow.com/q/14635295).
|
||||
|
||||
- Vim's internal test functions (test_autochdir(), test_settime(), etc.) are
|
||||
not exposed (nor implemented); instead Nvim has a robust API.
|
||||
@ -268,13 +273,16 @@ Lua interface (|if_lua.txt|):
|
||||
- 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
|
||||
on cancel and completion respectively) via dictionary argument (replaces all
|
||||
|input()| and |inputdialog()| support for each other’s features (return on
|
||||
cancel and completion respectively) via dictionary argument (replaces all
|
||||
other arguments if used).
|
||||
|
||||
|input()| and |inputdialog()| now support user-defined cmdline highlighting.
|
||||
|input()| and |inputdialog()| support user-defined cmdline highlighting.
|
||||
|
||||
Highlight groups:
|
||||
|hl-ColorColumn|, |hl-CursorColumn|, |hl-CursorLine| are lower priority than
|
||||
(overridden by) most other highlight groups.
|
||||
|
||||
==============================================================================
|
||||
5. Missing legacy features *nvim-features-missing*
|
||||
@ -282,7 +290,7 @@ other arguments if used).
|
||||
Some legacy Vim features are not implemented:
|
||||
|
||||
- |if_py|: vim.bindeval() and vim.Function() are not supported
|
||||
- |if_lua|: the `vim` object currently only supports `vim.api`
|
||||
- |if_lua|: the `vim` object is missing most legacy methods
|
||||
- *if_perl*
|
||||
- *if_mzscheme*
|
||||
- *if_tcl*
|
||||
@ -290,7 +298,7 @@ Some legacy Vim features are not implemented:
|
||||
==============================================================================
|
||||
6. Removed features *nvim-features-removed*
|
||||
|
||||
These features are in Vim, but have been intentionally removed from Nvim.
|
||||
These Vim features were intentionally removed from Nvim.
|
||||
|
||||
*'cp'* *'nocompatible'* *'nocp'* *'compatible'*
|
||||
Nvim is always "non-compatible" with Vi.
|
||||
|
@ -3,8 +3,8 @@
|
||||
" #############################################################################
|
||||
" #############################################################################
|
||||
" Note: Be careful when merging the upstream version of this file.
|
||||
" Much of this is generated by scripts/genvimvim.lua (result is installed
|
||||
" to: $VIMRUNTIME/syntax/vim/generated.vim)
|
||||
" Much of this is generated by scripts/genvimvim.lua
|
||||
" (installs to $VIMRUNTIME/syntax/vim/generated.vim)
|
||||
" #############################################################################
|
||||
" #############################################################################
|
||||
|
||||
@ -128,6 +128,13 @@ if exists("g:vimsyntax_noerror")
|
||||
let g:vimsyn_noerror= g:vimsyntax_noerror
|
||||
endif
|
||||
|
||||
" Variable options {{{2
|
||||
if exists("g:vim_maxlines")
|
||||
let s:vimsyn_maxlines= g:vim_maxlines
|
||||
else
|
||||
let s:vimsyn_maxlines= 60
|
||||
endif
|
||||
|
||||
" Numbers {{{2
|
||||
" =======
|
||||
syn match vimNumber "\<\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=" skipwhite nextgroup=vimGlobal,vimSubst,vimCommand
|
||||
@ -601,7 +608,7 @@ syn region vimGlobal matchgroup=Statement start='\<v\%[global]!\=/' skip='\\.' e
|
||||
" g:vimsyn_embed =~# 'r' : embed ruby
|
||||
" g:vimsyn_embed =~# 't' : embed tcl
|
||||
if !exists("g:vimsyn_embed")
|
||||
let g:vimsyn_embed= "lpPr"
|
||||
let g:vimsyn_embed= 0
|
||||
endif
|
||||
|
||||
" [-- lua --] {{{3
|
||||
@ -744,9 +751,10 @@ if !filereadable(s:mzschemepath)
|
||||
endif
|
||||
if g:vimsyn_embed =~# 'm' && filereadable(s:mzschemepath)
|
||||
unlet! b:current_syntax
|
||||
let iskKeep= &isk
|
||||
let s:iskKeep= &isk
|
||||
exe "syn include @vimMzSchemeScript ".s:mzschemepath
|
||||
let &isk= iskKeep
|
||||
let &isk= s:iskKeep
|
||||
unlet s:iskKeep
|
||||
VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+mz\%[scheme]\s*<<\s*\z(.*\)$+ end=+^\z1$+ contains=@vimMzSchemeScript
|
||||
VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+mz\%[scheme]\s*<<\s*$+ end=+\.$+ contains=@vimMzSchemeScript
|
||||
syn cluster vimFuncBodyList add=vimMzSchemeRegion
|
||||
@ -761,11 +769,7 @@ unlet s:mzschemepath
|
||||
if exists("g:vimsyn_minlines")
|
||||
exe "syn sync minlines=".g:vimsyn_minlines
|
||||
endif
|
||||
if exists("g:vimsyn_maxlines")
|
||||
exe "syn sync maxlines=".g:vimsyn_maxlines
|
||||
else
|
||||
syn sync maxlines=60
|
||||
endif
|
||||
exe "syn sync maxlines=".s:vimsyn_maxlines
|
||||
syn sync linecont "^\s\+\\"
|
||||
syn sync match vimAugroupSyncA groupthere NONE "\<aug\%[roup]\>\s\+[eE][nN][dD]"
|
||||
|
||||
@ -778,7 +782,7 @@ if !exists("skip_vim_syntax_inits")
|
||||
hi def link vimBehaveError vimError
|
||||
hi def link vimCollClassErr vimError
|
||||
hi def link vimErrSetting vimError
|
||||
hi def link vimEmbedError vimError
|
||||
hi def link vimEmbedError Normal
|
||||
hi def link vimFTError vimError
|
||||
hi def link vimFunctionError vimError
|
||||
hi def link vimFunc vimError
|
||||
@ -935,6 +939,11 @@ if !exists("skip_vim_syntax_inits")
|
||||
hi def link vimUserFunc Normal
|
||||
hi def link vimVar Identifier
|
||||
hi def link vimWarn WarningMsg
|
||||
|
||||
hi def link nvimAutoEvent vimAutoEvent
|
||||
hi def link nvimHLGroup vimHLGroup
|
||||
hi def link nvimMap vimMap
|
||||
hi def link nvimUnmap vimUnmap
|
||||
endif
|
||||
|
||||
" Current Syntax Variable: {{{2
|
||||
|
@ -23,7 +23,7 @@ relevant help (hopefully), and pressing K over any word will try to do so too.
|
||||
Sometimes you will be required to modify text like
|
||||
this here
|
||||
Once you have done the changes correctly, the ✗ sign at the left will change
|
||||
to ✓. I imagine you can already see how neat Vim can be ;)
|
||||
to ✓. I imagine you can already see how neat Vim can be. ;)
|
||||
Other times, you'll be prompted to run a command (I'll explain this later):
|
||||
~~~ cmd
|
||||
:help <Enter>
|
||||
@ -36,30 +36,30 @@ or press a sequence of keys
|
||||
Text within <'s and >'s (like `<Enter>`{normal}) describes a key to press instead of text
|
||||
to type.
|
||||
|
||||
Now, move to the next lesson (remember, use j).
|
||||
Now, move to the next lesson (remember, use the `j`{normal} key to scroll down).
|
||||
|
||||
## Lesson 1.1: MOVING THE CURSOR
|
||||
|
||||
** To move the cursor, press the `h`, `j`, `k`, `l` keys as indicated. **
|
||||
|
||||
↑
|
||||
k Hint: The h key is at the left and moves left.
|
||||
← h l → The l key is at the right and moves right.
|
||||
j The j key looks like a down arrow.
|
||||
k Hint: The `h`{normal} key is at the left and moves left.
|
||||
← h l → The `l`{normal} key is at the right and moves right.
|
||||
j The `j`{normal} key looks like a down arrow.
|
||||
↓
|
||||
|
||||
1. Move the cursor around the screen until you are comfortable.
|
||||
|
||||
2. Hold down the down key (j) until it repeats.
|
||||
2. Hold down the down key (`j`{normal}) until it repeats.
|
||||
Now you know how to move to the next lesson.
|
||||
|
||||
3. Using the down key, move to Lesson 1.2.
|
||||
|
||||
NOTE: If you are ever unsure about something you typed, press <Esc> to place
|
||||
you in Normal mode. Then retype the command you wanted.
|
||||
you in Normal mode. Then retype the command you wanted.
|
||||
|
||||
NOTE: The cursor keys should also work. But using hjkl you will be able to
|
||||
move around much faster, once you get used to it. Really!
|
||||
NOTE: The cursor keys should also work. But using hjkl you will be able to
|
||||
move around much faster, once you get used to it. Really!
|
||||
|
||||
# Lesson 1.2: EXITING VIM
|
||||
|
||||
@ -81,7 +81,7 @@ NOTE: The cursor keys should also work. But using hjkl you will be able to
|
||||
4. If you have these steps memorized and are confident, execute steps
|
||||
1 through 3 to exit and re-enter the editor.
|
||||
|
||||
NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
|
||||
NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
|
||||
will learn how to save the changes to a file.
|
||||
|
||||
5. Move the cursor down to Lesson 1.3.
|
||||
@ -90,18 +90,18 @@ NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
|
||||
|
||||
** Press `x`{normal} to delete the character under the cursor. **
|
||||
|
||||
1. Move the cursor to the line below marked --->.
|
||||
1. Move the cursor to the line below marked --->.
|
||||
|
||||
2. To fix the errors, move the cursor until it is on top of the
|
||||
character to be deleted.
|
||||
2. To fix the errors, move the cursor until it is on top of the
|
||||
character to be deleted.
|
||||
|
||||
3. Press [the x key](x) to delete the unwanted character.
|
||||
3. Press [the x key](x) to delete the unwanted character.
|
||||
|
||||
4. Repeat steps 2 through 4 until the sentence is correct.
|
||||
4. Repeat steps 2 through 4 until the sentence is correct.
|
||||
|
||||
The ccow jumpedd ovverr thhe mooon.
|
||||
|
||||
5. Now that the line is correct, go on to Lesson 1.4.
|
||||
5. Now that the line is correct, go on to Lesson 1.4.
|
||||
|
||||
NOTE: As you go through this tutor, do not try to memorize, learn by usage.
|
||||
|
||||
@ -114,15 +114,15 @@ NOTE: As you go through this tutor, do not try to memorize, learn by usage.
|
||||
2. To make the first line the same as the second, move the cursor on top
|
||||
of the first character AFTER where the text is to be inserted.
|
||||
|
||||
3. Press i and type in the necessary additions.
|
||||
3. Press `i`{normal} and type in the necessary additions.
|
||||
|
||||
4. As each error is fixed press <Esc> to return to Normal mode.
|
||||
4. As each error is fixed press `<Esc>`{normal} to return to Normal mode.
|
||||
Repeat steps 2 through 4 to correct the sentence.
|
||||
|
||||
There is text misng this .
|
||||
There is some text missing from this line.
|
||||
|
||||
5. When you are comfortable inserting text move to lesson 1.5.
|
||||
5. When you are comfortable inserting text move to Lesson 1.5.
|
||||
|
||||
# Lesson 1.5: TEXT EDITING: APPENDING
|
||||
|
||||
@ -131,9 +131,9 @@ There is some text missing from this line.
|
||||
1. Move the cursor to the first line below marked --->.
|
||||
It does not matter on what character the cursor is in that line.
|
||||
|
||||
2. Press [A](A) and type in the necessary additions.
|
||||
2. Press [A](A) and type in the necessary additions.
|
||||
|
||||
3. As the text has been appended press <Esc> to return to Normal mode.
|
||||
3. As the text has been appended press `<Esc>`{normal} to return to Normal mode.
|
||||
|
||||
4. Move the cursor to the second line marked ---> and repeat
|
||||
steps 2 and 3 to correct this sentence.
|
||||
@ -143,7 +143,7 @@ There is some text missing from this line.
|
||||
There is also some text miss
|
||||
There is also some text missing here.
|
||||
|
||||
5. When you are comfortable appending text move to lesson 1.6.
|
||||
5. When you are comfortable appending text move to Lesson 1.6.
|
||||
|
||||
# Lesson 1.6: EDITING A FILE
|
||||
|
||||
@ -151,7 +151,7 @@ There is also some text missing here.
|
||||
|
||||
!! NOTE: Before executing any of the steps below, read this entire lesson !!
|
||||
|
||||
1. Exit this tutor as you did in lesson 1.2: :q!
|
||||
1. Exit this tutor as you did in Lesson 1.2: `:q!`{vim}
|
||||
Or, if you have access to another terminal, do the following there.
|
||||
|
||||
2. At the shell prompt type this command:
|
||||
@ -159,7 +159,7 @@ There is also some text missing here.
|
||||
$ vim tutor
|
||||
~~~
|
||||
'vim' is the command to start the Vim editor, 'tutor' is the name of the
|
||||
file you wish to edit. Use a file that may be changed.
|
||||
file you wish to edit. Use a file that may be changed.
|
||||
|
||||
3. Insert and delete text as you learned in the previous lessons.
|
||||
|
||||
@ -186,14 +186,14 @@ There is also some text missing here.
|
||||
$ vim FILENAME
|
||||
~~~
|
||||
|
||||
3. To exit Vim type: <Esc> :q! <Enter> to trash all changes.
|
||||
OR type: <Esc> :wq <Enter> to save the changes.
|
||||
3. To exit Vim type: `<Esc>`{normal} `:q!`{vim} `<Enter>`{normal} to trash all changes.
|
||||
OR type: `<Esc>`{normal} `:wq`{vim} `<Enter>`{normal} to save the changes.
|
||||
|
||||
4. To delete the character at the cursor type: `x`{normal}
|
||||
4. To delete the character at the cursor type: `x`{normal}
|
||||
|
||||
5. To insert or append text type:
|
||||
`i`{normal} type inserted text `<Esc>`{normal} insert before the cursor
|
||||
`A`{normal} type appended text `<Esc>`{normal} append after the line
|
||||
`i`{normal} insert text `<Esc>`{normal} insert before the cursor.
|
||||
`A`{normal} append text `<Esc>`{normal} append after the line.
|
||||
|
||||
NOTE: Pressing `<Esc>`{normal} will place you in Normal mode or will cancel
|
||||
an unwanted and partially completed command.
|
||||
@ -210,7 +210,7 @@ Now continue with Lesson 2.
|
||||
|
||||
3. Move the cursor to the beginning of a word that needs to be deleted.
|
||||
|
||||
4. Type [d](d)[w](w) to make the word disappear.
|
||||
4. Type [d](d)[w](w) to make the word disappear.
|
||||
|
||||
There are a some words fun that don't belong paper in this sentence.
|
||||
|
||||
@ -218,9 +218,9 @@ There are a some words fun that don't belong paper in this sentence.
|
||||
|
||||
# Lesson 2.2: MORE DELETION COMMANDS
|
||||
|
||||
** Type `d$`{normal} to delete to the end of the line. **
|
||||
** Type `d$`{normal} to delete to the end of the line. **
|
||||
|
||||
1. Press <Esc> to make sure you are in Normal mode.
|
||||
1. Press `<Esc>`{normal} to make sure you are in Normal mode.
|
||||
|
||||
2. Move the cursor to the line below marked --->.
|
||||
|
||||
@ -236,7 +236,7 @@ Somebody typed the end of this line twice. end of this line twice.
|
||||
|
||||
|
||||
Many commands that change text are made from an [operator](operator) and a [motion](navigation).
|
||||
The format for a delete command with the [d](d) delete operator is as follows:
|
||||
The format for a delete command with the [d](d) delete operator is as follows:
|
||||
|
||||
d motion
|
||||
|
||||
@ -249,7 +249,7 @@ The format for a delete command with the [d](d) delete operator is as follows:
|
||||
[e](e) - to the end of the current word, INCLUDING the last character.
|
||||
[$]($) - to the end of the line, INCLUDING the last character.
|
||||
|
||||
Thus typing `de`{normal} will delete from the cursor to the end of the word.
|
||||
Thus typing `de`{normal} will delete from the cursor to the end of the word.
|
||||
|
||||
NOTE: Pressing just the motion while in Normal mode without an operator will
|
||||
move the cursor as specified.
|
||||
@ -260,11 +260,11 @@ NOTE: Pressing just the motion while in Normal mode without an operator will
|
||||
|
||||
1. Move the cursor to the start of the line marked ---> below.
|
||||
|
||||
2. Type `2w`{normal} to move the cursor two words forward.
|
||||
2. Type `2w`{normal} to move the cursor two words forward.
|
||||
|
||||
3. Type `3e`{normal} to move the cursor to the end of the third word forward.
|
||||
3. Type `3e`{normal} to move the cursor to the end of the third word forward.
|
||||
|
||||
4. Type `0`{normal} ([zero](0)) to move to the start of the line.
|
||||
4. Type `0`{normal} ([zero](0)) to move to the start of the line.
|
||||
|
||||
5. Repeat steps 2 and 3 with different numbers.
|
||||
|
||||
@ -282,22 +282,22 @@ insert a count before the motion to delete more:
|
||||
|
||||
1. Move the cursor to the first UPPER CASE word in the line marked --->.
|
||||
|
||||
2. Type `d2w`{normal} to delete the two UPPER CASE words
|
||||
2. Type `d2w`{normal} to delete the two UPPER CASE words
|
||||
|
||||
3. Repeat steps 1 and 2 with a different count to delete the consecutive
|
||||
UPPER CASE words with one command
|
||||
|
||||
this ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up.
|
||||
This ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up.
|
||||
|
||||
# Lesson 2.6: OPERATING ON LINES
|
||||
|
||||
** Type dd to delete a whole line. **
|
||||
** Type `dd`{normal} to delete a whole line. **
|
||||
|
||||
Due to the frequency of whole line deletion, the designers of Vi decided
|
||||
it would be easier to simply type two d's to delete a line.
|
||||
|
||||
1. Move the cursor to the second line in the phrase below.
|
||||
2. Type [dd](dd) to delete the line.
|
||||
2. Type [dd](dd) to delete the line.
|
||||
3. Now move to the fourth line.
|
||||
4. Type `2dd`{normal} to delete two lines.
|
||||
|
||||
@ -311,20 +311,20 @@ this ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up.
|
||||
|
||||
# Lesson 2.7: THE UNDO COMMAND
|
||||
|
||||
** Press u to undo the last commands, U to fix a whole line. **
|
||||
** Press `u`{normal} to undo the last commands, `U`{normal} to fix a whole line. **
|
||||
|
||||
1. Move the cursor to the line below marked ---> and place it on the
|
||||
first error.
|
||||
2. Type `x`{normal} to delete the first unwanted character.
|
||||
3. Now type `u`{normal} to undo the last command executed.
|
||||
4. This time fix all the errors on the line using the `x`{normal} command.
|
||||
5. Now type a capital `U`{normal} to return the line to its original state.
|
||||
6. Now type `u`{normal} a few times to undo the U and preceding commands.
|
||||
7. Now type `<Ctrl-r>`{normal} a few times to redo the commands (undo the undo's).
|
||||
2. Type `x`{normal} to delete the first unwanted character.
|
||||
3. Now type `u`{normal} to undo the last command executed.
|
||||
4. This time fix all the errors on the line using the `x`{normal} command.
|
||||
5. Now type a capital `U`{normal} to return the line to its original state.
|
||||
6. Now type `u`{normal} a few times to undo the `U`{normal} and preceding commands.
|
||||
7. Now type `<Ctrl-r>`{normal} a few times to redo the commands (undo the undo's).
|
||||
|
||||
Fiix the errors oon thhis line and reeplace them witth undo.
|
||||
|
||||
8. These are very useful commands. Now move on to the Lesson 2 Summary.
|
||||
8. These are very useful commands. Now move on to the Lesson 2 Summary.
|
||||
|
||||
# Lesson 2 SUMMARY
|
||||
|
||||
@ -336,13 +336,13 @@ Fiix the errors oon thhis line and reeplace them witth undo.
|
||||
5. The format for a change command is:
|
||||
operator [number] motion
|
||||
where:
|
||||
operator - is what to do, such as [d](d) for delete
|
||||
operator - is what to do, such as [d](d) for delete
|
||||
[number] - is an optional count to repeat the motion
|
||||
motion - moves over the text to operate on, such as:
|
||||
[w](w) (word),
|
||||
[$]($) (to the end of line), etc.
|
||||
|
||||
6. To move to the start of the line use a zero: [0](0)
|
||||
6. To move to the start of the line use a zero: [0](0)
|
||||
|
||||
7. To undo previous actions, type: `u`{normal} (lowercase u)
|
||||
To undo all the changes on a line, type: `U`{normal} (capital U)
|
||||
@ -350,15 +350,15 @@ Fiix the errors oon thhis line and reeplace them witth undo.
|
||||
|
||||
# Lesson 3.1: THE PUT COMMAND
|
||||
|
||||
** Type p to put previously deleted text after the cursor. **
|
||||
** Type `p`{normal} to put previously deleted text after the cursor. **
|
||||
|
||||
1. Move the cursor to the first ---> line below.
|
||||
|
||||
2. Type `dd`{normal} to delete the line and store it in a Vim register.
|
||||
2. Type `dd`{normal} to delete the line and store it in a Vim register.
|
||||
|
||||
3. Move the cursor to the c) line, ABOVE where the deleted line should go.
|
||||
|
||||
4. Type `p`{normal} to put the line below the cursor.
|
||||
4. Type `p`{normal} to put the line below the cursor.
|
||||
|
||||
5. Repeat steps 2 through 4 to put all the lines in correct order.
|
||||
|
||||
@ -388,11 +388,11 @@ NOTE: Remember that you should be learning by doing, not memorization.
|
||||
|
||||
# Lesson 3.3: THE CHANGE OPERATOR
|
||||
|
||||
** To change until the end of a word, type `ce`{normal} **
|
||||
** To change until the end of a word, type `ce`{normal}. **
|
||||
|
||||
1. Move the cursor to the first line below marked --->.
|
||||
|
||||
2. Place the cursor on the "u" in "lubw".
|
||||
2. Place the cursor on the "u" in "lubw".
|
||||
|
||||
3. Type `ce`{normal} and the correct word (in this case, type "ine" ).
|
||||
|
||||
@ -405,11 +405,11 @@ This line has a few words that need changing using the change operator.
|
||||
|
||||
Notice that [c](c)e deletes the word and places you in Insert mode.
|
||||
|
||||
# Lesson 3.4: MORE CHANGES USING c
|
||||
# Lesson 3.4: MORE CHANGES USING `c`{normal}
|
||||
|
||||
** The change operator is used with the same motions as delete. **
|
||||
|
||||
1. The change operator works in the same way as delete. The format is:
|
||||
1. The change operator works in the same way as delete. The format is:
|
||||
|
||||
c [number] motion
|
||||
|
||||
@ -422,13 +422,13 @@ Notice that [c](c)e deletes the word and places you in Insert mode.
|
||||
5. Type `c$`{normal} and type the rest of the line like the second and press `<Esc>`{normal}.
|
||||
|
||||
The end of this line needs some help to make it like the second.
|
||||
The end of this line needs to be corrected using the c$ command.
|
||||
The end of this line needs to be corrected using the `c$`{normal} command.
|
||||
|
||||
NOTE: You can use the Backspace key to correct mistakes while typing.
|
||||
NOTE: You can use the Backspace key to correct mistakes while typing.
|
||||
|
||||
# Lesson 3 SUMMARY
|
||||
|
||||
1. To put back text that has just been deleted, type [p](p). This puts the
|
||||
1. To put back text that has just been deleted, type [p](p). This puts the
|
||||
deleted text AFTER the cursor (if a line was deleted it will go on the
|
||||
line below the cursor).
|
||||
|
||||
@ -436,8 +436,8 @@ NOTE: You can use the Backspace key to correct mistakes while typing.
|
||||
character you want to have there.
|
||||
|
||||
3. The [change operator](c) allows you to change from the cursor to where the
|
||||
motion takes you. eg. Type `ce`{normal} to change from the cursor to the end of
|
||||
the word, `c$`{normal} to change to the end of a line.
|
||||
motion takes you. Type `ce`{normal} to change from the cursor to the end of
|
||||
the word, `c$`{normal} to change to the end of a line.
|
||||
|
||||
4. The format for change is:
|
||||
|
||||
@ -448,21 +448,21 @@ Now go on to the next lesson.
|
||||
# Lesson 4.1: CURSOR LOCATION AND FILE STATUS
|
||||
|
||||
** Type `<Ctrl-g>`{normal} to show your location in the file and the file status.
|
||||
Type `G`{normal} to move to a line in the file. **
|
||||
Type `G`{normal} to move to a line in the file. **
|
||||
|
||||
NOTE: Read this entire lesson before executing any of the steps!!
|
||||
|
||||
1. Hold down the `<Ctrl>`{normal} key and press `g`{normal}. We call this `<Ctrl-g>`{normal}.
|
||||
1. Hold down the `<Ctrl>`{normal} key and press `g`{normal}. We call this `<Ctrl-g>`{normal}.
|
||||
A message will appear at the bottom of the page with the filename and the
|
||||
position in the file. Remember the line number for Step 3.
|
||||
position in the file. Remember the line number for Step 3.
|
||||
|
||||
NOTE: You may see the cursor position in the lower right corner of the screen
|
||||
This happens when the ['ruler']('ruler') option is set (see :help 'ruler' )
|
||||
NOTE: You may see the cursor position in the lower right corner of the screen
|
||||
This happens when the ['ruler']('ruler') option is set (see `:help 'ruler'`{vim} ).
|
||||
|
||||
2. Press [G](G) to move you to the bottom of the file.
|
||||
Type [gg](gg) to move you to the start of the file.
|
||||
2. Press [G](G) to move you to the bottom of the file.
|
||||
Type [gg](gg) to move you to the start of the file.
|
||||
|
||||
3. Type the number of the line you were on and then `G`{normal} . This will
|
||||
3. Type the number of the line you were on and then `G`{normal}. This will
|
||||
return you to the line you were on when you first pressed `<Ctrl-g>`{normal}.
|
||||
|
||||
4. If you feel confident to do this, execute steps 1 through 3.
|
||||
@ -471,20 +471,20 @@ NOTE: You may see the cursor position in the lower right corner of the screen
|
||||
|
||||
** Type `/`{normal} followed by a phrase to search for the phrase. **
|
||||
|
||||
1. In Normal mode type the `/`{normal} character. Notice that it and the cursor
|
||||
appear at the bottom of the screen as with the : command.
|
||||
1. In Normal mode type the `/`{normal} character. Notice that it and the cursor
|
||||
appear at the bottom of the screen as with the `:`{normal} command.
|
||||
|
||||
2. Now type 'errroor' `<Enter>`{normal}. This is the word you want to search for.
|
||||
2. Now type 'errroor' `<Enter>`{normal}. This is the word you want to search for.
|
||||
|
||||
3. To search for the same phrase again, simply type [n](n) .
|
||||
To search for the same phrase in the opposite direction, type [N](N) .
|
||||
3. To search for the same phrase again, simply type [n](n).
|
||||
To search for the same phrase in the opposite direction, type [N](N).
|
||||
|
||||
4. To search for a phrase in the backward direction, use [?](?) instead of / .
|
||||
4. To search for a phrase in the backward direction, use [?](?) instead of `/`{normal}.
|
||||
|
||||
5. To go back to where you came from press `<Ctrl-o>`{normal} (Keep Ctrl down while
|
||||
pressing the letter o). Repeat to go back further. `<Ctrl-i>`{normal} goes forward.
|
||||
5. To go back to where you came from press `<Ctrl-o>`{normal} (keep `<Ctrl>`{normal} pressed down while
|
||||
pressing the letter `o`{normal}). Repeat to go back further. `<Ctrl-i>`{normal} goes forward.
|
||||
|
||||
"errroor" is not the way to spell error; errroor is an error.
|
||||
"errroor" is not the way to spell error; errroor is an error.
|
||||
|
||||
NOTE: When the search reaches the end of the file it will continue at the
|
||||
start, unless the ['wrapscan']('wrapscan') option has been reset.
|
||||
@ -495,7 +495,7 @@ NOTE: When the search reaches the end of the file it will continue at the
|
||||
|
||||
1. Place the cursor on any (, [, or { in the line below marked --->.
|
||||
|
||||
2. Now type the [%](%) character.
|
||||
2. Now type the [%](%) character.
|
||||
|
||||
3. The cursor will move to the matching parenthesis or bracket.
|
||||
|
||||
@ -528,7 +528,7 @@ NOTE: This is very useful in debugging a program with unmatched parentheses!
|
||||
Adding the g [flag](:s_flags) means to substitute globally in the line, change
|
||||
all occurrences of "thee" in the line.
|
||||
|
||||
thee best time to see thee flowers is in thee spring.
|
||||
Usually thee best time to see thee flowers is in thee spring.
|
||||
|
||||
4. To change every occurrence of a character string between two lines, type
|
||||
~~~ cmd
|
||||
@ -589,20 +589,20 @@ thee best time to see thee flowers is in thee spring.
|
||||
** Type `:!`{vim} followed by an external command to execute that command. **
|
||||
|
||||
1. Type the familiar command `:`{normal} to set the cursor at the bottom of the
|
||||
screen. This allows you to enter a command-line command.
|
||||
screen. This allows you to enter a command-line command.
|
||||
|
||||
2. Now type the [!](!cmd) (exclamation point) character. This allows you to
|
||||
2. Now type the [!](!cmd) (exclamation point) character. This allows you to
|
||||
execute any external shell command.
|
||||
|
||||
3. As an example type "ls" following the "!" and then hit `<Enter>`{normal}. This
|
||||
3. As an example type "ls" following the "!" and then hit `<Enter>`{normal}. This
|
||||
will show you a listing of your directory, just as if you were at the
|
||||
shell prompt.
|
||||
|
||||
NOTE: It is possible to execute any external command this way, also with
|
||||
arguments.
|
||||
NOTE: It is possible to execute any external command this way, also with
|
||||
arguments.
|
||||
|
||||
NOTE: All : commands must be finished by hitting <Enter>
|
||||
From here on we will not always mention it.
|
||||
NOTE: All `:`{vim} commands must be finished by hitting `<Enter>`{normal}.
|
||||
From here on we will not always mention it.
|
||||
|
||||
# Lesson 5.2: MORE ON WRITING FILES
|
||||
|
||||
@ -622,7 +622,7 @@ NOTE: All : commands must be finished by hitting <Enter>
|
||||
4. This saves the whole file (the Vim Tutor) under the name TEST.
|
||||
To verify this, type `:!ls`{vim} again to see your directory.
|
||||
|
||||
NOTE: If you were to exit Vim and start it again with vim TEST , the file
|
||||
NOTE: If you were to exit Vim and start it again with `nvim TEST`, the file
|
||||
would be an exact copy of the tutor when you saved it.
|
||||
|
||||
5. Now remove the file by typing:
|
||||
@ -632,14 +632,14 @@ NOTE: If you were to exit Vim and start it again with vim TEST , the file
|
||||
|
||||
# Lesson 5.3: SELECTING TEXT TO WRITE
|
||||
|
||||
** To save part of the file, type `v`{normal} motion `:w FILENAME`{vim} **
|
||||
** To save part of the file, type `v`{normal} motion `:w FILENAME`{vim}. **
|
||||
|
||||
1. Move the cursor to this line.
|
||||
|
||||
2. Press [v](v) and move the cursor to the fifth item below. Notice that the
|
||||
2. Press [v](v) and move the cursor to the fifth item below. Notice that the
|
||||
text is highlighted.
|
||||
|
||||
3. Press the `:`{normal} character. At the bottom of the screen
|
||||
3. Press the `:`{normal} character. At the bottom of the screen
|
||||
|
||||
:'<,'>
|
||||
|
||||
@ -649,27 +649,27 @@ NOTE: If you were to exit Vim and start it again with vim TEST , the file
|
||||
|
||||
`:w TEST`{vim}
|
||||
|
||||
where TEST is a filename that does not exist yet. Verify that you see
|
||||
where TEST is a filename that does not exist yet. Verify that you see
|
||||
|
||||
`:'<,'>w TEST`{vim}
|
||||
|
||||
before you press `<Enter>`{normal}.
|
||||
|
||||
5. Vim will write the selected lines to the file TEST. Use `:!ls`{vim} to see it.
|
||||
Do not remove it yet! We will use it in the next lesson.
|
||||
5. Vim will write the selected lines to the file TEST. Use `:!ls`{vim} to see it.
|
||||
Do not remove it yet! We will use it in the next lesson.
|
||||
|
||||
NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move
|
||||
the cursor around to make the selection bigger or smaller. Then you can
|
||||
use an operator to do something with the text. For example, `d`{normal} deletes
|
||||
the text.
|
||||
NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move
|
||||
the cursor around to make the selection bigger or smaller. Then you can
|
||||
use an operator to do something with the text. For example, `d`{normal} deletes
|
||||
the text.
|
||||
|
||||
# Lesson 5.4: RETRIEVING AND MERGING FILES
|
||||
|
||||
** To insert the contents of a file, type `:r FILENAME`{vim} **
|
||||
** To insert the contents of a file, type `:r FILENAME`{vim}. **
|
||||
|
||||
1. Place the cursor just above this line.
|
||||
|
||||
NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
|
||||
NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
|
||||
DOWN to see this lesson again.
|
||||
|
||||
2. Now retrieve your TEST file using the command
|
||||
@ -682,31 +682,31 @@ NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
|
||||
3. To verify that a file was retrieved, cursor back and notice that there
|
||||
are now two copies of Lesson 5.3, the original and the file version.
|
||||
|
||||
NOTE: You can also read the output of an external command. For example,
|
||||
NOTE: You can also read the output of an external command. For example,
|
||||
|
||||
`:r !ls`{vim}
|
||||
`:r !ls`{vim}
|
||||
|
||||
reads the output of the `ls` command and puts it below the cursor.
|
||||
reads the output of the `ls` command and puts it below the cursor.
|
||||
|
||||
# Lesson 5 SUMMARY
|
||||
|
||||
1. [:!command](:!cmd) executes an external command.
|
||||
1. [:!command](:!cmd) executes an external command.
|
||||
|
||||
Some useful examples are:
|
||||
`:!ls`{vim} - shows a directory listing
|
||||
`:!rm FILENAME`{vim} - removes file FILENAME
|
||||
Some useful examples are:
|
||||
`:!ls`{vim} - shows a directory listing
|
||||
`:!rm FILENAME`{vim} - removes file FILENAME
|
||||
|
||||
2. [:w](:w) FILENAME writes the current Vim file to disk with
|
||||
name FILENAME.
|
||||
2. [:w](:w) FILENAME writes the current Vim file to disk with
|
||||
name FILENAME.
|
||||
|
||||
3. [v](v) motion :w FILENAME saves the Visually selected lines in file
|
||||
FILENAME.
|
||||
3. [v](v) motion :w FILENAME saves the Visually selected lines in file
|
||||
FILENAME.
|
||||
|
||||
4. [:r](:r) FILENAME retrieves disk file FILENAME and puts it
|
||||
below the cursor position.
|
||||
4. [:r](:r) FILENAME retrieves disk file FILENAME and puts it
|
||||
below the cursor position.
|
||||
|
||||
5. [:r !dir](:r!) reads the output of the dir command and
|
||||
puts it below the cursor position.
|
||||
5. [:r !dir](:r!) reads the output of the dir command and
|
||||
puts it below the cursor position.
|
||||
|
||||
# Lesson 6.1: THE OPEN COMMAND
|
||||
|
||||
@ -719,10 +719,10 @@ NOTE: You can also read the output of an external command. For example,
|
||||
|
||||
3. Now type some text and press `<Esc>`{normal} to exit Insert mode.
|
||||
|
||||
After typing o the cursor is placed on the open line in Insert mode.
|
||||
After typing `o`{normal} the cursor is placed on the open line in Insert mode.
|
||||
|
||||
4. To open up a line ABOVE the cursor, simply type a [capital O](O), rather
|
||||
than a lowercase `o`{normal}. Try this on the line below.
|
||||
than a lowercase `o`{normal}. Try this on the line below.
|
||||
|
||||
Open up a line above this by typing O while the cursor is on this line.
|
||||
|
||||
@ -734,9 +734,9 @@ Open up a line above this by typing O while the cursor is on this line.
|
||||
|
||||
2. Press `e`{normal} until the cursor is on the end of "li".
|
||||
|
||||
3. Type an `a`{normal} (lowercase) to [append](a) text AFTER the cursor.
|
||||
3. Type the lowercase letter `a`{normal} to [append](a) text AFTER the cursor.
|
||||
|
||||
4. Complete the word like the line below it. Press `<Esc>`{normal} to exit Insert
|
||||
4. Complete the word like the line below it. Press `<Esc>`{normal} to exit Insert
|
||||
mode.
|
||||
|
||||
5. Use `e`{normal} to move to the next incomplete word and repeat steps 3 and 4.
|
||||
@ -744,20 +744,20 @@ Open up a line above this by typing O while the cursor is on this line.
|
||||
This li will allow you to pract appendi text to a line.
|
||||
This line will allow you to practice appending text to a line.
|
||||
|
||||
NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only difference is where
|
||||
the characters are inserted.
|
||||
NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only difference is where
|
||||
the characters are inserted.
|
||||
|
||||
# Lesson 6.3: ANOTHER WAY TO REPLACE
|
||||
|
||||
** Type a capital `R`{normal} to replace more than one character. **
|
||||
|
||||
1. Move the cursor to the first line below marked --->. Move the cursor to
|
||||
1. Move the cursor to the first line below marked --->. Move the cursor to
|
||||
the beginning of the first "xxx".
|
||||
|
||||
2. Now press `R`{normal} ([capital R](R)) and type the number below it in the second line, so that it
|
||||
replaces the "xxx".
|
||||
|
||||
3. Press `<Esc>`{normal} to leave [Replace mode](mode-replace). Notice that the rest of the line
|
||||
3. Press `<Esc>`{normal} to leave [Replace mode](mode-replace). Notice that the rest of the line
|
||||
remains unmodified.
|
||||
|
||||
4. Repeat the steps to replace the remaining "xxx".
|
||||
@ -765,12 +765,12 @@ NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only differ
|
||||
Adding 123 to xxx gives you xxx.
|
||||
Adding 123 to 456 gives you 579.
|
||||
|
||||
NOTE: Replace mode is like Insert mode, but every typed character deletes an
|
||||
existing character.
|
||||
NOTE: Replace mode is like Insert mode, but every typed character deletes an
|
||||
existing character.
|
||||
|
||||
# Lesson 6.4: COPY AND PASTE TEXT
|
||||
|
||||
** Use the `y`{normal} operator to copy text and `p`{normal} to paste it **
|
||||
** Use the `y`{normal} operator to copy text and `p`{normal} to paste it. **
|
||||
|
||||
1. Go to the line marked with ---> below and place the cursor after "a)".
|
||||
|
||||
@ -780,35 +780,37 @@ NOTE: Replace mode is like Insert mode, but every typed character deletes an
|
||||
|
||||
4. Move the cursor to the end of the next line: `j$`{normal}
|
||||
|
||||
5. Type `p`{normal} to [put](put) (paste) the text. Then type: "a second"`<Esc>`{normal}.
|
||||
5. Type `p`{normal} to [put](put) (paste) the text.
|
||||
|
||||
6. Use Visual mode to select " item.", yank it with `y`{normal}, move to the end of
|
||||
6. Press `a`{normal} and then type "second". Press `<Esc>`{normal} to leave Insert mode.
|
||||
|
||||
7. Use Visual mode to select " item.", yank it with `y`{normal}, move to the end of
|
||||
the next line with `j$`{normal} and put the text there with `p`{normal}.
|
||||
|
||||
a) this is the first item.
|
||||
b)
|
||||
a) This is the first item.
|
||||
b)
|
||||
|
||||
NOTE: you can also use `y`{normal} as an operator; `yw`{normal} yanks one word.
|
||||
NOTE: you can also use `y`{normal} as an operator; `yw`{normal} yanks one word.
|
||||
|
||||
# Lesson 6.5: SET OPTION
|
||||
|
||||
** Set an option so a search or substitute ignores case **
|
||||
** Set an option so a search or substitute ignores case. **
|
||||
|
||||
1. Search for 'ignore' by entering: `/ignore`
|
||||
1. Search for 'ignore' by entering: `/ignore`
|
||||
Repeat several times by pressing `n`{normal}.
|
||||
|
||||
2. Set the 'ic' (Ignore case) option by entering:
|
||||
~~~ cmd
|
||||
:set ic
|
||||
~~~
|
||||
3. Now search for 'ignore' again by pressing n
|
||||
3. Now search for 'ignore' again by pressing `n`{normal}.
|
||||
Notice that Ignore and IGNORE are now also found.
|
||||
|
||||
4. Set the 'hlsearch' and 'incsearch' options:
|
||||
~~~ cmd
|
||||
:set hls is
|
||||
~~~
|
||||
5. Now type the search command again and see what happens: /ignore <Enter>
|
||||
5. Now type the search command again and see what happens: /ignore <Enter>
|
||||
|
||||
6. To disable ignoring case enter:
|
||||
~~~ cmd
|
||||
@ -818,12 +820,12 @@ a) this is the first item.
|
||||
~~~ cmd
|
||||
:set invic
|
||||
~~~
|
||||
NOTE: To remove the highlighting of matches enter:
|
||||
NOTE: To remove the highlighting of matches enter:
|
||||
~~~ cmd
|
||||
:nohlsearch
|
||||
~~~
|
||||
NOTE: If you want to ignore case for just one search command, use [\c](/\c)
|
||||
in the phrase: /ignore\c <Enter>
|
||||
NOTE: If you want to ignore case for just one search command, use [\c](/\c)
|
||||
in the phrase: /ignore\c <Enter>
|
||||
|
||||
# Lesson 6 SUMMARY
|
||||
|
||||
@ -839,7 +841,7 @@ NOTE: If you want to ignore case for just one search command, use [\c](/\c)
|
||||
|
||||
5. Typing a capital `R`{normal} enters Replace mode until `<Esc>`{normal} is pressed.
|
||||
|
||||
6. Typing "[:set](:set) xxx" sets the option "xxx". Some options are:
|
||||
6. Typing "[:set](:set) xxx" sets the option "xxx". Some options are:
|
||||
|
||||
'ic' 'ignorecase' ignore upper/lower case when searching
|
||||
'is' 'incsearch' show partial matches for a search phrase
|
||||
@ -858,9 +860,9 @@ NOTE: If you want to ignore case for just one search command, use [\c](/\c)
|
||||
|
||||
# Lesson 7.1: GETTING HELP
|
||||
|
||||
** Use the on-line help system **
|
||||
** Use the on-line help system. **
|
||||
|
||||
Vim has a comprehensive on-line help system. To get started, try one of
|
||||
Vim has a comprehensive on-line help system. To get started, try one of
|
||||
these three:
|
||||
- press the `<HELP>`{normal} key (if you have one)
|
||||
- press the `<F1>`{normal} key (if you have one)
|
||||
@ -872,7 +874,7 @@ Type `<Ctrl-w><Ctrl-w>`{normal} to jump from one window to another.
|
||||
Type `:q`{vim} to close the help window.
|
||||
|
||||
You can find help on just about any subject, by giving an argument to the
|
||||
":help" command. Try these (don't forget pressing <Enter>):
|
||||
":help" command. Try these (don't forget pressing <Enter>):
|
||||
~~~ cmd
|
||||
:help w
|
||||
:help c_CTRL-D
|
||||
@ -881,13 +883,13 @@ You can find help on just about any subject, by giving an argument to the
|
||||
~~~
|
||||
# Lesson 7.2: CREATE A STARTUP SCRIPT
|
||||
|
||||
** Enable Vim features **
|
||||
** Enable Vim features. **
|
||||
|
||||
Vim has many more features than Vi, but most of them are disabled by
|
||||
default. To start using more features you have to create a "vimrc" file.
|
||||
default. To start using more features you have to create a "vimrc" file.
|
||||
|
||||
1. Start editing the "vimrc" file. This depends on your system:
|
||||
`:e ~/.config/nvim/init.vim`{vim} for Unix-like systems
|
||||
1. Start editing the "vimrc" file. This depends on your system:
|
||||
`:e ~/.config/nvim/init.vim`{vim} for Unix-like systems
|
||||
|
||||
2. Now read the example "vimrc" file contents:
|
||||
`:r $VIMRUNTIME/vimrc_example.vim`{vim}
|
||||
@ -897,15 +899,15 @@ default. To start using more features you have to create a "vimrc" file.
|
||||
|
||||
The next time you start Vim it will use syntax highlighting.
|
||||
You can add all your preferred settings to this "vimrc" file.
|
||||
For more information type :help vimrc-intro
|
||||
For more information type `:help vimrc-intro`{vim}.
|
||||
|
||||
# Lesson 7.3: COMPLETION
|
||||
|
||||
** Command line completion with `<Ctrl-d>`{normal} and `<Tab>`{normal} **
|
||||
** Command line completion with `<Ctrl-d>`{normal} and `<Tab>`{normal}. **
|
||||
|
||||
1. Look what files exist in the directory: `:!ls`{vim}
|
||||
1. Look what files exist in the directory: `:!ls`{vim}
|
||||
|
||||
2. Type the start of a command: `:e`{vim}
|
||||
2. Type the start of a command: `:e`{vim}
|
||||
|
||||
3. Press `<Ctrl-d>`{normal} and Vim will show a list of commands that start with "e".
|
||||
|
||||
@ -913,20 +915,20 @@ default. To start using more features you have to create a "vimrc" file.
|
||||
|
||||
5. Now add a space and the start of an existing file name: `:edit FIL`{vim}
|
||||
|
||||
6. Press `<Tab>`{normal}. Vim will complete the name (if it is unique).
|
||||
6. Press `<Tab>`{normal}. Vim will complete the name (if it is unique).
|
||||
|
||||
NOTE: Completion works for many commands. It is especially useful for `:help`{vim}.
|
||||
NOTE: Completion works for many commands. It is especially useful for `:help`{vim}.
|
||||
|
||||
# Lesson 7 SUMMARY
|
||||
|
||||
1. Type `:help`{vim}
|
||||
or press `<F1>`{normal} or `<Help>`{normal} to open a help window.
|
||||
|
||||
2. Type `:help TOPIC`{vim} to find help on TOPIC.
|
||||
2. Type `:help TOPIC`{vim} to find help on TOPIC.
|
||||
|
||||
3. Type `<Ctrl-w><Ctrl-w>`{normal} to jump to another window
|
||||
3. Type `<Ctrl-w><Ctrl-w>`{normal} to jump to another window
|
||||
|
||||
4. Type `:q`{vim} to close the help window
|
||||
4. Type `:q`{vim} to close the help window
|
||||
|
||||
5. Create a vimrc startup script to keep your preferred settings.
|
||||
|
||||
@ -937,24 +939,24 @@ NOTE: Completion works for many commands. It is especially useful for `:help`{v
|
||||
|
||||
This was intended to give a brief overview of the Vim editor, just enough to
|
||||
allow you to use the editor fairly easily. It is far from complete as Vim has
|
||||
many many more commands. Consult the help often.
|
||||
many many more commands. Consult the help often.
|
||||
|
||||
There are many resources online to learn more about vim. Here's a bunch of them:
|
||||
|
||||
- *Learn Vim Progressively*: http://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/
|
||||
- *Learning Vim in 2014*: http://benmccormick.org/learning-vim-in-2014/
|
||||
- Vimcasts: http://vimcasts.org/
|
||||
- Vim Video-Tutorials by Derek Wyatt: http://derekwyatt.org/vim/tutorials/
|
||||
- *Vimcasts*: http://vimcasts.org/
|
||||
- *Vim Video-Tutorials by Derek Wyatt*: http://derekwyatt.org/vim/tutorials/
|
||||
- *Learn Vimscript the Hard Way*: http://learnvimscriptthehardway.stevelosh.com/
|
||||
- *7 Habits of Effective Text Editing*: http://www.moolenaar.net/habits.html
|
||||
- *vim-galore*: https://github.com/mhinz/vim-galore
|
||||
|
||||
If you prefer a book, *Practical Vim* by Drew Neil is recommended often (the sequel, *Modern
|
||||
Vim*, includes material specific to nvim!).
|
||||
Vim*, includes material specific to nvim).
|
||||
|
||||
This tutorial was written by Michael C. Pierce and Robert K. Ware, Colorado
|
||||
School of Mines using ideas supplied by Charles Smith, Colorado State
|
||||
University. E-mail: bware@mines.colorado.edu.
|
||||
University. E-mail: bware@mines.colorado.edu.
|
||||
|
||||
Modified for Vim by Bram Moolenaar.
|
||||
Modified for vim-tutor-mode by Felipe Morales.
|
||||
|
@ -11,7 +11,7 @@
|
||||
"215": "There are some words that don't belong in this sentence.",
|
||||
"231": "Somebody typed the end of this line twice.",
|
||||
"271": -1,
|
||||
"290": "this line of words is cleaned up.",
|
||||
"290": "This line of words is cleaned up.",
|
||||
"304": -1,
|
||||
"305": -1,
|
||||
"306": -1,
|
||||
@ -32,14 +32,14 @@
|
||||
"425": "The end of this line needs to be corrected using the c$ command.",
|
||||
"487": -1,
|
||||
"506": -1,
|
||||
"531": "the best time to see the flowers is in the spring.",
|
||||
"531": "Usually the best time to see the flowers is in the spring.",
|
||||
"722": -1,
|
||||
"727": -1,
|
||||
"744": "This line will allow you to practice appending text to a line.",
|
||||
"745": "This line will allow you to practice appending text to a line.",
|
||||
"765": "Adding 123 to 456 gives you 579.",
|
||||
"766": "Adding 123 to 456 gives you 579.",
|
||||
"788": "a) this is the first item.",
|
||||
"789": " b) this is the second item."
|
||||
"790": "a) This is the first item.",
|
||||
"791": " b) This is the second item."
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ preprocess_patch() {
|
||||
|
||||
# Remove *.proto, Make*, gui_*, some if_*
|
||||
local na_src='proto\|Make*\|gui_*\|if_lua\|if_mzsch\|if_olepp\|if_ole\|if_perl\|if_py\|if_ruby\|if_tcl\|if_xcmdsrv'
|
||||
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\S*\<\%('${na_src}'\)@norm! d/\v(^diff)|%$
' +w +q "$file"
|
||||
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\S*\<\%(testdir/\)\@<!\%('${na_src}'\)@norm! d/\v(^diff)|%$
' +w +q "$file"
|
||||
|
||||
# Remove channel.txt, netbeans.txt, os_*.txt, term.txt, todo.txt, version*.txt, tags
|
||||
local na_doc='channel\.txt\|netbeans\.txt\|os_\w\+\.txt\|term\.txt\|todo\.txt\|version\d\.txt\|tags'
|
||||
|
@ -10,6 +10,11 @@ if(USE_GCOV)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# tell MinGW compiler to enable wmain
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode")
|
||||
endif()
|
||||
|
||||
set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
|
||||
set(GENERATOR_DIR ${CMAKE_CURRENT_LIST_DIR}/generators)
|
||||
set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto)
|
||||
|
@ -215,6 +215,7 @@ static void ui_set_option(UI *ui, String name, Object value, Error *error)
|
||||
#undef UI_EXT_OPTION
|
||||
}
|
||||
|
||||
/// Pushes data into UI.UIData, to be consumed later by remote_ui_flush().
|
||||
static void push_call(UI *ui, char *name, Array args)
|
||||
{
|
||||
Array call = ARRAY_DICT_INIT;
|
||||
@ -241,39 +242,7 @@ static void push_call(UI *ui, char *name, Array args)
|
||||
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
|
||||
{
|
||||
Array args = ARRAY_DICT_INIT;
|
||||
Dictionary hl = ARRAY_DICT_INIT;
|
||||
|
||||
if (attrs.bold) {
|
||||
PUT(hl, "bold", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.underline) {
|
||||
PUT(hl, "underline", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.undercurl) {
|
||||
PUT(hl, "undercurl", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.italic) {
|
||||
PUT(hl, "italic", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.reverse) {
|
||||
PUT(hl, "reverse", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.foreground != -1) {
|
||||
PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground));
|
||||
}
|
||||
|
||||
if (attrs.background != -1) {
|
||||
PUT(hl, "background", INTEGER_OBJ(attrs.background));
|
||||
}
|
||||
|
||||
if (attrs.special != -1) {
|
||||
PUT(hl, "special", INTEGER_OBJ(attrs.special));
|
||||
}
|
||||
Dictionary hl = hlattrs2dict(attrs);
|
||||
|
||||
ADD(args, DICTIONARY_OBJ(hl));
|
||||
push_call(ui, "highlight_set", args);
|
||||
|
@ -55,6 +55,47 @@ void nvim_command(String command, Error *err)
|
||||
try_end(err);
|
||||
}
|
||||
|
||||
/// Gets a highlight definition by name.
|
||||
///
|
||||
/// @param name Highlight group name
|
||||
/// @param rgb Export RGB colors
|
||||
/// @param[out] err Error details, if any
|
||||
/// @return Highlight definition map
|
||||
/// @see nvim_get_hl_by_id
|
||||
Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
|
||||
FUNC_API_SINCE(3)
|
||||
{
|
||||
Dictionary result = ARRAY_DICT_INIT;
|
||||
int id = syn_name2id((const char_u *)name.data);
|
||||
|
||||
if (id == 0) {
|
||||
api_set_error(err, kErrorTypeException, "Invalid highlight name: %s",
|
||||
name.data);
|
||||
return result;
|
||||
}
|
||||
result = nvim_get_hl_by_id(id, rgb, err);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Gets a highlight definition by id. |hlID()|
|
||||
///
|
||||
/// @param hl_id Highlight id as returned by |hlID()|
|
||||
/// @param rgb Export RGB colors
|
||||
/// @param[out] err Error details, if any
|
||||
/// @return Highlight definition map
|
||||
/// @see nvim_get_hl_by_name
|
||||
Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err)
|
||||
FUNC_API_SINCE(3)
|
||||
{
|
||||
Dictionary dic = ARRAY_DICT_INIT;
|
||||
if (syn_get_final_id((int)hl_id) == 0) {
|
||||
api_set_error(err, kErrorTypeException, "Invalid highlight id: %d", hl_id);
|
||||
return dic;
|
||||
}
|
||||
int attrcode = syn_id2attr((int)hl_id);
|
||||
return hl_get_attr_by_id(attrcode, rgb, err);
|
||||
}
|
||||
|
||||
/// Passes input keys to Nvim.
|
||||
/// On VimL error: Does not fail, but updates v:errmsg.
|
||||
///
|
||||
@ -255,12 +296,11 @@ free_vim_args:
|
||||
return rv;
|
||||
}
|
||||
|
||||
/// Execute lua code. Parameters might be passed, they are available inside
|
||||
/// the chunk as `...`. The chunk can return a value.
|
||||
/// Execute lua code. Parameters (if any) are available as `...` inside the
|
||||
/// chunk. 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(...)".
|
||||
/// Only statements are executed. To evaluate an expression, prefix it
|
||||
/// with `return`: return my_function(...)
|
||||
///
|
||||
/// @param code lua code to execute
|
||||
/// @param args Arguments to the code
|
||||
@ -423,29 +463,18 @@ void nvim_del_var(String name, Error *err)
|
||||
dict_set_var(&globvardict, name, NIL, true, false, err);
|
||||
}
|
||||
|
||||
/// Sets a global variable
|
||||
///
|
||||
/// @deprecated
|
||||
///
|
||||
/// @param name Variable name
|
||||
/// @param value Variable value
|
||||
/// @param[out] err Error details, if any
|
||||
/// @see nvim_set_var
|
||||
/// @return Old value or nil if there was no previous value.
|
||||
///
|
||||
/// @warning It may return nil if there was no previous value
|
||||
/// or if previous value was `v:null`.
|
||||
/// @warning May return nil if there was no previous value
|
||||
/// OR if previous value was `v:null`.
|
||||
Object vim_set_var(String name, Object value, Error *err)
|
||||
{
|
||||
return dict_set_var(&globvardict, name, value, false, true, err);
|
||||
}
|
||||
|
||||
/// Removes a global variable
|
||||
///
|
||||
/// @deprecated
|
||||
///
|
||||
/// @param name Variable name
|
||||
/// @param[out] err Error details, if any
|
||||
/// @return Old value
|
||||
/// @see nvim_del_var
|
||||
Object vim_del_var(String name, Error *err)
|
||||
{
|
||||
return dict_set_var(&globvardict, name, NIL, true, true, err);
|
||||
@ -484,7 +513,8 @@ void nvim_set_option(String name, Object value, Error *err)
|
||||
set_option_to(NULL, SREQ_GLOBAL, name, value, err);
|
||||
}
|
||||
|
||||
/// Writes a message to vim output buffer
|
||||
/// Writes a message to the Vim output buffer. Does not append "\n", the
|
||||
/// message is buffered (won't display) until a linefeed is written.
|
||||
///
|
||||
/// @param str Message
|
||||
void nvim_out_write(String str)
|
||||
@ -493,7 +523,8 @@ void nvim_out_write(String str)
|
||||
write_msg(str, false);
|
||||
}
|
||||
|
||||
/// Writes a message to vim error buffer
|
||||
/// Writes a message to the Vim error buffer. Does not append "\n", the
|
||||
/// message is buffered (won't display) until a linefeed is written.
|
||||
///
|
||||
/// @param str Message
|
||||
void nvim_err_write(String str)
|
||||
@ -502,8 +533,8 @@ void nvim_err_write(String str)
|
||||
write_msg(str, true);
|
||||
}
|
||||
|
||||
/// Writes a message to vim error buffer. Appends a linefeed to ensure all
|
||||
/// contents are written.
|
||||
/// Writes a message to the Vim error buffer. Appends "\n", so the buffer is
|
||||
/// flushed (and displayed).
|
||||
///
|
||||
/// @param str Message
|
||||
/// @see nvim_err_write()
|
||||
|
41
src/nvim/aucmd.c
Normal file
41
src/nvim/aucmd.c
Normal file
@ -0,0 +1,41 @@
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
||||
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/fileio.h"
|
||||
#include "nvim/vim.h"
|
||||
#include "nvim/main.h"
|
||||
#include "nvim/ui.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "aucmd.c.generated.h"
|
||||
#endif
|
||||
|
||||
static void focusgained_event(void **argv)
|
||||
{
|
||||
bool *gainedp = argv[0];
|
||||
do_autocmd_focusgained(*gainedp);
|
||||
xfree(gainedp);
|
||||
}
|
||||
void aucmd_schedule_focusgained(bool gained)
|
||||
{
|
||||
bool *gainedp = xmalloc(sizeof(*gainedp));
|
||||
*gainedp = gained;
|
||||
loop_schedule_deferred(&main_loop,
|
||||
event_create(focusgained_event, 1, gainedp));
|
||||
}
|
||||
|
||||
static void do_autocmd_focusgained(bool gained)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
static bool recursive = false;
|
||||
|
||||
if (recursive) {
|
||||
return; // disallow recursion
|
||||
}
|
||||
recursive = true;
|
||||
apply_autocmds((gained ? EVENT_FOCUSGAINED : EVENT_FOCUSLOST),
|
||||
NULL, NULL, false, curbuf);
|
||||
recursive = false;
|
||||
}
|
||||
|
9
src/nvim/aucmd.h
Normal file
9
src/nvim/aucmd.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef NVIM_AUCMD_H
|
||||
#define NVIM_AUCMD_H
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "aucmd.h.generated.h"
|
||||
#endif
|
||||
|
||||
#endif // NVIM_AUCMD_H
|
||||
|
@ -3069,8 +3069,8 @@ static bool ti_change(char_u *str, char_u **last)
|
||||
/// Set current window title
|
||||
void resettitle(void)
|
||||
{
|
||||
ui_call_set_title(cstr_as_string((char *)lasttitle));
|
||||
ui_call_set_icon(cstr_as_string((char *)lasticon));
|
||||
ui_call_set_title(cstr_as_string((char *)lasttitle));
|
||||
ui_flush();
|
||||
}
|
||||
|
||||
|
@ -762,7 +762,7 @@ bool vim_isIDc(int c)
|
||||
}
|
||||
|
||||
/// Check that "c" is a keyword character:
|
||||
/// Letters and characters from 'iskeyword' option for current buffer.
|
||||
/// Letters and characters from 'iskeyword' option for the current buffer.
|
||||
/// For multi-byte characters mb_get_class() is used (builtin rules).
|
||||
///
|
||||
/// @param c character to check
|
||||
|
@ -135,6 +135,20 @@ void diff_buf_add(buf_T *buf)
|
||||
EMSGN(_("E96: Cannot diff more than %" PRId64 " buffers"), DB_COUNT);
|
||||
}
|
||||
|
||||
///
|
||||
/// Remove all buffers to make diffs for.
|
||||
///
|
||||
static void diff_buf_clear(void)
|
||||
{
|
||||
for (int i = 0; i < DB_COUNT; i++) {
|
||||
if (curtab->tp_diffbuf[i] != NULL) {
|
||||
curtab->tp_diffbuf[i] = NULL;
|
||||
curtab->tp_diff_invalid = true;
|
||||
diff_redraw(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find buffer "buf" in the list of diff buffers for the current tab page.
|
||||
///
|
||||
/// @param buf The buffer to find.
|
||||
@ -1175,6 +1189,11 @@ void ex_diffoff(exarg_T *eap)
|
||||
diffwin |= wp->w_p_diff;
|
||||
}
|
||||
|
||||
// Also remove hidden buffers from the list.
|
||||
if (eap->forceit) {
|
||||
diff_buf_clear();
|
||||
}
|
||||
|
||||
// Remove "hor" from from 'scrollopt' if there are no diff windows left.
|
||||
if (!diffwin && (vim_strchr(p_sbo, 'h') != NULL)) {
|
||||
do_cmdline_cmd("set sbo-=hor");
|
||||
|
@ -974,14 +974,6 @@ static int insert_handle_key(InsertState *s)
|
||||
multiqueue_process_events(main_loop.events);
|
||||
break;
|
||||
|
||||
case K_FOCUSGAINED: // Neovim has been given focus
|
||||
apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
|
||||
break;
|
||||
|
||||
case K_FOCUSLOST: // Neovim has lost focus
|
||||
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
|
||||
break;
|
||||
|
||||
case K_HOME: // <Home>
|
||||
case K_KHOME:
|
||||
case K_S_HOME:
|
||||
@ -2406,6 +2398,7 @@ void set_completion(colnr_T startcol, list_T *list)
|
||||
ins_compl_prep(' ');
|
||||
}
|
||||
ins_compl_clear();
|
||||
ins_compl_free();
|
||||
|
||||
compl_direction = FORWARD;
|
||||
if (startcol > curwin->w_cursor.col)
|
||||
@ -3166,8 +3159,7 @@ static bool ins_compl_prep(int c)
|
||||
|
||||
/* Ignore end of Select mode mapping and mouse scroll buttons. */
|
||||
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
|
||||
|| c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
|
||||
|| c == K_FOCUSGAINED || c == K_FOCUSLOST) {
|
||||
|| c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -6733,6 +6733,39 @@ static void prepare_assert_error(garray_T *gap)
|
||||
}
|
||||
}
|
||||
|
||||
// Append "str" to "gap", escaping unprintable characters.
|
||||
// Changes NL to \n, CR to \r, etc.
|
||||
static void ga_concat_esc(garray_T *gap, char_u *str)
|
||||
{
|
||||
char_u *p;
|
||||
char_u buf[NUMBUFLEN];
|
||||
|
||||
if (str == NULL) {
|
||||
ga_concat(gap, (char_u *)"NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
for (p = str; *p != NUL; p++) {
|
||||
switch (*p) {
|
||||
case BS: ga_concat(gap, (char_u *)"\\b"); break;
|
||||
case ESC: ga_concat(gap, (char_u *)"\\e"); break;
|
||||
case FF: ga_concat(gap, (char_u *)"\\f"); break;
|
||||
case NL: ga_concat(gap, (char_u *)"\\n"); break;
|
||||
case TAB: ga_concat(gap, (char_u *)"\\t"); break;
|
||||
case CAR: ga_concat(gap, (char_u *)"\\r"); break;
|
||||
case '\\': ga_concat(gap, (char_u *)"\\\\"); break;
|
||||
default:
|
||||
if (*p < ' ') {
|
||||
vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
|
||||
ga_concat(gap, buf);
|
||||
} else {
|
||||
ga_append(gap, *p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill "gap" with information about an assert error.
|
||||
static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
|
||||
char_u *exp_str, typval_T *exp_tv,
|
||||
@ -6747,28 +6780,30 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
|
||||
} else {
|
||||
if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) {
|
||||
ga_concat(gap, (char_u *)"Pattern ");
|
||||
} else if (atype == ASSERT_NOTEQUAL) {
|
||||
ga_concat(gap, (char_u *)"Expected not equal to ");
|
||||
} else {
|
||||
ga_concat(gap, (char_u *)"Expected ");
|
||||
}
|
||||
if (exp_str == NULL) {
|
||||
tofree = (char_u *) encode_tv2string(exp_tv, NULL);
|
||||
ga_concat(gap, tofree);
|
||||
tofree = (char_u *)encode_tv2string(exp_tv, NULL);
|
||||
ga_concat_esc(gap, tofree);
|
||||
xfree(tofree);
|
||||
} else {
|
||||
ga_concat(gap, exp_str);
|
||||
ga_concat_esc(gap, exp_str);
|
||||
}
|
||||
tofree = (char_u *)encode_tv2string(got_tv, NULL);
|
||||
if (atype == ASSERT_MATCH) {
|
||||
ga_concat(gap, (char_u *)" does not match ");
|
||||
} else if (atype == ASSERT_NOTMATCH) {
|
||||
ga_concat(gap, (char_u *)" does match ");
|
||||
} else if (atype == ASSERT_NOTEQUAL) {
|
||||
ga_concat(gap, (char_u *)" differs from ");
|
||||
} else {
|
||||
ga_concat(gap, (char_u *)" but got ");
|
||||
if (atype != ASSERT_NOTEQUAL) {
|
||||
if (atype == ASSERT_MATCH) {
|
||||
ga_concat(gap, (char_u *)" does not match ");
|
||||
} else if (atype == ASSERT_NOTMATCH) {
|
||||
ga_concat(gap, (char_u *)" does match ");
|
||||
} else {
|
||||
ga_concat(gap, (char_u *)" but got ");
|
||||
}
|
||||
tofree = (char_u *)encode_tv2string(got_tv, NULL);
|
||||
ga_concat_esc(gap, tofree);
|
||||
xfree(tofree);
|
||||
}
|
||||
ga_concat(gap, tofree);
|
||||
xfree(tofree);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17493,7 +17528,7 @@ static void f_winsaveview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
tv_dict_add_nr(dict, S_LEN("skipcol"), (varnumber_T)curwin->w_skipcol);
|
||||
}
|
||||
|
||||
/// Writes list of strings to file
|
||||
/// Write "list" of strings to file "fd".
|
||||
///
|
||||
/// @param fp File to write to.
|
||||
/// @param[in] list List to write.
|
||||
@ -22775,7 +22810,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
|
||||
|
||||
bool eval_has_provider(const char *name)
|
||||
{
|
||||
#define check_provider(name) \
|
||||
#define CHECK_PROVIDER(name) \
|
||||
if (has_##name == -1) { \
|
||||
has_##name = !!find_func((char_u *)"provider#" #name "#Call"); \
|
||||
if (!has_##name) { \
|
||||
@ -22791,17 +22826,17 @@ bool eval_has_provider(const char *name)
|
||||
static int has_python3 = -1;
|
||||
static int has_ruby = -1;
|
||||
|
||||
if (!strcmp(name, "clipboard")) {
|
||||
check_provider(clipboard);
|
||||
if (strequal(name, "clipboard")) {
|
||||
CHECK_PROVIDER(clipboard);
|
||||
return has_clipboard;
|
||||
} else if (!strcmp(name, "python3")) {
|
||||
check_provider(python3);
|
||||
} else if (strequal(name, "python3")) {
|
||||
CHECK_PROVIDER(python3);
|
||||
return has_python3;
|
||||
} else if (!strcmp(name, "python")) {
|
||||
check_provider(python);
|
||||
} else if (strequal(name, "python")) {
|
||||
CHECK_PROVIDER(python);
|
||||
return has_python;
|
||||
} else if (!strcmp(name, "ruby")) {
|
||||
check_provider(ruby);
|
||||
} else if (strequal(name, "ruby")) {
|
||||
CHECK_PROVIDER(ruby);
|
||||
return has_ruby;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,14 @@ void loop_poll_events(Loop *loop, int ms)
|
||||
multiqueue_process_events(loop->fast_events);
|
||||
}
|
||||
|
||||
// Schedule an event from another thread
|
||||
/// Schedules an event from another thread.
|
||||
///
|
||||
/// @note Event is queued into `fast_events`, which is processed outside of the
|
||||
/// primary `events` queue by loop_poll_events(). For `main_loop`, that
|
||||
/// means `fast_events` is NOT processed in an "editor mode"
|
||||
/// (VimState.execute), so redraw and other side-effects are likely to be
|
||||
/// skipped.
|
||||
/// @see loop_schedule_deferred
|
||||
void loop_schedule(Loop *loop, Event event)
|
||||
{
|
||||
uv_mutex_lock(&loop->mutex);
|
||||
@ -68,6 +75,24 @@ void loop_schedule(Loop *loop, Event event)
|
||||
uv_mutex_unlock(&loop->mutex);
|
||||
}
|
||||
|
||||
/// Schedules an event from another thread. Unlike loop_schedule(), the event
|
||||
/// is forwarded to `Loop.events`, instead of being processed immediately.
|
||||
///
|
||||
/// @see loop_schedule
|
||||
void loop_schedule_deferred(Loop *loop, Event event)
|
||||
{
|
||||
Event *eventp = xmalloc(sizeof(*eventp));
|
||||
*eventp = event;
|
||||
loop_schedule(loop, event_create(loop_deferred_event, 2, loop, eventp));
|
||||
}
|
||||
static void loop_deferred_event(void **argv)
|
||||
{
|
||||
Loop *loop = argv[0];
|
||||
Event *eventp = argv[1];
|
||||
multiqueue_put_event(loop->events, *eventp);
|
||||
xfree(eventp);
|
||||
}
|
||||
|
||||
void loop_on_put(MultiQueue *queue, void *data)
|
||||
{
|
||||
Loop *loop = data;
|
||||
|
@ -16,10 +16,28 @@ KLIST_INIT(WatcherPtr, WatcherPtr, _noop)
|
||||
|
||||
typedef struct loop {
|
||||
uv_loop_t uv;
|
||||
MultiQueue *events, *fast_events, *thread_events;
|
||||
MultiQueue *events;
|
||||
MultiQueue *thread_events;
|
||||
// Immediate events:
|
||||
// "Events that should be processed after exiting uv_run() (to avoid
|
||||
// recursion), but before returning from loop_poll_events()."
|
||||
// 502aee690c980fcb3cfcb3f211dcfad06103db46
|
||||
// Practical consequence: these events are processed by
|
||||
// state_enter()..os_inchar()
|
||||
// whereas "regular" (main_loop.events) events are processed by
|
||||
// state_enter()..VimState.execute()
|
||||
// But state_enter()..os_inchar() can be "too early" if you want the event
|
||||
// to trigger UI updates and other user-activity-related side-effects.
|
||||
MultiQueue *fast_events;
|
||||
|
||||
// used by process/job-control subsystem
|
||||
klist_t(WatcherPtr) *children;
|
||||
uv_signal_t children_watcher;
|
||||
uv_timer_t children_kill_timer, poll_timer;
|
||||
uv_timer_t children_kill_timer;
|
||||
|
||||
// generic timer, used by loop_poll_events()
|
||||
uv_timer_t poll_timer;
|
||||
|
||||
size_t children_stop_requests;
|
||||
uv_async_t async;
|
||||
uv_mutex_t mutex;
|
||||
|
@ -233,8 +233,7 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
|
||||
switch (proc->type) {
|
||||
case kProcessTypeUv:
|
||||
// Close the process's stdin. If the process doesn't close its own
|
||||
// stdout/stderr, they will be closed when it exits(possibly due to being
|
||||
// terminated after a timeout)
|
||||
// stdout/stderr, they will be closed when it exits (voluntarily or not).
|
||||
process_close_in(proc);
|
||||
ILOG("Sending SIGTERM to pid %d", proc->pid);
|
||||
uv_kill(proc->pid, SIGTERM);
|
||||
|
@ -118,7 +118,7 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
|
||||
// to `alloc_cb` will return the same unused pointer(`rbuffer_produced`
|
||||
// won't be called)
|
||||
&& cnt != 0) {
|
||||
DLOG("Closing Stream (%p): %s (%s)", stream,
|
||||
DLOG("closing Stream: %p: %s (%s)", stream,
|
||||
uv_err_name((int)cnt), os_strerror((int)cnt));
|
||||
// Read error or EOF, either way stop the stream and invoke the callback
|
||||
// with eof == true
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include "nvim/log.h"
|
||||
#include "nvim/rbuffer.h"
|
||||
#include "nvim/macros.h"
|
||||
#include "nvim/event/stream.h"
|
||||
@ -81,6 +82,7 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
assert(!stream->closed);
|
||||
DLOG("closing Stream: %p", stream);
|
||||
stream->closed = true;
|
||||
stream->close_cb = on_stream_close;
|
||||
stream->close_cb_data = data;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include "nvim/log.h"
|
||||
#include "nvim/event/loop.h"
|
||||
#include "nvim/event/wstream.h"
|
||||
#include "nvim/vim.h"
|
||||
|
@ -3332,10 +3332,12 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
|
||||
sub = regtilde(sub, p_magic);
|
||||
|
||||
// Check for a match on each line.
|
||||
// If preview: limit to max('cmdwinheight', viewport).
|
||||
linenr_T line2 = eap->line2;
|
||||
for (linenr_T lnum = eap->line1;
|
||||
lnum <= line2 && !(got_quit || aborting())
|
||||
&& (!preview || matched_lines.size <= (size_t)p_cwh);
|
||||
lnum <= line2 && !got_quit && !aborting()
|
||||
&& (!preview || matched_lines.size < (size_t)p_cwh
|
||||
|| lnum <= curwin->w_botline);
|
||||
lnum++) {
|
||||
long nmatch = vim_regexec_multi(®match, curwin, curbuf, lnum,
|
||||
(colnr_T)0, NULL);
|
||||
@ -3500,6 +3502,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
|
||||
setmouse(); /* disable mouse in xterm */
|
||||
curwin->w_cursor.col = regmatch.startpos[0].col;
|
||||
|
||||
if (curwin->w_p_crb) {
|
||||
do_check_cursorbind();
|
||||
}
|
||||
|
||||
/* When 'cpoptions' contains "u" don't sync undo when
|
||||
* asking for confirmation. */
|
||||
if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
|
||||
@ -3659,6 +3665,42 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
|
||||
* use "\=col("."). */
|
||||
curwin->w_cursor.col = regmatch.startpos[0].col;
|
||||
|
||||
// When the match included the "$" of the last line it may
|
||||
// go beyond the last line of the buffer.
|
||||
if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1) {
|
||||
nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1;
|
||||
skip_match = true;
|
||||
}
|
||||
|
||||
#define ADJUST_SUB_FIRSTLNUM() \
|
||||
do { \
|
||||
/* For a multi-line match, make a copy of the last matched */ \
|
||||
/* line and continue in that one. */ \
|
||||
if (nmatch > 1) { \
|
||||
sub_firstlnum += nmatch - 1; \
|
||||
xfree(sub_firstline); \
|
||||
sub_firstline = vim_strsave(ml_get(sub_firstlnum)); \
|
||||
/* When going beyond the last line, stop substituting. */ \
|
||||
if (sub_firstlnum <= line2) { \
|
||||
do_again = true; \
|
||||
} else { \
|
||||
subflags.do_all = false; \
|
||||
} \
|
||||
} \
|
||||
if (skip_match) { \
|
||||
/* Already hit end of the buffer, sub_firstlnum is one */ \
|
||||
/* less than what it ought to be. */ \
|
||||
xfree(sub_firstline); \
|
||||
sub_firstline = vim_strsave((char_u *)""); \
|
||||
copycol = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
if (preview && !has_second_delim) {
|
||||
ADJUST_SUB_FIRSTLNUM();
|
||||
goto skip;
|
||||
}
|
||||
|
||||
// 3. Substitute the string. During 'inccommand' preview only do this if
|
||||
// there is a replace pattern.
|
||||
if (!preview || has_second_delim) {
|
||||
@ -3685,13 +3727,6 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
|
||||
goto skip;
|
||||
}
|
||||
|
||||
// When the match included the "$" of the last line it may
|
||||
// go beyond the last line of the buffer.
|
||||
if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1) {
|
||||
nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1;
|
||||
skip_match = true;
|
||||
}
|
||||
|
||||
// Need room for:
|
||||
// - result so far in new_start (not for first sub in line)
|
||||
// - original text up to match
|
||||
@ -3722,30 +3757,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
|
||||
// is beyond the end of the line after the substitution.
|
||||
curwin->w_cursor.col = 0;
|
||||
|
||||
// For a multi-line match, make a copy of the last matched
|
||||
// line and continue in that one.
|
||||
if (nmatch > 1) {
|
||||
sub_firstlnum += nmatch - 1;
|
||||
xfree(sub_firstline);
|
||||
sub_firstline = vim_strsave(ml_get(sub_firstlnum));
|
||||
// When going beyond the last line, stop substituting.
|
||||
if (sub_firstlnum <= line2) {
|
||||
do_again = true;
|
||||
} else {
|
||||
subflags.do_all = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remember next character to be copied.
|
||||
copycol = regmatch.endpos[0].col;
|
||||
|
||||
if (skip_match) {
|
||||
// Already hit end of the buffer, sub_firstlnum is one
|
||||
// less than what it ought to be.
|
||||
xfree(sub_firstline);
|
||||
sub_firstline = vim_strsave((char_u *)"");
|
||||
copycol = 0;
|
||||
}
|
||||
ADJUST_SUB_FIRSTLNUM();
|
||||
|
||||
// Now the trick is to replace CTRL-M chars with a real line
|
||||
// break. This would make it impossible to insert a CTRL-M in
|
||||
@ -4002,6 +4017,7 @@ skip:
|
||||
kv_destroy(matched_lines);
|
||||
|
||||
return preview_buf;
|
||||
#undef ADJUST_SUB_FIRSTLNUM
|
||||
} // NOLINT(readability/fn_size)
|
||||
|
||||
/*
|
||||
|
@ -2319,16 +2319,6 @@ static void source_callback(char_u *fname, void *cookie)
|
||||
(void)do_source(fname, false, DOSO_NONE);
|
||||
}
|
||||
|
||||
/// Source the file "name" from all directories in 'runtimepath'.
|
||||
/// "name" can contain wildcards.
|
||||
/// When "flags" has DIP_ALL: source all files, otherwise only the first one.
|
||||
///
|
||||
/// return FAIL when no file could be sourced, OK otherwise.
|
||||
int source_runtime(char_u *name, int flags)
|
||||
{
|
||||
return do_in_runtimepath(name, flags, source_callback, NULL);
|
||||
}
|
||||
|
||||
/// Find the file "name" in all directories in "path" and invoke
|
||||
/// "callback(fname, cookie)".
|
||||
/// "name" can contain wildcards.
|
||||
@ -2434,21 +2424,21 @@ int do_in_path(char_u *path, char_u *name, int flags,
|
||||
return did_one ? OK : FAIL;
|
||||
}
|
||||
|
||||
/// Find "name" in 'runtimepath'. When found, invoke the callback function for
|
||||
/// Find "name" in "path". When found, invoke the callback function for
|
||||
/// it: callback(fname, "cookie")
|
||||
/// When "flags" has DIP_ALL repeat for all matches, otherwise only the first
|
||||
/// one is used.
|
||||
/// Returns OK when at least one match found, FAIL otherwise.
|
||||
/// If "name" is NULL calls callback for each entry in runtimepath. Cookie is
|
||||
/// If "name" is NULL calls callback for each entry in "path". Cookie is
|
||||
/// passed by reference in this case, setting it to NULL indicates that callback
|
||||
/// has done its job.
|
||||
int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
|
||||
void *cookie)
|
||||
int do_in_path_and_pp(char_u *path, char_u *name, int flags,
|
||||
DoInRuntimepathCB callback, void *cookie)
|
||||
{
|
||||
int done = FAIL;
|
||||
|
||||
if ((flags & DIP_NORTP) == 0) {
|
||||
done = do_in_path(p_rtp, name, flags, callback, cookie);
|
||||
done = do_in_path(path, name, flags, callback, cookie);
|
||||
}
|
||||
|
||||
if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START)) {
|
||||
@ -2476,6 +2466,29 @@ int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
|
||||
return done;
|
||||
}
|
||||
|
||||
/// Just like do_in_path_and_pp(), using 'runtimepath' for "path".
|
||||
int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
|
||||
void *cookie)
|
||||
{
|
||||
return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
|
||||
}
|
||||
|
||||
/// Source the file "name" from all directories in 'runtimepath'.
|
||||
/// "name" can contain wildcards.
|
||||
/// When "flags" has DIP_ALL: source all files, otherwise only the first one.
|
||||
///
|
||||
/// return FAIL when no file could be sourced, OK otherwise.
|
||||
int source_runtime(char_u *name, int flags)
|
||||
{
|
||||
return source_in_path(p_rtp, name, flags);
|
||||
}
|
||||
|
||||
/// Just like source_runtime(), but use "path" instead of 'runtimepath'.
|
||||
int source_in_path(char_u *path, char_u *name, int flags)
|
||||
{
|
||||
return do_in_path_and_pp(path, name, flags, source_callback, NULL);
|
||||
}
|
||||
|
||||
// Expand wildcards in "pat" and invoke do_source() for each match.
|
||||
static void source_all_matches(char_u *pat)
|
||||
{
|
||||
@ -2498,6 +2511,7 @@ static int APP_BOTH;
|
||||
static void add_pack_plugin(char_u *fname, void *cookie)
|
||||
{
|
||||
char_u *p4, *p3, *p2, *p1, *p;
|
||||
char_u *buf = NULL;
|
||||
|
||||
char *const ffname = fix_fname((char *)fname);
|
||||
|
||||
@ -2525,26 +2539,30 @@ static void add_pack_plugin(char_u *fname, void *cookie)
|
||||
// Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
|
||||
size_t fname_len = strlen(ffname);
|
||||
const char *insp = (const char *)p_rtp;
|
||||
for (;;) {
|
||||
if (path_fnamencmp(insp, ffname, fname_len) == 0) {
|
||||
buf = try_malloc(MAXPATHL);
|
||||
if (buf == NULL) {
|
||||
goto theend;
|
||||
}
|
||||
while (*insp != NUL) {
|
||||
copy_option_part((char_u **)&insp, buf, MAXPATHL, ",");
|
||||
add_pathsep((char *)buf);
|
||||
char *const rtp_ffname = fix_fname((char *)buf);
|
||||
if (rtp_ffname == NULL) {
|
||||
goto theend;
|
||||
}
|
||||
bool match = path_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
|
||||
xfree(rtp_ffname);
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
insp = strchr(insp, ',');
|
||||
if (insp == NULL) {
|
||||
break;
|
||||
}
|
||||
insp++;
|
||||
}
|
||||
|
||||
if (insp == NULL) {
|
||||
if (*insp == NUL) {
|
||||
// not found, append at the end
|
||||
insp = (const char *)p_rtp + STRLEN(p_rtp);
|
||||
} else {
|
||||
// append after the matching directory.
|
||||
insp += strlen(ffname);
|
||||
while (*insp != NUL && *insp != ',') {
|
||||
insp++;
|
||||
}
|
||||
insp--;
|
||||
}
|
||||
*p4 = c;
|
||||
|
||||
@ -2614,26 +2632,35 @@ static void add_pack_plugin(char_u *fname, void *cookie)
|
||||
}
|
||||
|
||||
theend:
|
||||
xfree(buf);
|
||||
xfree(ffname);
|
||||
}
|
||||
|
||||
static bool did_source_packages = false;
|
||||
/// Add all packages in the "start" directory to 'runtimepath'.
|
||||
void add_pack_start_dirs(void)
|
||||
{
|
||||
do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
|
||||
add_pack_plugin, &APP_ADD_DIR);
|
||||
}
|
||||
|
||||
/// Load plugins from all packages in the "start" directory.
|
||||
void load_start_packages(void)
|
||||
{
|
||||
did_source_packages = true;
|
||||
do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
|
||||
add_pack_plugin, &APP_LOAD);
|
||||
}
|
||||
|
||||
// ":packloadall"
|
||||
// Find plugins in the package directories and source them.
|
||||
// "eap" is NULL when invoked during startup.
|
||||
void ex_packloadall(exarg_T *eap)
|
||||
{
|
||||
if (!did_source_packages || (eap != NULL && eap->forceit)) {
|
||||
did_source_packages = true;
|
||||
|
||||
if (!did_source_packages || eap->forceit) {
|
||||
// First do a round to add all directories to 'runtimepath', then load
|
||||
// the plugins. This allows for plugins to use an autoload directory
|
||||
// of another plugin.
|
||||
do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
|
||||
add_pack_plugin, &APP_ADD_DIR);
|
||||
do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
|
||||
add_pack_plugin, &APP_LOAD);
|
||||
add_pack_start_dirs();
|
||||
load_start_packages();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1668,8 +1668,8 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
||||
if (*ea.cmd == ';') {
|
||||
if (!ea.skip) {
|
||||
curwin->w_cursor.lnum = ea.line2;
|
||||
// Don't leave the cursor on an illegal line (caused by ';')
|
||||
check_cursor_lnum();
|
||||
// don't leave the cursor on an illegal line or column
|
||||
check_cursor();
|
||||
}
|
||||
} else if (*ea.cmd != ',') {
|
||||
break;
|
||||
@ -1813,7 +1813,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
||||
if (text_locked() && !(ea.argt & CMDWIN)
|
||||
&& !IS_USER_CMDIDX(ea.cmdidx)) {
|
||||
// Command not allowed when editing the command line.
|
||||
errormsg = get_text_locked_msg();
|
||||
errormsg = (char_u *)_(get_text_locked_msg());
|
||||
goto doend;
|
||||
}
|
||||
/* Disallow editing another buffer when "curbuf_lock" is set.
|
||||
@ -8810,11 +8810,12 @@ makeopens (
|
||||
&& buf->b_fname != NULL
|
||||
&& buf->b_p_bl) {
|
||||
if (fprintf(fd, "badd +%" PRId64 " ",
|
||||
buf->b_wininfo == NULL ?
|
||||
(int64_t)1L :
|
||||
(int64_t)buf->b_wininfo->wi_fpos.lnum) < 0
|
||||
|| ses_fname(fd, buf, &ssop_flags) == FAIL)
|
||||
buf->b_wininfo == NULL
|
||||
? (int64_t)1L
|
||||
: (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0
|
||||
|| ses_fname(fd, buf, &ssop_flags, true) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8885,11 +8886,13 @@ makeopens (
|
||||
&& !bt_nofile(wp->w_buffer)
|
||||
) {
|
||||
if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0
|
||||
|| ses_fname(fd, wp->w_buffer, &ssop_flags) == FAIL)
|
||||
|| ses_fname(fd, wp->w_buffer, &ssop_flags, true) == FAIL) {
|
||||
return FAIL;
|
||||
need_tabnew = FALSE;
|
||||
if (!wp->w_arg_idx_invalid)
|
||||
}
|
||||
need_tabnew = false;
|
||||
if (!wp->w_arg_idx_invalid) {
|
||||
edited_win = wp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -8933,6 +8936,8 @@ makeopens (
|
||||
// resized when moving between windows.
|
||||
// Do this before restoring the view, so that the topline and the
|
||||
// cursor can be set. This is done again below.
|
||||
// winminheight and winminwidth need to be set to avoid an error if the
|
||||
// user has set winheight or winwidth.
|
||||
if (put_line(fd, "set winminheight=1 winminwidth=1 winheight=1 winwidth=1")
|
||||
== FAIL) {
|
||||
return FAIL;
|
||||
@ -9221,24 +9226,35 @@ put_view (
|
||||
if (wp->w_buffer->b_ffname != NULL
|
||||
&& (!bt_nofile(wp->w_buffer) || wp->w_buffer->terminal)
|
||||
) {
|
||||
/*
|
||||
* Editing a file in this buffer: use ":edit file".
|
||||
* This may have side effects! (e.g., compressed or network file).
|
||||
*/
|
||||
if (fputs("edit ", fd) < 0
|
||||
|| ses_fname(fd, wp->w_buffer, flagp) == FAIL)
|
||||
// Editing a file in this buffer: use ":edit file".
|
||||
// This may have side effects! (e.g., compressed or network file).
|
||||
//
|
||||
// Note, if a buffer for that file already exists, use :badd to
|
||||
// edit that buffer, to not lose folding information (:edit resets
|
||||
// folds in other buffers)
|
||||
if (fputs("if bufexists('", fd) < 0
|
||||
|| ses_fname(fd, wp->w_buffer, flagp, false) == FAIL
|
||||
|| fputs("') | buffer ", fd) < 0
|
||||
|| ses_fname(fd, wp->w_buffer, flagp, false) == FAIL
|
||||
|| fputs(" | else | edit ", fd) < 0
|
||||
|| ses_fname(fd, wp->w_buffer, flagp, false) == FAIL
|
||||
|| fputs(" | endif", fd) < 0
|
||||
|| put_eol(fd) == FAIL) {
|
||||
return FAIL;
|
||||
} else {
|
||||
/* No file in this buffer, just make it empty. */
|
||||
if (put_line(fd, "enew") == FAIL)
|
||||
return FAIL;
|
||||
if (wp->w_buffer->b_ffname != NULL) {
|
||||
/* The buffer does have a name, but it's not a file name. */
|
||||
if (fputs("file ", fd) < 0
|
||||
|| ses_fname(fd, wp->w_buffer, flagp) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
do_cursor = FALSE;
|
||||
} else {
|
||||
// No file in this buffer, just make it empty.
|
||||
if (put_line(fd, "enew") == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
if (wp->w_buffer->b_ffname != NULL) {
|
||||
// The buffer does have a name, but it's not a file name.
|
||||
if (fputs("file ", fd) < 0
|
||||
|| ses_fname(fd, wp->w_buffer, flagp, true) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
do_cursor = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9378,7 +9394,7 @@ ses_arglist (
|
||||
(void)vim_FullName((char *)s, (char *)buf, MAXPATHL, FALSE);
|
||||
s = buf;
|
||||
}
|
||||
if (fputs("argadd ", fd) < 0 || ses_put_fname(fd, s, flagp) == FAIL
|
||||
if (fputs("$argadd ", fd) < 0 || ses_put_fname(fd, s, flagp) == FAIL
|
||||
|| put_eol(fd) == FAIL) {
|
||||
xfree(buf);
|
||||
return FAIL;
|
||||
@ -9389,12 +9405,10 @@ ses_arglist (
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a buffer name to the session file.
|
||||
* Also ends the line.
|
||||
* Returns FAIL if writing fails.
|
||||
*/
|
||||
static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp)
|
||||
/// Write a buffer name to the session file.
|
||||
/// Also ends the line, if "add_eol" is true.
|
||||
/// Returns FAIL if writing fails.
|
||||
static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, bool add_eol)
|
||||
{
|
||||
char_u *name;
|
||||
|
||||
@ -9411,8 +9425,10 @@ static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp)
|
||||
name = buf->b_sfname;
|
||||
else
|
||||
name = buf->b_ffname;
|
||||
if (ses_put_fname(fd, name, flagp) == FAIL || put_eol(fd) == FAIL)
|
||||
if (ses_put_fname(fd, name, flagp) == FAIL
|
||||
|| (add_eol && put_eol(fd) == FAIL)) {
|
||||
return FAIL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -9835,7 +9851,7 @@ static void ex_terminal(exarg_T *eap)
|
||||
if (*eap->arg != NUL) { // Run {cmd} in 'shell'.
|
||||
char *name = (char *)vim_strsave_escaped(eap->arg, (char_u *)"\"\\");
|
||||
snprintf(ex_cmd, sizeof(ex_cmd),
|
||||
":enew%s | call termopen(\"%s\") | startinsert",
|
||||
":enew%s | call termopen(\"%s\")",
|
||||
eap->forceit ? "!" : "", name);
|
||||
xfree(name);
|
||||
} else { // No {cmd}: run the job with tokenized 'shell'.
|
||||
@ -9857,7 +9873,7 @@ static void ex_terminal(exarg_T *eap)
|
||||
shell_free_argv(argv);
|
||||
|
||||
snprintf(ex_cmd, sizeof(ex_cmd),
|
||||
":enew%s | call termopen([%s]) | startinsert",
|
||||
":enew%s | call termopen([%s])",
|
||||
eap->forceit ? "!" : "", shell_argv + 1);
|
||||
}
|
||||
|
||||
|
@ -1620,14 +1620,6 @@ static int command_line_handle_key(CommandLineState *s)
|
||||
}
|
||||
return command_line_not_changed(s);
|
||||
|
||||
case K_FOCUSGAINED: // Neovim has been given focus
|
||||
apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
|
||||
return command_line_not_changed(s);
|
||||
|
||||
case K_FOCUSLOST: // Neovim has lost focus
|
||||
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
|
||||
return command_line_not_changed(s);
|
||||
|
||||
default:
|
||||
// Normal character with no special meaning. Just set mod_mask
|
||||
// to 0x0 so that typing Shift-Space in the GUI doesn't enter
|
||||
@ -1871,9 +1863,13 @@ char *getcmdline_prompt(const char firstc, const char *const prompt,
|
||||
ccline.input_fn = (firstc == '@');
|
||||
ccline.highlight_callback = highlight_callback;
|
||||
|
||||
int msg_silent_saved = msg_silent;
|
||||
msg_silent = 0;
|
||||
|
||||
char *const ret = (char *)getcmdline(firstc, 1L, 0);
|
||||
|
||||
restore_cmdline(&save_ccline);
|
||||
msg_silent = msg_silent_saved;
|
||||
// Restore msg_col, the prompt from input() may have changed it.
|
||||
// But only if called recursively and the commandline is therefore being
|
||||
// restored to an old one; if not, the input() prompt stays on the screen,
|
||||
@ -5722,6 +5718,7 @@ static int ex_window(void)
|
||||
|
||||
i = RedrawingDisabled;
|
||||
RedrawingDisabled = 0;
|
||||
int save_count = save_batch_count();
|
||||
|
||||
/*
|
||||
* Call the main loop until <CR> or CTRL-C is typed.
|
||||
@ -5730,6 +5727,7 @@ static int ex_window(void)
|
||||
normal_enter(true, false);
|
||||
|
||||
RedrawingDisabled = i;
|
||||
restore_batch_count(save_count);
|
||||
|
||||
int save_KeyTyped = KeyTyped;
|
||||
|
||||
|
@ -92,17 +92,15 @@ static int typeahead_char = 0; /* typeahead char that's not flushed */
|
||||
*/
|
||||
static int block_redo = FALSE;
|
||||
|
||||
/*
|
||||
* Make a hash value for a mapping.
|
||||
* "mode" is the lower 4 bits of the State for the mapping.
|
||||
* "c1" is the first character of the "lhs".
|
||||
* Returns a value between 0 and 255, index in maphash.
|
||||
* Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode.
|
||||
*/
|
||||
// Make a hash value for a mapping.
|
||||
// "mode" is the lower 4 bits of the State for the mapping.
|
||||
// "c1" is the first character of the "lhs".
|
||||
// Returns a value between 0 and 255, index in maphash.
|
||||
// Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode.
|
||||
#define MAP_HASH(mode, \
|
||||
c1) (((mode) & \
|
||||
(NORMAL + VISUAL + SELECTMODE + \
|
||||
OP_PENDING)) ? (c1) : ((c1) ^ 0x80))
|
||||
OP_PENDING + TERM_FOCUS)) ? (c1) : ((c1) ^ 0x80))
|
||||
|
||||
// Each mapping is put in one of the MAX_MAPHASH hash lists,
|
||||
// to speed up finding it.
|
||||
@ -870,20 +868,15 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
|
||||
|
||||
addlen = (int)STRLEN(str);
|
||||
|
||||
/*
|
||||
* Easy case: there is room in front of typebuf.tb_buf[typebuf.tb_off]
|
||||
*/
|
||||
if (offset == 0 && addlen <= typebuf.tb_off) {
|
||||
// Easy case: there is room in front of typebuf.tb_buf[typebuf.tb_off]
|
||||
typebuf.tb_off -= addlen;
|
||||
memmove(typebuf.tb_buf + typebuf.tb_off, str, (size_t)addlen);
|
||||
}
|
||||
/*
|
||||
* Need to allocate a new buffer.
|
||||
* In typebuf.tb_buf there must always be room for 3 * MAXMAPLEN + 4
|
||||
* characters. We add some extra room to avoid having to allocate too
|
||||
* often.
|
||||
*/
|
||||
else {
|
||||
} else {
|
||||
// Need to allocate a new buffer.
|
||||
// In typebuf.tb_buf there must always be room for 3 * MAXMAPLEN + 4
|
||||
// characters. We add some extra room to avoid having to allocate too
|
||||
// often.
|
||||
newoff = MAXMAPLEN + 4;
|
||||
newlen = typebuf.tb_len + addlen + newoff + 4 * (MAXMAPLEN + 4);
|
||||
if (newlen < 0) { /* string is getting too long */
|
||||
@ -1665,10 +1658,10 @@ static int vgetorpeek(int advance)
|
||||
}
|
||||
if (c != NUL && !got_int) {
|
||||
if (advance) {
|
||||
/* KeyTyped = FALSE; When the command that stuffed something
|
||||
* was typed, behave like the stuffed command was typed.
|
||||
* needed for CTRL-W CTRl-] to open a fold, for example. */
|
||||
KeyStuffed = TRUE;
|
||||
// KeyTyped = FALSE; When the command that stuffed something
|
||||
// was typed, behave like the stuffed command was typed.
|
||||
// needed for CTRL-W CTRL-] to open a fold, for example.
|
||||
KeyStuffed = true;
|
||||
}
|
||||
if (typebuf.tb_no_abbr_cnt == 0)
|
||||
typebuf.tb_no_abbr_cnt = 1; /* no abbreviations now */
|
||||
|
@ -13,6 +13,7 @@
|
||||
#else
|
||||
# define _(x) ((char *)(x))
|
||||
# define N_(x) x
|
||||
# define ngettext(x, xs, n) ((n) == 1 ? (x) : (xs))
|
||||
# define bindtextdomain(x, y) // empty
|
||||
# define bind_textdomain_codeset(x, y) // empty
|
||||
# define textdomain(x) // empty
|
||||
|
@ -407,6 +407,9 @@ EXTERN int garbage_collect_at_exit INIT(= FALSE);
|
||||
|
||||
/* ID of script being sourced or was sourced to define the current function. */
|
||||
EXTERN scid_T current_SID INIT(= 0);
|
||||
|
||||
EXTERN bool did_source_packages INIT(= false);
|
||||
|
||||
// Scope information for the code that indirectly triggered the current
|
||||
// provider function call
|
||||
EXTERN struct caller_scope {
|
||||
@ -1120,8 +1123,9 @@ EXTERN char_u e_winheight[] INIT(= N_(
|
||||
EXTERN char_u e_winwidth[] INIT(= N_(
|
||||
"E592: 'winwidth' cannot be smaller than 'winminwidth'"));
|
||||
EXTERN char_u e_write[] INIT(= N_("E80: Error while writing"));
|
||||
EXTERN char_u e_zerocount[] INIT(= N_("Zero count"));
|
||||
EXTERN char_u e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context"));
|
||||
EXTERN char_u e_zerocount[] INIT(= N_("E939: Positive count required"));
|
||||
EXTERN char_u e_usingsid[] INIT(= N_(
|
||||
"E81: Using <SID> not in a script context"));
|
||||
EXTERN char_u e_intern2[] INIT(= N_("E685: Internal error: %s"));
|
||||
EXTERN char_u e_maxmempat[] INIT(= N_(
|
||||
"E363: pattern uses more memory than 'maxmempattern'"));
|
||||
|
@ -515,34 +515,41 @@ int cin_isscopedecl(char_u *s)
|
||||
/* Maximum number of lines to search back for a "namespace" line. */
|
||||
#define FIND_NAMESPACE_LIM 20
|
||||
|
||||
/*
|
||||
* Recognize a "namespace" scope declaration.
|
||||
*/
|
||||
static int cin_is_cpp_namespace(char_u *s)
|
||||
// Recognize a "namespace" scope declaration.
|
||||
static bool cin_is_cpp_namespace(char_u *s)
|
||||
{
|
||||
char_u *p;
|
||||
int has_name = FALSE;
|
||||
char_u *p;
|
||||
bool has_name = false;
|
||||
bool has_name_start = false;
|
||||
|
||||
s = cin_skipcomment(s);
|
||||
if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9]))) {
|
||||
p = cin_skipcomment(skipwhite(s + 9));
|
||||
while (*p != NUL) {
|
||||
if (ascii_iswhite(*p)) {
|
||||
has_name = TRUE; /* found end of a name */
|
||||
has_name = true; // found end of a name
|
||||
p = cin_skipcomment(skipwhite(p));
|
||||
} else if (*p == '{') {
|
||||
break;
|
||||
} else if (vim_iswordc(*p)) {
|
||||
if (has_name)
|
||||
return FALSE; /* word character after skipping past name */
|
||||
++p;
|
||||
has_name_start = true;
|
||||
if (has_name) {
|
||||
return false; // word character after skipping past name
|
||||
}
|
||||
p++;
|
||||
} else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2])) {
|
||||
if (!has_name_start || has_name) {
|
||||
return false;
|
||||
}
|
||||
// C++ 17 nested namespace
|
||||
p += 3;
|
||||
} else {
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -727,16 +734,20 @@ static int cin_ispreproc(char_u *s)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
|
||||
* continuation line of a preprocessor statement. Decrease "*lnump" to the
|
||||
* start and return the line in "*pp".
|
||||
*/
|
||||
static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump)
|
||||
/// Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
|
||||
/// continuation line of a preprocessor statement. Decrease "*lnump" to the
|
||||
/// start and return the line in "*pp".
|
||||
/// Put the amount of indent in "*amount".
|
||||
static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount)
|
||||
{
|
||||
char_u *line = *pp;
|
||||
linenr_T lnum = *lnump;
|
||||
int retval = FALSE;
|
||||
int retval = false;
|
||||
int candidate_amount = *amount;
|
||||
|
||||
if (*line != NUL && line[STRLEN(line) - 1] == '\\') {
|
||||
candidate_amount = get_indent_lnum(lnum);
|
||||
}
|
||||
|
||||
for (;; ) {
|
||||
if (cin_ispreproc(line)) {
|
||||
@ -751,8 +762,12 @@ static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump)
|
||||
break;
|
||||
}
|
||||
|
||||
if (lnum != *lnump)
|
||||
if (lnum != *lnump) {
|
||||
*pp = ml_get(*lnump);
|
||||
}
|
||||
if (retval) {
|
||||
*amount = candidate_amount;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1987,10 +2002,12 @@ int get_c_indent(void)
|
||||
amount = -1;
|
||||
for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum) {
|
||||
l = skipwhite(ml_get(lnum));
|
||||
if (cin_nocode(l)) /* skip comment lines */
|
||||
if (cin_nocode(l)) { // skip comment lines
|
||||
continue;
|
||||
if (cin_ispreproc_cont(&l, &lnum))
|
||||
continue; /* ignore #define, #if, etc. */
|
||||
}
|
||||
if (cin_ispreproc_cont(&l, &lnum, &amount)) {
|
||||
continue; // ignore #define, #if, etc.
|
||||
}
|
||||
curwin->w_cursor.lnum = lnum;
|
||||
|
||||
/* Skip a comment or raw string. XXX */
|
||||
@ -2346,15 +2363,14 @@ int get_c_indent(void)
|
||||
* up with it.
|
||||
*/
|
||||
if (curwin->w_cursor.lnum <= ourscope) {
|
||||
/* we reached end of scope:
|
||||
* if looking for an enum or structure initialization
|
||||
* go further back:
|
||||
* if it is an initializer (enum xxx or xxx =), then
|
||||
* don't add ind_continuation, otherwise it is a variable
|
||||
* declaration:
|
||||
* int x,
|
||||
* here; <-- add ind_continuation
|
||||
*/
|
||||
// We reached end of scope:
|
||||
// If looking for a enum or structure initialization
|
||||
// go further back:
|
||||
// If it is an initializer (enum xxx or xxx =), then
|
||||
// don't add ind_continuation, otherwise it is a variable
|
||||
// declaration:
|
||||
// int x,
|
||||
// here; <-- add ind_continuation
|
||||
if (lookfor == LOOKFOR_ENUM_OR_INIT) {
|
||||
if (curwin->w_cursor.lnum == 0
|
||||
|| curwin->w_cursor.lnum
|
||||
@ -2382,11 +2398,12 @@ int get_c_indent(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip preprocessor directives and blank lines.
|
||||
*/
|
||||
if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum))
|
||||
//
|
||||
// Skip preprocessor directives and blank lines.
|
||||
//
|
||||
if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cin_nocode(l))
|
||||
continue;
|
||||
@ -2490,9 +2507,10 @@ int get_c_indent(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip preprocessor directives and blank lines. */
|
||||
if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum))
|
||||
// Skip preprocessor directives and blank lines.
|
||||
if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Finally the actual check for "namespace". */
|
||||
if (cin_is_cpp_namespace(l)) {
|
||||
@ -2655,9 +2673,10 @@ int get_c_indent(void)
|
||||
* unlocked it)
|
||||
*/
|
||||
l = get_cursor_line_ptr();
|
||||
if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum)
|
||||
|| cin_nocode(l))
|
||||
if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)
|
||||
|| cin_nocode(l)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Are we at the start of a cpp base class declaration or
|
||||
@ -3302,11 +3321,12 @@ term_again:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip preprocessor directives and blank lines.
|
||||
*/
|
||||
if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum))
|
||||
//
|
||||
// Skip preprocessor directives and blank lines.
|
||||
//
|
||||
if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cin_nocode(l))
|
||||
continue;
|
||||
@ -3398,9 +3418,10 @@ term_again:
|
||||
|
||||
while (curwin->w_cursor.lnum > 1) {
|
||||
look = ml_get(--curwin->w_cursor.lnum);
|
||||
if (!(cin_nocode(look) || cin_ispreproc_cont(
|
||||
&look, &curwin->w_cursor.lnum)))
|
||||
if (!(cin_nocode(look)
|
||||
|| cin_ispreproc_cont(&look, &curwin->w_cursor.lnum, &amount))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curwin->w_cursor.lnum > 0
|
||||
&& cin_ends_in(look, (char_u *)"}", NULL))
|
||||
|
@ -139,154 +139,153 @@ static char_u modifier_keys_table[] =
|
||||
};
|
||||
|
||||
static const struct key_name_entry {
|
||||
int key; ///< Special key code or ASCII value.
|
||||
const char *name; ///< Name of the key
|
||||
} key_names_table[] = {
|
||||
{' ', "Space"},
|
||||
{TAB, "Tab"},
|
||||
{K_TAB, "Tab"},
|
||||
{NL, "NL"},
|
||||
{NL, "NewLine"}, // Alternative name
|
||||
{NL, "LineFeed"}, // Alternative name
|
||||
{NL, "LF"}, // Alternative name
|
||||
{CAR, "CR"},
|
||||
{CAR, "Return"}, // Alternative name
|
||||
{CAR, "Enter"}, // Alternative name
|
||||
{K_BS, "BS"},
|
||||
{K_BS, "BackSpace"}, // Alternative name
|
||||
{ESC, "Esc"},
|
||||
{CSI, "CSI"},
|
||||
{K_CSI, "xCSI"},
|
||||
{'|', "Bar"},
|
||||
{'\\', "Bslash"},
|
||||
{K_DEL, "Del"},
|
||||
{K_DEL, "Delete"}, // Alternative name
|
||||
{K_KDEL, "kDel"},
|
||||
{K_UP, "Up"},
|
||||
{K_DOWN, "Down"},
|
||||
{K_LEFT, "Left"},
|
||||
{K_RIGHT, "Right"},
|
||||
{K_XUP, "xUp"},
|
||||
{K_XDOWN, "xDown"},
|
||||
{K_XLEFT, "xLeft"},
|
||||
{K_XRIGHT, "xRight"},
|
||||
int key; // Special key code or ascii value
|
||||
const char *name; // Name of key
|
||||
} key_names_table[] =
|
||||
{
|
||||
{ ' ', "Space" },
|
||||
{ TAB, "Tab" },
|
||||
{ K_TAB, "Tab" },
|
||||
{ NL, "NL" },
|
||||
{ NL, "NewLine" }, // Alternative name
|
||||
{ NL, "LineFeed" }, // Alternative name
|
||||
{ NL, "LF" }, // Alternative name
|
||||
{ CAR, "CR" },
|
||||
{ CAR, "Return" }, // Alternative name
|
||||
{ CAR, "Enter" }, // Alternative name
|
||||
{ K_BS, "BS" },
|
||||
{ K_BS, "BackSpace" }, // Alternative name
|
||||
{ ESC, "Esc" },
|
||||
{ CSI, "CSI" },
|
||||
{ K_CSI, "xCSI" },
|
||||
{ '|', "Bar" },
|
||||
{ '\\', "Bslash" },
|
||||
{ K_DEL, "Del" },
|
||||
{ K_DEL, "Delete" }, // Alternative name
|
||||
{ K_KDEL, "kDel" },
|
||||
{ K_UP, "Up" },
|
||||
{ K_DOWN, "Down" },
|
||||
{ K_LEFT, "Left" },
|
||||
{ K_RIGHT, "Right" },
|
||||
{ K_XUP, "xUp" },
|
||||
{ K_XDOWN, "xDown" },
|
||||
{ K_XLEFT, "xLeft" },
|
||||
{ K_XRIGHT, "xRight" },
|
||||
|
||||
{K_F1, "F1"},
|
||||
{K_F2, "F2"},
|
||||
{K_F3, "F3"},
|
||||
{K_F4, "F4"},
|
||||
{K_F5, "F5"},
|
||||
{K_F6, "F6"},
|
||||
{K_F7, "F7"},
|
||||
{K_F8, "F8"},
|
||||
{K_F9, "F9"},
|
||||
{K_F10, "F10"},
|
||||
{ K_F1, "F1" },
|
||||
{ K_F2, "F2" },
|
||||
{ K_F3, "F3" },
|
||||
{ K_F4, "F4" },
|
||||
{ K_F5, "F5" },
|
||||
{ K_F6, "F6" },
|
||||
{ K_F7, "F7" },
|
||||
{ K_F8, "F8" },
|
||||
{ K_F9, "F9" },
|
||||
{ K_F10, "F10" },
|
||||
|
||||
{K_F11, "F11"},
|
||||
{K_F12, "F12"},
|
||||
{K_F13, "F13"},
|
||||
{K_F14, "F14"},
|
||||
{K_F15, "F15"},
|
||||
{K_F16, "F16"},
|
||||
{K_F17, "F17"},
|
||||
{K_F18, "F18"},
|
||||
{K_F19, "F19"},
|
||||
{K_F20, "F20"},
|
||||
{ K_F11, "F11" },
|
||||
{ K_F12, "F12" },
|
||||
{ K_F13, "F13" },
|
||||
{ K_F14, "F14" },
|
||||
{ K_F15, "F15" },
|
||||
{ K_F16, "F16" },
|
||||
{ K_F17, "F17" },
|
||||
{ K_F18, "F18" },
|
||||
{ K_F19, "F19" },
|
||||
{ K_F20, "F20" },
|
||||
|
||||
{K_F21, "F21"},
|
||||
{K_F22, "F22"},
|
||||
{K_F23, "F23"},
|
||||
{K_F24, "F24"},
|
||||
{K_F25, "F25"},
|
||||
{K_F26, "F26"},
|
||||
{K_F27, "F27"},
|
||||
{K_F28, "F28"},
|
||||
{K_F29, "F29"},
|
||||
{K_F30, "F30"},
|
||||
{ K_F21, "F21" },
|
||||
{ K_F22, "F22" },
|
||||
{ K_F23, "F23" },
|
||||
{ K_F24, "F24" },
|
||||
{ K_F25, "F25" },
|
||||
{ K_F26, "F26" },
|
||||
{ K_F27, "F27" },
|
||||
{ K_F28, "F28" },
|
||||
{ K_F29, "F29" },
|
||||
{ K_F30, "F30" },
|
||||
|
||||
{K_F31, "F31"},
|
||||
{K_F32, "F32"},
|
||||
{K_F33, "F33"},
|
||||
{K_F34, "F34"},
|
||||
{K_F35, "F35"},
|
||||
{K_F36, "F36"},
|
||||
{K_F37, "F37"},
|
||||
{ K_F31, "F31" },
|
||||
{ K_F32, "F32" },
|
||||
{ K_F33, "F33" },
|
||||
{ K_F34, "F34" },
|
||||
{ K_F35, "F35" },
|
||||
{ K_F36, "F36" },
|
||||
{ K_F37, "F37" },
|
||||
|
||||
{K_XF1, "xF1"},
|
||||
{K_XF2, "xF2"},
|
||||
{K_XF3, "xF3"},
|
||||
{K_XF4, "xF4"},
|
||||
{ K_XF1, "xF1" },
|
||||
{ K_XF2, "xF2" },
|
||||
{ K_XF3, "xF3" },
|
||||
{ K_XF4, "xF4" },
|
||||
|
||||
{K_HELP, "Help"},
|
||||
{K_UNDO, "Undo"},
|
||||
{K_INS, "Insert"},
|
||||
{K_INS, "Ins"}, // Alternative name
|
||||
{K_KINS, "kInsert"},
|
||||
{K_HOME, "Home"},
|
||||
{K_KHOME, "kHome"},
|
||||
{K_XHOME, "xHome"},
|
||||
{K_ZHOME, "zHome"},
|
||||
{K_END, "End"},
|
||||
{K_KEND, "kEnd"},
|
||||
{K_XEND, "xEnd"},
|
||||
{K_ZEND, "zEnd"},
|
||||
{K_PAGEUP, "PageUp"},
|
||||
{K_PAGEDOWN, "PageDown"},
|
||||
{K_KPAGEUP, "kPageUp"},
|
||||
{K_KPAGEDOWN, "kPageDown"},
|
||||
{ K_HELP, "Help" },
|
||||
{ K_UNDO, "Undo" },
|
||||
{ K_INS, "Insert" },
|
||||
{ K_INS, "Ins" }, // Alternative name
|
||||
{ K_KINS, "kInsert" },
|
||||
{ K_HOME, "Home" },
|
||||
{ K_KHOME, "kHome" },
|
||||
{ K_XHOME, "xHome" },
|
||||
{ K_ZHOME, "zHome" },
|
||||
{ K_END, "End" },
|
||||
{ K_KEND, "kEnd" },
|
||||
{ K_XEND, "xEnd" },
|
||||
{ K_ZEND, "zEnd" },
|
||||
{ K_PAGEUP, "PageUp" },
|
||||
{ K_PAGEDOWN, "PageDown" },
|
||||
{ K_KPAGEUP, "kPageUp" },
|
||||
{ K_KPAGEDOWN, "kPageDown" },
|
||||
|
||||
{K_KPLUS, "kPlus"},
|
||||
{K_KMINUS, "kMinus"},
|
||||
{K_KDIVIDE, "kDivide"},
|
||||
{K_KMULTIPLY, "kMultiply"},
|
||||
{K_KENTER, "kEnter"},
|
||||
{K_KPOINT, "kPoint"},
|
||||
{ K_KPLUS, "kPlus" },
|
||||
{ K_KMINUS, "kMinus" },
|
||||
{ K_KDIVIDE, "kDivide" },
|
||||
{ K_KMULTIPLY, "kMultiply" },
|
||||
{ K_KENTER, "kEnter" },
|
||||
{ K_KPOINT, "kPoint" },
|
||||
|
||||
{K_K0, "k0"},
|
||||
{K_K1, "k1"},
|
||||
{K_K2, "k2"},
|
||||
{K_K3, "k3"},
|
||||
{K_K4, "k4"},
|
||||
{K_K5, "k5"},
|
||||
{K_K6, "k6"},
|
||||
{K_K7, "k7"},
|
||||
{K_K8, "k8"},
|
||||
{K_K9, "k9"},
|
||||
{ K_K0, "k0" },
|
||||
{ K_K1, "k1" },
|
||||
{ K_K2, "k2" },
|
||||
{ K_K3, "k3" },
|
||||
{ K_K4, "k4" },
|
||||
{ K_K5, "k5" },
|
||||
{ K_K6, "k6" },
|
||||
{ K_K7, "k7" },
|
||||
{ K_K8, "k8" },
|
||||
{ K_K9, "k9" },
|
||||
|
||||
{'<', "lt"},
|
||||
{ '<', "lt" },
|
||||
|
||||
{K_MOUSE, "Mouse"},
|
||||
{K_LEFTMOUSE, "LeftMouse"},
|
||||
{K_LEFTMOUSE_NM, "LeftMouseNM"},
|
||||
{K_LEFTDRAG, "LeftDrag"},
|
||||
{K_LEFTRELEASE, "LeftRelease"},
|
||||
{K_LEFTRELEASE_NM, "LeftReleaseNM"},
|
||||
{K_MIDDLEMOUSE, "MiddleMouse"},
|
||||
{K_MIDDLEDRAG, "MiddleDrag"},
|
||||
{K_MIDDLERELEASE, "MiddleRelease"},
|
||||
{K_RIGHTMOUSE, "RightMouse"},
|
||||
{K_RIGHTDRAG, "RightDrag"},
|
||||
{K_RIGHTRELEASE, "RightRelease"},
|
||||
{K_MOUSEDOWN, "ScrollWheelUp"},
|
||||
{K_MOUSEUP, "ScrollWheelDown"},
|
||||
{K_MOUSELEFT, "ScrollWheelRight"},
|
||||
{K_MOUSERIGHT, "ScrollWheelLeft"},
|
||||
{K_MOUSEDOWN, "MouseDown"}, // OBSOLETE: Use ScrollWheelXXX instead
|
||||
{K_MOUSEUP, "MouseUp"}, // Same
|
||||
{K_X1MOUSE, "X1Mouse"},
|
||||
{K_X1DRAG, "X1Drag"},
|
||||
{K_X1RELEASE, "X1Release"},
|
||||
{K_X2MOUSE, "X2Mouse"},
|
||||
{K_X2DRAG, "X2Drag"},
|
||||
{K_X2RELEASE, "X2Release"},
|
||||
{K_DROP, "Drop"},
|
||||
{K_ZERO, "Nul"},
|
||||
{K_SNR, "SNR"},
|
||||
{K_PLUG, "Plug"},
|
||||
{K_PASTE, "Paste"},
|
||||
{K_FOCUSGAINED, "FocusGained"},
|
||||
{K_FOCUSLOST, "FocusLost"},
|
||||
{0, NULL}
|
||||
{ K_MOUSE, "Mouse" },
|
||||
{ K_LEFTMOUSE, "LeftMouse" },
|
||||
{ K_LEFTMOUSE_NM, "LeftMouseNM" },
|
||||
{ K_LEFTDRAG, "LeftDrag" },
|
||||
{ K_LEFTRELEASE, "LeftRelease" },
|
||||
{ K_LEFTRELEASE_NM, "LeftReleaseNM" },
|
||||
{ K_MIDDLEMOUSE, "MiddleMouse" },
|
||||
{ K_MIDDLEDRAG, "MiddleDrag" },
|
||||
{ K_MIDDLERELEASE, "MiddleRelease" },
|
||||
{ K_RIGHTMOUSE, "RightMouse" },
|
||||
{ K_RIGHTDRAG, "RightDrag" },
|
||||
{ K_RIGHTRELEASE, "RightRelease" },
|
||||
{ K_MOUSEDOWN, "ScrollWheelUp" },
|
||||
{ K_MOUSEUP, "ScrollWheelDown" },
|
||||
{ K_MOUSELEFT, "ScrollWheelRight" },
|
||||
{ K_MOUSERIGHT, "ScrollWheelLeft" },
|
||||
{ K_MOUSEDOWN, "MouseDown" }, // OBSOLETE: Use
|
||||
{ K_MOUSEUP, "MouseUp" }, // ScrollWheelXXX instead
|
||||
{ K_X1MOUSE, "X1Mouse" },
|
||||
{ K_X1DRAG, "X1Drag" },
|
||||
{ K_X1RELEASE, "X1Release" },
|
||||
{ K_X2MOUSE, "X2Mouse" },
|
||||
{ K_X2DRAG, "X2Drag" },
|
||||
{ K_X2RELEASE, "X2Release" },
|
||||
{ K_DROP, "Drop" },
|
||||
{ K_ZERO, "Nul" },
|
||||
{ K_SNR, "SNR" },
|
||||
{ K_PLUG, "Plug" },
|
||||
{ K_PASTE, "Paste" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static struct mousetable {
|
||||
@ -720,8 +719,8 @@ int get_special_key_code(const char_u *name)
|
||||
for (int i = 0; key_names_table[i].name != NULL; i++) {
|
||||
const char *const table_name = key_names_table[i].name;
|
||||
int j;
|
||||
for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++) {
|
||||
if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j])) {
|
||||
for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++)
|
||||
if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -428,8 +428,6 @@ enum key_extra {
|
||||
#define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)
|
||||
|
||||
#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
|
||||
#define K_FOCUSGAINED TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
|
||||
#define K_FOCUSLOST TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
|
||||
|
||||
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
|
||||
#define K_PASTE TERMCAP2KEY(KS_EXTRA, KE_PASTE)
|
||||
|
@ -95,8 +95,12 @@ void log_unlock(void)
|
||||
uv_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
bool do_log(int log_level, const char *func_name, int line_num, bool eol,
|
||||
const char* fmt, ...) FUNC_ATTR_UNUSED
|
||||
/// @param context description of a shared context or subsystem
|
||||
/// @param func_name function name, or NULL
|
||||
/// @param line_num source line number, or -1
|
||||
bool do_log(int log_level, const char *context, const char *func_name,
|
||||
int line_num, bool eol, const char *fmt, ...)
|
||||
FUNC_ATTR_UNUSED
|
||||
{
|
||||
if (log_level < MIN_LOG_LEVEL) {
|
||||
return false;
|
||||
@ -112,8 +116,8 @@ bool do_log(int log_level, const char *func_name, int line_num, bool eol,
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ret = v_do_log_to_file(log_file, log_level, func_name, line_num, eol,
|
||||
fmt, args);
|
||||
ret = v_do_log_to_file(log_file, log_level, context, func_name, line_num,
|
||||
eol, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (log_file != stderr && log_file != stdout) {
|
||||
@ -151,7 +155,7 @@ FILE *open_log_file(void)
|
||||
static bool opening_log_file = false;
|
||||
// check if it's a recursive call
|
||||
if (opening_log_file) {
|
||||
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
|
||||
do_log_to_file(stderr, ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true,
|
||||
"Cannot LOG() recursively.");
|
||||
return stderr;
|
||||
}
|
||||
@ -171,7 +175,7 @@ FILE *open_log_file(void)
|
||||
// - LOG() is called before early_init()
|
||||
// - Directory does not exist
|
||||
// - File is not writable
|
||||
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
|
||||
do_log_to_file(stderr, ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true,
|
||||
"Logging to stderr, failed to open $" LOG_FILE_ENV ": %s",
|
||||
log_file_path);
|
||||
return stderr;
|
||||
@ -201,7 +205,7 @@ void log_callstack_to_file(FILE *log_file, const char *const func_name,
|
||||
// Now we have a command string like:
|
||||
// addr2line -e /path/to/exe -f -p 0x123 0x456 ...
|
||||
|
||||
do_log_to_file(log_file, DEBUG_LOG_LEVEL, func_name, line_num, true,
|
||||
do_log_to_file(log_file, DEBUG_LOG_LEVEL, NULL, func_name, line_num, true,
|
||||
"trace:");
|
||||
FILE *fp = popen(cmdbuf, "r");
|
||||
char linebuf[IOSIZE];
|
||||
@ -230,27 +234,28 @@ end:
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool do_log_to_file(FILE *log_file, int log_level,
|
||||
static bool do_log_to_file(FILE *log_file, int log_level, const char *context,
|
||||
const char *func_name, int line_num, bool eol,
|
||||
const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
bool ret = v_do_log_to_file(log_file, log_level, func_name, line_num, eol,
|
||||
fmt, args);
|
||||
bool ret = v_do_log_to_file(log_file, log_level, context, func_name,
|
||||
line_num, eol, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool v_do_log_to_file(FILE *log_file, int log_level,
|
||||
const char *func_name, int line_num, bool eol,
|
||||
const char* fmt, va_list args)
|
||||
const char *context, const char *func_name,
|
||||
int line_num, bool eol, const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
static const char *log_levels[] = {
|
||||
[DEBUG_LOG_LEVEL] = "DEBUG",
|
||||
[INFO_LOG_LEVEL] = "INFO ",
|
||||
[WARNING_LOG_LEVEL] = "WARN ",
|
||||
[WARN_LOG_LEVEL] = "WARN ",
|
||||
[ERROR_LOG_LEVEL] = "ERROR",
|
||||
};
|
||||
assert(log_level >= DEBUG_LOG_LEVEL && log_level <= ERROR_LOG_LEVEL);
|
||||
@ -268,8 +273,15 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
|
||||
|
||||
// print the log message prefixed by the current timestamp and pid
|
||||
int64_t pid = os_get_pid();
|
||||
if (fprintf(log_file, "%s %s %" PRId64 "/%s:%d: ", date_time,
|
||||
log_levels[log_level], pid, func_name, line_num) < 0) {
|
||||
int rv = (line_num == -1 || func_name == NULL)
|
||||
? fprintf(log_file, "%s %s %" PRId64 " %s", date_time,
|
||||
log_levels[log_level], pid,
|
||||
(context == NULL ? "?:" : context))
|
||||
: fprintf(log_file, "%s %s %" PRId64 " %s%s:%d: ", date_time,
|
||||
log_levels[log_level], pid,
|
||||
(context == NULL ? "" : context),
|
||||
func_name, line_num);
|
||||
if (rv < 0) {
|
||||
return false;
|
||||
}
|
||||
if (vfprintf(log_file, fmt, args) < 0) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#define DEBUG_LOG_LEVEL 0
|
||||
#define INFO_LOG_LEVEL 1
|
||||
#define WARNING_LOG_LEVEL 2
|
||||
#define WARN_LOG_LEVEL 2
|
||||
#define ERROR_LOG_LEVEL 3
|
||||
|
||||
#define DLOG(...)
|
||||
@ -22,42 +22,42 @@
|
||||
# define MIN_LOG_LEVEL INFO_LOG_LEVEL
|
||||
#endif
|
||||
|
||||
#define LOG(level, ...) do_log((level), __func__, __LINE__, true, \
|
||||
#define LOG(level, ...) do_log((level), NULL, __func__, __LINE__, true, \
|
||||
__VA_ARGS__)
|
||||
|
||||
#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL
|
||||
# undef DLOG
|
||||
# undef DLOGN
|
||||
# define DLOG(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, true, \
|
||||
# define DLOG(...) do_log(DEBUG_LOG_LEVEL, NULL, __func__, __LINE__, true, \
|
||||
__VA_ARGS__)
|
||||
# define DLOGN(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, false, \
|
||||
# define DLOGN(...) do_log(DEBUG_LOG_LEVEL, NULL, __func__, __LINE__, false, \
|
||||
__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if MIN_LOG_LEVEL <= INFO_LOG_LEVEL
|
||||
# undef ILOG
|
||||
# undef ILOGN
|
||||
# define ILOG(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, true, \
|
||||
# define ILOG(...) do_log(INFO_LOG_LEVEL, NULL, __func__, __LINE__, true, \
|
||||
__VA_ARGS__)
|
||||
# define ILOGN(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, false, \
|
||||
# define ILOGN(...) do_log(INFO_LOG_LEVEL, NULL, __func__, __LINE__, false, \
|
||||
__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if MIN_LOG_LEVEL <= WARNING_LOG_LEVEL
|
||||
#if MIN_LOG_LEVEL <= WARN_LOG_LEVEL
|
||||
# undef WLOG
|
||||
# undef WLOGN
|
||||
# define WLOG(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, true, \
|
||||
# define WLOG(...) do_log(WARN_LOG_LEVEL, NULL, __func__, __LINE__, true, \
|
||||
__VA_ARGS__)
|
||||
# define WLOGN(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, false, \
|
||||
# define WLOGN(...) do_log(WARN_LOG_LEVEL, NULL, __func__, __LINE__, false, \
|
||||
__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if MIN_LOG_LEVEL <= ERROR_LOG_LEVEL
|
||||
# undef ELOG
|
||||
# undef ELOGN
|
||||
# define ELOG(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, true, \
|
||||
# define ELOG(...) do_log(ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true, \
|
||||
__VA_ARGS__)
|
||||
# define ELOGN(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, false, \
|
||||
# define ELOGN(...) do_log(ERROR_LOG_LEVEL, NULL, __func__, __LINE__, false, \
|
||||
__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
126
src/nvim/main.c
126
src/nvim/main.c
@ -7,6 +7,11 @@
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef WIN32
|
||||
# include <wchar.h>
|
||||
# include <winnls.h>
|
||||
#endif
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include "nvim/ascii.h"
|
||||
@ -215,10 +220,22 @@ void early_init(void)
|
||||
|
||||
#ifdef MAKE_LIB
|
||||
int nvim_main(int argc, char **argv)
|
||||
#elif defined(WIN32)
|
||||
int wmain(int argc, wchar_t **argv_w) // multibyte args on Windows. #7060
|
||||
#else
|
||||
int main(int argc, char **argv)
|
||||
#endif
|
||||
{
|
||||
#if defined(WIN32) && !defined(MAKE_LIB)
|
||||
char *argv[argc];
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char *buf = NULL;
|
||||
utf16_to_utf8(argv_w[i], &buf);
|
||||
assert(buf);
|
||||
argv[i] = buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
argv0 = argv[0];
|
||||
|
||||
char_u *fname = NULL; // file name from command line
|
||||
@ -632,6 +649,11 @@ void getout(int exitval)
|
||||
/* Position the cursor again, the autocommands may have moved it */
|
||||
ui_cursor_goto((int)Rows - 1, 0);
|
||||
|
||||
// Apply 'titleold'.
|
||||
if (p_title && *p_titleold != NUL) {
|
||||
ui_call_set_title(cstr_as_string((char *)p_titleold));
|
||||
}
|
||||
|
||||
#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
|
||||
iconv_end();
|
||||
#endif
|
||||
@ -1291,10 +1313,29 @@ static void set_window_layout(mparm_T *paramp)
|
||||
static void load_plugins(void)
|
||||
{
|
||||
if (p_lpl) {
|
||||
source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_NOAFTER); // NOLINT
|
||||
TIME_MSG("loading plugins");
|
||||
char_u *rtp_copy = NULL;
|
||||
|
||||
ex_packloadall(NULL);
|
||||
// First add all package directories to 'runtimepath', so that their
|
||||
// autoload directories can be found. Only if not done already with a
|
||||
// :packloadall command.
|
||||
// Make a copy of 'runtimepath', so that source_runtime does not use the
|
||||
// pack directories.
|
||||
if (!did_source_packages) {
|
||||
rtp_copy = vim_strsave(p_rtp);
|
||||
add_pack_start_dirs();
|
||||
}
|
||||
|
||||
source_in_path(rtp_copy == NULL ? p_rtp : rtp_copy,
|
||||
(char_u *)"plugin/**/*.vim", // NOLINT
|
||||
DIP_ALL | DIP_NOAFTER);
|
||||
TIME_MSG("loading plugins");
|
||||
xfree(rtp_copy);
|
||||
|
||||
// Only source "start" packages if not done already with a :packloadall
|
||||
// command.
|
||||
if (!did_source_packages) {
|
||||
load_start_packages();
|
||||
}
|
||||
TIME_MSG("loading packages");
|
||||
|
||||
source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_AFTER);
|
||||
@ -1878,54 +1919,47 @@ static void usage(void)
|
||||
signal_stop(); // kill us with CTRL-C here, if you like
|
||||
|
||||
mch_msg(_("Usage:\n"));
|
||||
mch_msg(_(" nvim [arguments] [file ...] Edit specified file(s)\n"));
|
||||
mch_msg(_(" nvim [arguments] - Read text from stdin\n"));
|
||||
mch_msg(_(" nvim [arguments] -t <tag> Edit file where tag is defined\n"));
|
||||
mch_msg(_(" nvim [arguments] -q [errorfile] Edit file with first error\n"));
|
||||
mch_msg(_("\nArguments:\n"));
|
||||
mch_msg(_(" nvim [options] [file ...] Edit file(s)\n"));
|
||||
mch_msg(_(" nvim [options] - Read text from stdin\n"));
|
||||
mch_msg(_(" nvim [options] -t <tag> Edit file where tag is defined\n"));
|
||||
mch_msg(_(" nvim [options] -q [errorfile] Edit file with first error\n"));
|
||||
mch_msg(_("\nOptions:\n"));
|
||||
mch_msg(_(" -- Only file names after this\n"));
|
||||
mch_msg(_(" + Start at end of file\n"));
|
||||
mch_msg(_(" --cmd <cmd> Execute <cmd> before any config\n"));
|
||||
mch_msg(_(" +<cmd>, -c <cmd> Execute <cmd> after config and first file\n"));
|
||||
mch_msg("\n");
|
||||
mch_msg(_(" -b Binary mode\n"));
|
||||
mch_msg(_(" -d Diff mode\n"));
|
||||
mch_msg(_(" -e, -E Ex mode, Improved Ex mode\n"));
|
||||
mch_msg(_(" -es Silent (batch) mode\n"));
|
||||
mch_msg(_(" -h, --help Print this help message\n"));
|
||||
mch_msg(_(" -i <shada> Use this shada file\n"));
|
||||
mch_msg(_(" -m Modifications (writing files) not allowed\n"));
|
||||
mch_msg(_(" -M Modifications in text not allowed\n"));
|
||||
mch_msg(_(" -n No swap file, use memory only\n"));
|
||||
mch_msg(_(" -o[N] Open N windows (default: one per file)\n"));
|
||||
mch_msg(_(" -O[N] Open N vertical windows (default: one per file)\n"));
|
||||
mch_msg(_(" -p[N] Open N tab pages (default: one per file)\n"));
|
||||
mch_msg(_(" -r, -L List swap files\n"));
|
||||
mch_msg(_(" -r <file> Recover edit state for this file\n"));
|
||||
mch_msg(_(" -R Read-only mode\n"));
|
||||
mch_msg(_(" -S <session> Source <session> after loading the first file\n"));
|
||||
mch_msg(_(" -s <scriptin> Read Normal mode commands from <scriptin>\n"));
|
||||
mch_msg(_(" -u <config> Use this config file\n"));
|
||||
mch_msg(_(" -v, --version Print version information\n"));
|
||||
mch_msg(_(" -V[N][file] Verbose [level][file]\n"));
|
||||
mch_msg(_(" -Z Restricted mode\n"));
|
||||
mch_msg("\n");
|
||||
mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n"));
|
||||
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
|
||||
mch_msg(_(" --headless Don't start a user interface\n"));
|
||||
#if !defined(UNIX)
|
||||
mch_msg(_(" --literal Don't expand wildcards\n"));
|
||||
#endif
|
||||
mch_msg(_(" -e Ex mode\n"));
|
||||
mch_msg(_(" -E Improved Ex mode\n"));
|
||||
mch_msg(_(" -s Silent (batch) mode (only for ex mode)\n"));
|
||||
mch_msg(_(" -d Diff mode\n"));
|
||||
mch_msg(_(" -R Read-only mode\n"));
|
||||
mch_msg(_(" -Z Restricted mode\n"));
|
||||
mch_msg(_(" -m Modifications (writing files) not allowed\n"));
|
||||
mch_msg(_(" -M Modifications in text not allowed\n"));
|
||||
mch_msg(_(" -b Binary mode\n"));
|
||||
mch_msg(_(" -l Lisp mode\n"));
|
||||
mch_msg(_(" -A Arabic mode\n"));
|
||||
mch_msg(_(" -F Farsi mode\n"));
|
||||
mch_msg(_(" -H Hebrew mode\n"));
|
||||
mch_msg(_(" -V[N][file] Be verbose [level N][log messages to file]\n"));
|
||||
mch_msg(_(" -D Debugging mode\n"));
|
||||
mch_msg(_(" -n No swap file, use memory only\n"));
|
||||
mch_msg(_(" -r, -L List swap files and exit\n"));
|
||||
mch_msg(_(" -r <file> Recover crashed session\n"));
|
||||
mch_msg(_(" -u <vimrc> Use <vimrc> instead of the default\n"));
|
||||
mch_msg(_(" -i <shada> Use <shada> instead of the default\n"));
|
||||
mch_msg(_(" --noplugin Don't load plugin scripts\n"));
|
||||
mch_msg(_(" -o[N] Open N windows (default: one for each file)\n"));
|
||||
mch_msg(_(" -O[N] Like -o but split vertically\n"));
|
||||
mch_msg(_(" -p[N] Open N tab pages (default: one for each file)\n"));
|
||||
mch_msg(_(" + Start at end of file\n"));
|
||||
mch_msg(_(" +<linenum> Start at line <linenum>\n"));
|
||||
mch_msg(_(" +/<pattern> Start at first occurrence of <pattern>\n"));
|
||||
mch_msg(_(" --cmd <command> Execute <command> before loading any vimrc\n"));
|
||||
mch_msg(_(" -c <command> Execute <command> after loading the first file\n"));
|
||||
mch_msg(_(" -S <session> Source <session> after loading the first file\n"));
|
||||
mch_msg(_(" -s <scriptin> Read Normal mode commands from <scriptin>\n"));
|
||||
mch_msg(_(" -w <scriptout> Append all typed characters to <scriptout>\n"));
|
||||
mch_msg(_(" -W <scriptout> Write all typed characters to <scriptout>\n"));
|
||||
mch_msg(_(" --noplugin Don't load plugins\n"));
|
||||
mch_msg(_(" --startuptime <file> Write startup timing messages to <file>\n"));
|
||||
mch_msg(_(" --api-info Dump API metadata serialized to msgpack and exit\n"));
|
||||
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
|
||||
mch_msg(_(" --headless Don't start a user interface\n"));
|
||||
mch_msg(_(" -v, --version Print version information and exit\n"));
|
||||
mch_msg(_(" -h, --help Print this help message and exit\n"));
|
||||
mch_msg(_("\nSee \":help startup-options\" for all options.\n"));
|
||||
}
|
||||
|
||||
|
||||
|
@ -2164,16 +2164,21 @@ void do_check_cursorbind(void)
|
||||
int restart_edit_save = restart_edit;
|
||||
restart_edit = true;
|
||||
check_cursor();
|
||||
if (curwin->w_p_cul || curwin->w_p_cuc) {
|
||||
validate_cursor();
|
||||
}
|
||||
restart_edit = restart_edit_save;
|
||||
}
|
||||
/* Correct cursor for multi-byte character. */
|
||||
if (has_mbyte)
|
||||
// Correct cursor for multi-byte character.
|
||||
if (has_mbyte) {
|
||||
mb_adjust_cursor();
|
||||
}
|
||||
redraw_later(VALID);
|
||||
|
||||
/* Only scroll when 'scrollbind' hasn't done this. */
|
||||
if (!curwin->w_p_scb)
|
||||
// Only scroll when 'scrollbind' hasn't done this.
|
||||
if (!curwin->w_p_scb) {
|
||||
update_topline();
|
||||
}
|
||||
curwin->w_redr_status = true;
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ typedef struct {
|
||||
ChannelType type;
|
||||
msgpack_unpacker *unpacker;
|
||||
union {
|
||||
Stream stream;
|
||||
Stream stream; // bidirectional (socket)
|
||||
Process *proc;
|
||||
struct {
|
||||
Stream in;
|
||||
@ -133,6 +133,9 @@ uint64_t channel_from_process(Process *proc, uint64_t id, char *source)
|
||||
rstream_init(proc->out, 0);
|
||||
rstream_start(proc->out, receive_msgpack, channel);
|
||||
|
||||
DLOG("ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id, proc->in,
|
||||
proc->out);
|
||||
|
||||
return channel->id;
|
||||
}
|
||||
|
||||
@ -150,6 +153,9 @@ void channel_from_connection(SocketWatcher *watcher)
|
||||
wstream_init(&channel->data.stream, 0);
|
||||
rstream_init(&channel->data.stream, CHANNEL_BUFFER_SIZE);
|
||||
rstream_start(&channel->data.stream, receive_msgpack, channel);
|
||||
|
||||
DLOG("ch %" PRIu64 " in/out-stream=%p", channel->id,
|
||||
&channel->data.stream);
|
||||
}
|
||||
|
||||
/// @param source description of source function, rplugin name, TCP addr, etc
|
||||
@ -182,12 +188,11 @@ uint64_t channel_connect(bool tcp, const char *address, int timeout,
|
||||
return channel->id;
|
||||
}
|
||||
|
||||
/// Sends event/arguments to channel
|
||||
/// Publishes an event to a channel.
|
||||
///
|
||||
/// @param id The channel id. If 0, the event will be sent to all
|
||||
/// channels that have subscribed to the event type
|
||||
/// @param name The event name, an arbitrary string
|
||||
/// @param args Array with event arguments
|
||||
/// @param id Channel id. 0 means "broadcast to all subscribed channels"
|
||||
/// @param name Event name (application-defined)
|
||||
/// @param args Array of event arguments
|
||||
/// @return True if the event was sent successfully, false otherwise.
|
||||
bool channel_send_event(uint64_t id, const char *name, Array args)
|
||||
{
|
||||
@ -209,7 +214,6 @@ bool channel_send_event(uint64_t id, const char *name, Array args)
|
||||
send_event(channel, name, args);
|
||||
}
|
||||
} else {
|
||||
// TODO(tarruda): Implement event broadcasting in vimscript
|
||||
broadcast_event(name, args);
|
||||
}
|
||||
|
||||
@ -344,6 +348,9 @@ void channel_from_stdio(void)
|
||||
rstream_start(&channel->data.std.in, receive_msgpack, channel);
|
||||
// write stream
|
||||
wstream_init_fd(&main_loop, &channel->data.std.out, 1, 0);
|
||||
|
||||
DLOG("ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id,
|
||||
&channel->data.std.in, &channel->data.std.out);
|
||||
}
|
||||
|
||||
/// Creates a loopback channel. This is used to avoid deadlock
|
||||
@ -363,6 +370,7 @@ void channel_process_exit(uint64_t id, int status)
|
||||
decref(channel);
|
||||
}
|
||||
|
||||
// rstream.c:read_event() invokes this as stream->read_cb().
|
||||
static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c,
|
||||
void *data, bool eof)
|
||||
{
|
||||
@ -374,12 +382,24 @@ static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c,
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client",
|
||||
channel->id);
|
||||
call_set_error(channel, buf, WARNING_LOG_LEVEL);
|
||||
call_set_error(channel, buf, WARN_LOG_LEVEL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((chan_wstream(channel) != NULL && chan_wstream(channel)->closed)
|
||||
|| (chan_rstream(channel) != NULL && chan_rstream(channel)->closed)) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"ch %" PRIu64 ": stream closed unexpectedly. "
|
||||
"closing channel",
|
||||
channel->id);
|
||||
call_set_error(channel, buf, WARN_LOG_LEVEL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
size_t count = rbuffer_size(rbuf);
|
||||
DLOG("parsing %u bytes of msgpack data from Stream(%p)", count, stream);
|
||||
DLOG("ch %" PRIu64 ": parsing %u bytes from msgpack Stream: %p",
|
||||
channel->id, count, stream);
|
||||
|
||||
// Feed the unpacker with data
|
||||
msgpack_unpacker_reserve_buffer(channel->unpacker, count);
|
||||
@ -435,8 +455,8 @@ static void parse_msgpack(Channel *channel)
|
||||
// causes for this error(search for 'goto _failed')
|
||||
//
|
||||
// A not so uncommon cause for this might be deserializing objects with
|
||||
// a high nesting level: msgpack will break when it's internal parse stack
|
||||
// size exceeds MSGPACK_EMBED_STACK_SIZE(defined as 32 by default)
|
||||
// a high nesting level: msgpack will break when its internal parse stack
|
||||
// size exceeds MSGPACK_EMBED_STACK_SIZE (defined as 32 by default)
|
||||
send_error(channel, 0, "Invalid msgpack payload. "
|
||||
"This error can also happen when deserializing "
|
||||
"an object with high level of nesting");
|
||||
@ -534,6 +554,39 @@ static void on_request_event(void **argv)
|
||||
api_clear_error(&error);
|
||||
}
|
||||
|
||||
/// Returns the Stream that a Channel writes to.
|
||||
static Stream *chan_wstream(Channel *chan)
|
||||
{
|
||||
switch (chan->type) {
|
||||
case kChannelTypeSocket:
|
||||
return &chan->data.stream;
|
||||
case kChannelTypeProc:
|
||||
return chan->data.proc->in;
|
||||
case kChannelTypeStdio:
|
||||
return &chan->data.std.out;
|
||||
case kChannelTypeInternal:
|
||||
return NULL;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
/// Returns the Stream that a Channel reads from.
|
||||
static Stream *chan_rstream(Channel *chan)
|
||||
{
|
||||
switch (chan->type) {
|
||||
case kChannelTypeSocket:
|
||||
return &chan->data.stream;
|
||||
case kChannelTypeProc:
|
||||
return chan->data.proc->out;
|
||||
case kChannelTypeStdio:
|
||||
return &chan->data.std.in;
|
||||
case kChannelTypeInternal:
|
||||
return NULL;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static bool channel_write(Channel *channel, WBuffer *buffer)
|
||||
{
|
||||
bool success = false;
|
||||
@ -545,13 +598,9 @@ static bool channel_write(Channel *channel, WBuffer *buffer)
|
||||
|
||||
switch (channel->type) {
|
||||
case kChannelTypeSocket:
|
||||
success = wstream_write(&channel->data.stream, buffer);
|
||||
break;
|
||||
case kChannelTypeProc:
|
||||
success = wstream_write(channel->data.proc->in, buffer);
|
||||
break;
|
||||
case kChannelTypeStdio:
|
||||
success = wstream_write(&channel->data.std.out, buffer);
|
||||
success = wstream_write(chan_wstream(channel), buffer);
|
||||
break;
|
||||
case kChannelTypeInternal:
|
||||
incref(channel);
|
||||
@ -565,8 +614,8 @@ static bool channel_write(Channel *channel, WBuffer *buffer)
|
||||
char buf[256];
|
||||
snprintf(buf,
|
||||
sizeof(buf),
|
||||
"Before returning from a RPC call, ch %" PRIu64 " was "
|
||||
"closed due to a failed write",
|
||||
"ch %" PRIu64 ": stream write failed. "
|
||||
"RPC canceled; closing channel",
|
||||
channel->id);
|
||||
call_set_error(channel, buf, ERROR_LOG_LEVEL);
|
||||
}
|
||||
@ -817,6 +866,7 @@ static void call_set_error(Channel *channel, char *msg, int loglevel)
|
||||
ChannelCallFrame *frame = kv_A(channel->call_stack, i);
|
||||
frame->returned = true;
|
||||
frame->errored = true;
|
||||
api_free_object(frame->result);
|
||||
frame->result = STRING_OBJ(cstr_to_string(msg));
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,12 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
|
||||
{
|
||||
bool ret = true;
|
||||
kvec_t(MPToAPIObjectStackItem) stack = KV_INITIAL_VALUE;
|
||||
kv_push(stack, ((MPToAPIObjectStackItem) { obj, arg, false, 0 }));
|
||||
kv_push(stack, ((MPToAPIObjectStackItem) {
|
||||
.mobj = obj,
|
||||
.aobj = arg,
|
||||
.container = false,
|
||||
.idx = 0,
|
||||
}));
|
||||
while (ret && kv_size(stack)) {
|
||||
MPToAPIObjectStackItem cur = kv_last(stack);
|
||||
if (!cur.container) {
|
||||
@ -361,7 +366,7 @@ typedef struct {
|
||||
size_t idx;
|
||||
} APIToMPObjectStackItem;
|
||||
|
||||
/// Convert type used by Neovim API to msgpack
|
||||
/// Convert type used by Nvim API to msgpack type.
|
||||
///
|
||||
/// @param[in] result Object to convert.
|
||||
/// @param[out] res Structure that defines where conversion results are saved.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nvim/log.h"
|
||||
#include "nvim/vim.h"
|
||||
#include "nvim/ascii.h"
|
||||
#include "nvim/normal.h"
|
||||
@ -344,8 +345,6 @@ static const struct nv_cmd {
|
||||
{ K_F8, farsi_f8, 0, 0 },
|
||||
{ K_F9, farsi_f9, 0, 0 },
|
||||
{ K_EVENT, nv_event, NV_KEEPREG, 0 },
|
||||
{ K_FOCUSGAINED, nv_focusgained, NV_KEEPREG, 0 },
|
||||
{ K_FOCUSLOST, nv_focuslost, NV_KEEPREG, 0 },
|
||||
};
|
||||
|
||||
/* Number of commands in nv_cmds[]. */
|
||||
@ -1943,8 +1942,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
|
||||
* the lines. */
|
||||
auto_format(false, true);
|
||||
|
||||
if (restart_edit == 0)
|
||||
if (restart_edit == 0) {
|
||||
restart_edit = restart_edit_save;
|
||||
} else {
|
||||
cap->retval |= CA_COMMAND_BUSY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -7957,18 +7959,7 @@ static void nv_event(cmdarg_T *cap)
|
||||
may_garbage_collect = false;
|
||||
multiqueue_process_events(main_loop.events);
|
||||
cap->retval |= CA_COMMAND_BUSY; // don't call edit() now
|
||||
}
|
||||
|
||||
/// Trigger FocusGained event.
|
||||
static void nv_focusgained(cmdarg_T *cap)
|
||||
{
|
||||
apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
|
||||
}
|
||||
|
||||
/// Trigger FocusLost event.
|
||||
static void nv_focuslost(cmdarg_T *cap)
|
||||
{
|
||||
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
|
||||
finish_op = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -55,12 +55,11 @@ static yankreg_T y_regs[NUM_REGISTERS];
|
||||
|
||||
static yankreg_T *y_previous = NULL; /* ptr to last written yankreg */
|
||||
|
||||
static bool clipboard_didwarn_unnamed = false;
|
||||
|
||||
// for behavior between start_batch_changes() and end_batch_changes())
|
||||
static bool clipboard_delay_update = false; // delay clipboard update
|
||||
static int batch_change_count = 0; // inside a script
|
||||
static bool clipboard_delay_update = false; // delay clipboard update
|
||||
static bool clipboard_needs_update = false; // clipboard was updated
|
||||
static bool clipboard_didwarn = false;
|
||||
|
||||
/*
|
||||
* structure used by block_prep, op_delete and op_yank for blockwise operators
|
||||
@ -2061,7 +2060,7 @@ void op_insert(oparg_T *oap, long count1)
|
||||
}
|
||||
|
||||
t1 = oap->start;
|
||||
edit(NUL, false, (linenr_T)count1);
|
||||
(void)edit(NUL, false, (linenr_T)count1);
|
||||
|
||||
// When a tab was inserted, and the characters in front of the tab
|
||||
// have been converted to a tab as well, the column of the cursor
|
||||
@ -5524,7 +5523,7 @@ int get_default_register_name(void)
|
||||
}
|
||||
|
||||
/// Determine if register `*name` should be used as a clipboard.
|
||||
/// In an unnammed operation, `*name` is `NUL` and will be adjusted to `'*'/'+'` if
|
||||
/// In an unnamed operation, `*name` is `NUL` and will be adjusted to */+ if
|
||||
/// `clipboard=unnamed[plus]` is set.
|
||||
///
|
||||
/// @param name The name of register, or `NUL` if unnamed.
|
||||
@ -5535,33 +5534,41 @@ int get_default_register_name(void)
|
||||
/// if the register isn't a clipboard or provider isn't available.
|
||||
static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
|
||||
{
|
||||
if (*name == '*' || *name == '+') {
|
||||
if(!eval_has_provider("clipboard")) {
|
||||
if (!quiet) {
|
||||
EMSG("clipboard: No provider. Try \":CheckHealth\" or "
|
||||
"\":h clipboard\".");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER];
|
||||
} else if ((*name == NUL) && (cb_flags & CB_UNNAMEDMASK)) {
|
||||
if(!eval_has_provider("clipboard")) {
|
||||
if (!quiet && !clipboard_didwarn_unnamed) {
|
||||
msg((char_u *)"clipboard: No provider. Try \":CheckHealth\" or "
|
||||
"\":h clipboard\".");
|
||||
clipboard_didwarn_unnamed = true;
|
||||
}
|
||||
return NULL;
|
||||
#define MSG_NO_CLIP "clipboard: No provider. " \
|
||||
"Try \":CheckHealth\" or \":h clipboard\"."
|
||||
|
||||
yankreg_T *target = NULL;
|
||||
bool explicit_cb_reg = (*name == '*' || *name == '+');
|
||||
bool implicit_cb_reg = (*name == NUL) && (cb_flags & CB_UNNAMEDMASK);
|
||||
if (!explicit_cb_reg && !implicit_cb_reg) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!eval_has_provider("clipboard")) {
|
||||
if (batch_change_count == 1 && !quiet
|
||||
&& (!clipboard_didwarn || (explicit_cb_reg && !redirecting()))) {
|
||||
clipboard_didwarn = true;
|
||||
// Do NOT error (emsg()) here--if it interrupts :redir we get into
|
||||
// a weird state, stuck in "redirect mode".
|
||||
msg((char_u *)MSG_NO_CLIP);
|
||||
}
|
||||
// ... else, be silent (don't flood during :while, :redir, etc.).
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (explicit_cb_reg) {
|
||||
target = &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER];
|
||||
goto end;
|
||||
} else { // unnamed register: "implicit" clipboard
|
||||
if (writing && clipboard_delay_update) {
|
||||
// For "set" (copy), defer the clipboard call.
|
||||
clipboard_needs_update = true;
|
||||
return NULL;
|
||||
goto end;
|
||||
} else if (!writing && clipboard_needs_update) {
|
||||
// use the internal value
|
||||
return NULL;
|
||||
// For "get" (paste), use the internal value.
|
||||
goto end;
|
||||
}
|
||||
|
||||
yankreg_T *target;
|
||||
if (cb_flags & CB_UNNAMEDPLUS) {
|
||||
*name = (cb_flags & CB_UNNAMED && writing) ? '"': '+';
|
||||
target = &y_regs[PLUS_REGISTER];
|
||||
@ -5569,10 +5576,11 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
|
||||
*name = '*';
|
||||
target = &y_regs[STAR_REGISTER];
|
||||
}
|
||||
return target; // unnamed register
|
||||
goto end;
|
||||
}
|
||||
// don't do anything for other register names
|
||||
return NULL;
|
||||
|
||||
end:
|
||||
return target;
|
||||
}
|
||||
|
||||
static bool get_clipboard(int name, yankreg_T **target, bool quiet)
|
||||
@ -5740,17 +5748,16 @@ static void set_clipboard(int name, yankreg_T *reg)
|
||||
(void)eval_call_provider("clipboard", "set", args);
|
||||
}
|
||||
|
||||
/// Avoid clipboard (slow) during batch operations (i.e., a script).
|
||||
/// Avoid slow things (clipboard) during batch operations (while/for-loops).
|
||||
void start_batch_changes(void)
|
||||
{
|
||||
if (++batch_change_count > 1) {
|
||||
return;
|
||||
}
|
||||
clipboard_delay_update = true;
|
||||
clipboard_needs_update = false;
|
||||
}
|
||||
|
||||
/// Update the clipboard after batch changes finished.
|
||||
/// Counterpart to start_batch_changes().
|
||||
void end_batch_changes(void)
|
||||
{
|
||||
if (--batch_change_count > 0) {
|
||||
@ -5759,11 +5766,37 @@ void end_batch_changes(void)
|
||||
}
|
||||
clipboard_delay_update = false;
|
||||
if (clipboard_needs_update) {
|
||||
set_clipboard(NUL, y_previous);
|
||||
// must be before, as set_clipboard will invoke
|
||||
// start/end_batch_changes recursively
|
||||
clipboard_needs_update = false;
|
||||
// unnamed ("implicit" clipboard)
|
||||
set_clipboard(NUL, y_previous);
|
||||
}
|
||||
}
|
||||
|
||||
int save_batch_count(void)
|
||||
{
|
||||
int save_count = batch_change_count;
|
||||
batch_change_count = 0;
|
||||
clipboard_delay_update = false;
|
||||
if (clipboard_needs_update) {
|
||||
clipboard_needs_update = false;
|
||||
// unnamed ("implicit" clipboard)
|
||||
set_clipboard(NUL, y_previous);
|
||||
}
|
||||
return save_count;
|
||||
}
|
||||
|
||||
void restore_batch_count(int save_count)
|
||||
{
|
||||
assert(batch_change_count == 0);
|
||||
batch_change_count = save_count;
|
||||
if (batch_change_count > 0) {
|
||||
clipboard_delay_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Check whether register is empty
|
||||
static inline bool reg_empty(const yankreg_T *const reg)
|
||||
FUNC_ATTR_PURE
|
||||
|
@ -1749,7 +1749,7 @@ do_set (
|
||||
|
||||
if (flags & P_FLAGLIST) {
|
||||
// Remove flags that appear twice.
|
||||
for (s = newval; *s; s++) {
|
||||
for (s = newval; *s;) {
|
||||
// if options have P_FLAGLIST and P_ONECOMMA such as
|
||||
// 'whichwrap'
|
||||
if (flags & P_ONECOMMA) {
|
||||
@ -1757,15 +1757,16 @@ do_set (
|
||||
&& vim_strchr(s + 2, *s) != NULL) {
|
||||
// Remove the duplicated value and the next comma.
|
||||
STRMOVE(s, s + 2);
|
||||
s -= 2;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if ((!(flags & P_COMMA) || *s != ',')
|
||||
&& vim_strchr(s + 1, *s) != NULL) {
|
||||
STRMOVE(s, s + 1);
|
||||
s--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2996,9 +2997,10 @@ did_set_string_option (
|
||||
if (s[-1] == 'k' || s[-1] == 's') {
|
||||
/* skip optional filename after 'k' and 's' */
|
||||
while (*s && *s != ',' && *s != ' ') {
|
||||
if (*s == '\\')
|
||||
++s;
|
||||
++s;
|
||||
if (*s == '\\' && s[1] != NUL) {
|
||||
s++;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
} else {
|
||||
if (errbuf != NULL) {
|
||||
|
@ -2498,7 +2498,7 @@ return {
|
||||
no_mkrc=true,
|
||||
vi_def=true,
|
||||
varname='p_titleold',
|
||||
defaults={if_true={vi=N_("Thanks for flying Vim")}}
|
||||
defaults={if_true={vi=N_("")}}
|
||||
},
|
||||
{
|
||||
full_name='titlestring',
|
||||
|
@ -1690,6 +1690,9 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force)
|
||||
|
||||
if (strlen(fname) > (len - 1)) {
|
||||
xstrlcpy(buf, fname, len); // truncate
|
||||
#ifdef WIN32
|
||||
slash_adjust(buf);
|
||||
#endif
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
@ -1702,6 +1705,9 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force)
|
||||
if (rv == FAIL) {
|
||||
xstrlcpy(buf, fname, len); // something failed; use the filename
|
||||
}
|
||||
#ifdef WIN32
|
||||
slash_adjust(buf);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -2196,11 +2202,11 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf,
|
||||
|
||||
// expand it if forced or not an absolute path
|
||||
if (force || !path_is_absolute_path(fname)) {
|
||||
if ((p = vim_strrchr(fname, '/')) != NULL) {
|
||||
if ((p = vim_strrchr(fname, PATHSEP)) != NULL) {
|
||||
// relative to root
|
||||
if (p == fname) {
|
||||
// only one path component
|
||||
relative_directory[0] = '/';
|
||||
relative_directory[0] = PATHSEP;
|
||||
relative_directory[1] = NUL;
|
||||
} else {
|
||||
assert(p >= fname);
|
||||
|
@ -3316,6 +3316,47 @@ bt_regexec_nl (
|
||||
return (int)r;
|
||||
}
|
||||
|
||||
/// Wrapper around strchr which accounts for case-insensitive searches and
|
||||
/// non-ASCII characters.
|
||||
///
|
||||
/// This function is used a lot for simple searches, keep it fast!
|
||||
///
|
||||
/// @param s string to search
|
||||
/// @param c character to find in @a s
|
||||
///
|
||||
/// @return NULL if no match, otherwise pointer to the position in @a s
|
||||
static inline char_u *cstrchr(const char_u *const s, const int c)
|
||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||
FUNC_ATTR_ALWAYS_INLINE
|
||||
{
|
||||
if (!rex.reg_ic) {
|
||||
return vim_strchr(s, c);
|
||||
}
|
||||
|
||||
// Use folded case for UTF-8, slow! For ASCII use libc strpbrk which is
|
||||
// expected to be highly optimized.
|
||||
if (c > 0x80) {
|
||||
const int folded_c = utf_fold(c);
|
||||
for (const char_u *p = s; *p != NUL; p += utfc_ptr2len(p)) {
|
||||
if (utf_fold(utf_ptr2char(p)) == folded_c) {
|
||||
return (char_u *)p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cc;
|
||||
if (ASCII_ISUPPER(c)) {
|
||||
cc = TOLOWER_ASC(c);
|
||||
} else if (ASCII_ISLOWER(c)) {
|
||||
cc = TOUPPER_ASC(c);
|
||||
} else {
|
||||
return vim_strchr(s, c);
|
||||
}
|
||||
|
||||
char tofind[] = { (char)c, (char)cc, NUL };
|
||||
return (char_u *)strpbrk((const char *)s, tofind);
|
||||
}
|
||||
|
||||
/// Matches a regexp against multiple lines.
|
||||
/// "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
|
||||
@ -6320,42 +6361,6 @@ static int cstrncmp(char_u *s1, char_u *s2, int *n)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* cstrchr: This function is used a lot for simple searches, keep it fast!
|
||||
*/
|
||||
static inline char_u *cstrchr(const char_u *const s, const int c)
|
||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||
FUNC_ATTR_ALWAYS_INLINE
|
||||
{
|
||||
if (!rex.reg_ic) {
|
||||
return vim_strchr(s, c);
|
||||
}
|
||||
|
||||
// Use folded case for UTF-8, slow! For ASCII use libc strpbrk which is
|
||||
// expected to be highly optimized.
|
||||
if (c > 0x80) {
|
||||
const int folded_c = utf_fold(c);
|
||||
for (const char_u *p = s; *p != NUL; p += utfc_ptr2len(p)) {
|
||||
if (utf_fold(utf_ptr2char(p)) == folded_c) {
|
||||
return (char_u *)p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cc;
|
||||
if (ASCII_ISUPPER(c)) {
|
||||
cc = TOLOWER_ASC(c);
|
||||
} else if (ASCII_ISLOWER(c)) {
|
||||
cc = TOUPPER_ASC(c);
|
||||
} else {
|
||||
return vim_strchr(s, c);
|
||||
}
|
||||
|
||||
char tofind[] = { (char)c, (char)cc, NUL };
|
||||
return (char_u *)strpbrk((const char *)s, tofind);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* regsub stuff *
|
||||
***************************************************************/
|
||||
|
@ -2201,16 +2201,17 @@ win_line (
|
||||
int change_end = -1; /* last col of changed area */
|
||||
colnr_T trailcol = MAXCOL; /* start of trailing spaces */
|
||||
int need_showbreak = false; // overlong line, skip first x chars
|
||||
int line_attr = 0; /* attribute for the whole line */
|
||||
matchitem_T *cur; /* points to the match list */
|
||||
match_T *shl; /* points to search_hl or a match */
|
||||
int shl_flag; /* flag to indicate whether search_hl
|
||||
has been processed or not */
|
||||
int prevcol_hl_flag; /* flag to indicate whether prevcol
|
||||
equals startcol of search_hl or one
|
||||
of the matches */
|
||||
int prev_c = 0; /* previous Arabic character */
|
||||
int prev_c1 = 0; /* first composing char for prev_c */
|
||||
int line_attr = 0; // attribute for the whole line
|
||||
int line_attr_low_priority = 0; // current line, lowest priority
|
||||
matchitem_T *cur; // points to the match list
|
||||
match_T *shl; // points to search_hl or a match
|
||||
int shl_flag; // flag to indicate whether search_hl
|
||||
// has been processed or not
|
||||
int prevcol_hl_flag; // flag to indicate whether prevcol
|
||||
// equals startcol of search_hl or one
|
||||
// of the matches
|
||||
int prev_c = 0; // previous Arabic character
|
||||
int prev_c1 = 0; // first composing char for prev_c
|
||||
int did_line_attr = 0;
|
||||
|
||||
bool search_attr_from_match = false; // if search_attr is from :match
|
||||
@ -2427,10 +2428,17 @@ win_line (
|
||||
filler_lines = wp->w_topfill;
|
||||
filler_todo = filler_lines;
|
||||
|
||||
/* If this line has a sign with line highlighting set line_attr. */
|
||||
// 'cursorline' highlighting for the current window. Not when Visual mode is
|
||||
// active, because it's not clear what is selected then.
|
||||
if (wp->w_p_cul && lnum == wp->w_cursor.lnum
|
||||
&& !(wp == curwin && VIsual_active)) {
|
||||
line_attr_low_priority = win_hl_attr(wp, HLF_CUL);
|
||||
}
|
||||
|
||||
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
|
||||
if (v != 0)
|
||||
line_attr = sign_get_attr((int)v, TRUE);
|
||||
if (v != 0) {
|
||||
line_attr = sign_get_attr((int)v, true);
|
||||
}
|
||||
|
||||
// Highlight the current line in the quickfix window.
|
||||
if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) {
|
||||
@ -2441,7 +2449,7 @@ win_line (
|
||||
line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr);
|
||||
}
|
||||
|
||||
if (line_attr != 0) {
|
||||
if (line_attr_low_priority || line_attr) {
|
||||
area_highlighting = true;
|
||||
}
|
||||
|
||||
@ -2663,20 +2671,6 @@ win_line (
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
/* Cursor line highlighting for 'cursorline' in the current window. Not
|
||||
* when Visual mode is active, because it's not clear what is selected
|
||||
* then. */
|
||||
if (wp->w_p_cul && lnum == wp->w_cursor.lnum
|
||||
&& !(wp == curwin && VIsual_active)) {
|
||||
if (line_attr != 0 && !(State & INSERT) && bt_quickfix(wp->w_buffer)
|
||||
&& qf_current_entry(wp) == lnum) {
|
||||
line_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), line_attr);
|
||||
} else {
|
||||
line_attr = win_hl_attr(wp, HLF_CUL);
|
||||
}
|
||||
area_highlighting = true;
|
||||
}
|
||||
|
||||
off = (unsigned)(current_ScreenLine - ScreenLines);
|
||||
col = 0;
|
||||
if (wp->w_p_rl) {
|
||||
@ -3594,15 +3588,15 @@ win_line (
|
||||
&& lcs_eol_one > 0) {
|
||||
// Display a '$' after the line or highlight an extra
|
||||
// character if the line break is included.
|
||||
// For a diff line the highlighting continues after the
|
||||
// "$".
|
||||
if (diff_hlf == (hlf_T)0 && line_attr == 0) {
|
||||
/* In virtualedit, visual selections may extend
|
||||
* beyond end of line. */
|
||||
// For a diff line the highlighting continues after the "$".
|
||||
if (diff_hlf == (hlf_T)0
|
||||
&& line_attr == 0
|
||||
&& line_attr_low_priority == 0) {
|
||||
// In virtualedit, visual selections may extend beyond end of line.
|
||||
if (area_highlighting && virtual_active()
|
||||
&& tocol != MAXCOL && vcol < tocol)
|
||||
&& tocol != MAXCOL && vcol < tocol) {
|
||||
n_extra = 0;
|
||||
else {
|
||||
} else {
|
||||
p_extra = at_end_str;
|
||||
n_extra = 1;
|
||||
c_extra = NUL;
|
||||
@ -3661,7 +3655,7 @@ win_line (
|
||||
(col < wp->w_width))) {
|
||||
c = ' ';
|
||||
ptr--; // put it back at the NUL
|
||||
} else if ((diff_hlf != (hlf_T)0 || line_attr != 0)
|
||||
} else if ((diff_hlf != (hlf_T)0 || line_attr_low_priority || line_attr)
|
||||
&& (wp->w_p_rl
|
||||
? (col >= 0)
|
||||
: (col - boguscols < wp->w_width))) {
|
||||
@ -3673,7 +3667,8 @@ win_line (
|
||||
did_line_attr++;
|
||||
|
||||
// don't do search HL for the rest of the line
|
||||
if (line_attr != 0 && char_attr == search_attr && col > 0) {
|
||||
if ((line_attr_low_priority || line_attr)
|
||||
&& char_attr == search_attr && col > 0) {
|
||||
char_attr = line_attr;
|
||||
}
|
||||
if (diff_hlf == HLF_TXD) {
|
||||
@ -4035,13 +4030,16 @@ win_line (
|
||||
if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
|
||||
&& lnum != wp->w_cursor.lnum) {
|
||||
vcol_save_attr = char_attr;
|
||||
char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUC));
|
||||
char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), char_attr);
|
||||
} else if (draw_color_col && VCOL_HLC == *color_cols) {
|
||||
vcol_save_attr = char_attr;
|
||||
char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_MC));
|
||||
char_attr = hl_combine_attr(win_hl_attr(wp, HLF_MC), char_attr);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply `line_attr_low_priority` now, so that everthing can override it.
|
||||
char_attr = hl_combine_attr(line_attr_low_priority, char_attr);
|
||||
|
||||
/*
|
||||
* Store character to be displayed.
|
||||
* Skip characters that are left of the screen for 'nowrap'.
|
||||
@ -5847,7 +5845,7 @@ static void screen_start_highlight(int attr)
|
||||
ui_start_highlight(attr);
|
||||
}
|
||||
|
||||
void screen_stop_highlight(void)
|
||||
static void screen_stop_highlight(void)
|
||||
{
|
||||
ui_stop_highlight();
|
||||
screen_attr = 0;
|
||||
|
@ -3557,11 +3557,15 @@ extend:
|
||||
--start_lnum;
|
||||
|
||||
if (VIsual_active) {
|
||||
/* Problem: when doing "Vipipip" nothing happens in a single white
|
||||
* line, we get stuck there. Trap this here. */
|
||||
if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum)
|
||||
// Problem: when doing "Vipipip" nothing happens in a single white
|
||||
// line, we get stuck there. Trap this here.
|
||||
if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum) {
|
||||
goto extend;
|
||||
VIsual.lnum = start_lnum;
|
||||
}
|
||||
if (VIsual.lnum != start_lnum) {
|
||||
VIsual.lnum = start_lnum;
|
||||
VIsual.col = 0;
|
||||
}
|
||||
VIsual_mode = 'V';
|
||||
redraw_curbuf_later(INVERTED); /* update the inversion */
|
||||
showmode();
|
||||
|
@ -26,10 +26,11 @@ void state_enter(VimState *s)
|
||||
int check_result = s->check ? s->check(s) : 1;
|
||||
|
||||
if (!check_result) {
|
||||
break;
|
||||
break; // Terminate this state.
|
||||
} else if (check_result == -1) {
|
||||
continue;
|
||||
continue; // check() again.
|
||||
}
|
||||
// Execute this state.
|
||||
|
||||
int key;
|
||||
|
||||
@ -48,11 +49,13 @@ getkey:
|
||||
ui_flush();
|
||||
// Call `os_inchar` directly to block for events or user input without
|
||||
// consuming anything from `input_buffer`(os/input.c) or calling the
|
||||
// mapping engine. If an event was put into the queue, we send K_EVENT
|
||||
// directly.
|
||||
// mapping engine.
|
||||
(void)os_inchar(NULL, 0, -1, 0);
|
||||
input_disable_events();
|
||||
key = !multiqueue_empty(main_loop.events) ? K_EVENT : safe_vgetc();
|
||||
// If an event was put into the queue, we send K_EVENT directly.
|
||||
key = !multiqueue_empty(main_loop.events)
|
||||
? K_EVENT
|
||||
: safe_vgetc();
|
||||
}
|
||||
|
||||
if (key == K_EVENT) {
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "nvim/ui.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/time.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
|
||||
static bool did_syntax_onoff = false;
|
||||
|
||||
@ -81,7 +82,10 @@ struct hl_group {
|
||||
// highlight groups for 'highlight' option
|
||||
static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
|
||||
|
||||
#define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data)))
|
||||
static inline struct hl_group * HL_TABLE(void)
|
||||
{
|
||||
return ((struct hl_group *)((highlight_ga.ga_data)));
|
||||
}
|
||||
|
||||
#define MAX_HL_ID 20000 /* maximum value for a highlight ID. */
|
||||
|
||||
@ -100,10 +104,8 @@ static int include_none = 0; /* when 1 include "nvim/None" */
|
||||
static int include_default = 0; /* when 1 include "nvim/default" */
|
||||
static int include_link = 0; /* when 2 include "nvim/link" and "clear" */
|
||||
|
||||
/*
|
||||
* The "term", "cterm" and "gui" arguments can be any combination of the
|
||||
* following names, separated by commas (but no spaces!).
|
||||
*/
|
||||
/// The "term", "cterm" and "gui" arguments can be any combination of the
|
||||
/// following names, separated by commas (but no spaces!).
|
||||
static char *(hl_name_table[]) =
|
||||
{"bold", "standout", "underline", "undercurl",
|
||||
"italic", "reverse", "inverse", "NONE"};
|
||||
@ -1775,8 +1777,9 @@ syn_current_attr (
|
||||
cur_si->si_trans_id = CUR_STATE(
|
||||
current_state.ga_len - 2).si_trans_id;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
cur_si->si_attr = syn_id2attr(syn_id);
|
||||
}
|
||||
cur_si->si_cont_list = NULL;
|
||||
cur_si->si_next_list = next_list;
|
||||
check_keepend();
|
||||
@ -5252,12 +5255,10 @@ get_id_list (
|
||||
/*
|
||||
* Handle full group name.
|
||||
*/
|
||||
if (vim_strpbrk(name + 1, (char_u *)"\\.*^$~[") == NULL)
|
||||
if (vim_strpbrk(name + 1, (char_u *)"\\.*^$~[") == NULL) {
|
||||
id = syn_check_group(name + 1, (int)(end - p));
|
||||
else {
|
||||
/*
|
||||
* Handle match of regexp with group names.
|
||||
*/
|
||||
} else {
|
||||
// Handle match of regexp with group names.
|
||||
*name = '^';
|
||||
STRCAT(name, "$");
|
||||
regmatch.regprog = vim_regcomp(name, RE_MAGIC);
|
||||
@ -5567,8 +5568,10 @@ bool syntax_present(win_T *win)
|
||||
|
||||
|
||||
static enum {
|
||||
EXP_SUBCMD, /* expand ":syn" sub-commands */
|
||||
EXP_CASE /* expand ":syn case" arguments */
|
||||
EXP_SUBCMD, // expand ":syn" sub-commands
|
||||
EXP_CASE, // expand ":syn case" arguments
|
||||
EXP_SPELL, // expand ":syn spell" arguments
|
||||
EXP_SYNC // expand ":syn sync" arguments
|
||||
} expand_what;
|
||||
|
||||
/*
|
||||
@ -5612,6 +5615,10 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg)
|
||||
xp->xp_context = EXPAND_NOTHING;
|
||||
} else if (STRNICMP(arg, "case", p - arg) == 0) {
|
||||
expand_what = EXP_CASE;
|
||||
} else if (STRNICMP(arg, "spell", p - arg) == 0) {
|
||||
expand_what = EXP_SPELL;
|
||||
} else if (STRNICMP(arg, "sync", p - arg) == 0) {
|
||||
expand_what = EXP_SYNC;
|
||||
} else if (STRNICMP(arg, "keyword", p - arg) == 0
|
||||
|| STRNICMP(arg, "region", p - arg) == 0
|
||||
|| STRNICMP(arg, "match", p - arg) == 0
|
||||
@ -5624,17 +5631,33 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static char *(case_args[]) = {"match", "ignore", NULL};
|
||||
|
||||
/*
|
||||
* Function given to ExpandGeneric() to obtain the list syntax names for
|
||||
* expansion.
|
||||
*/
|
||||
char_u *get_syntax_name(expand_T *xp, int idx)
|
||||
{
|
||||
if (expand_what == EXP_SUBCMD)
|
||||
return (char_u *)subcommands[idx].name;
|
||||
return (char_u *)case_args[idx];
|
||||
switch (expand_what) {
|
||||
case EXP_SUBCMD:
|
||||
return (char_u *)subcommands[idx].name;
|
||||
case EXP_CASE: {
|
||||
static char *case_args[] = { "match", "ignore", NULL };
|
||||
return (char_u *)case_args[idx];
|
||||
}
|
||||
case EXP_SPELL: {
|
||||
static char *spell_args[] =
|
||||
{ "toplevel", "notoplevel", "default", NULL };
|
||||
return (char_u *)spell_args[idx];
|
||||
}
|
||||
case EXP_SYNC: {
|
||||
static char *sync_args[] =
|
||||
{ "ccomment", "clear", "fromstart",
|
||||
"linebreaks=", "linecont", "lines=", "match",
|
||||
"maxlines=", "minlines=", "region", NULL };
|
||||
return (char_u *)sync_args[idx];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -5845,9 +5868,12 @@ static void syntime_report(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* sort on total time */
|
||||
qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(time_entry_T),
|
||||
syn_compare_syntime);
|
||||
// Sort on total time. Skip if there are no items to avoid passing NULL
|
||||
// pointer to qsort().
|
||||
if (ga.ga_len > 1) {
|
||||
qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(time_entry_T),
|
||||
syn_compare_syntime);
|
||||
}
|
||||
|
||||
MSG_PUTS_TITLE(_(
|
||||
" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"));
|
||||
@ -5958,6 +5984,7 @@ static char *highlight_init_light[] =
|
||||
"Title ctermfg=DarkMagenta gui=bold guifg=Magenta",
|
||||
"Visual guibg=LightGrey",
|
||||
"WarningMsg ctermfg=DarkRed guifg=Red",
|
||||
"Normal gui=NONE",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -5991,23 +6018,25 @@ static char *highlight_init_dark[] =
|
||||
"Title ctermfg=LightMagenta gui=bold guifg=Magenta",
|
||||
"Visual guibg=DarkGrey",
|
||||
"WarningMsg ctermfg=LightRed guifg=Red",
|
||||
"Normal gui=NONE",
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
init_highlight (
|
||||
int both, /* include groups where 'bg' doesn't matter */
|
||||
int reset /* clear group first */
|
||||
)
|
||||
|
||||
/// Load colors from a file if "g:colors_name" is set, otherwise load builtin
|
||||
/// colors
|
||||
///
|
||||
/// @param both include groups where 'bg' doesn't matter
|
||||
/// @param reset clear groups first
|
||||
void
|
||||
init_highlight(int both, int reset)
|
||||
{
|
||||
int i;
|
||||
char **pp;
|
||||
static int had_both = FALSE;
|
||||
|
||||
/*
|
||||
* Try finding the color scheme file. Used when a color file was loaded
|
||||
* and 'background' or 't_Co' is changed.
|
||||
*/
|
||||
// Try finding the color scheme file. Used when a color file was loaded
|
||||
// and 'background' or 't_Co' is changed.
|
||||
char_u *p = get_var_value("g:colors_name");
|
||||
if (p != NULL) {
|
||||
// Value of g:colors_name could be freed in load_colors() and make
|
||||
@ -6026,33 +6055,34 @@ init_highlight (
|
||||
if (both) {
|
||||
had_both = TRUE;
|
||||
pp = highlight_init_both;
|
||||
for (i = 0; pp[i] != NULL; ++i)
|
||||
do_highlight((char_u *)pp[i], reset, TRUE);
|
||||
} else if (!had_both)
|
||||
/* Don't do anything before the call with both == TRUE from main().
|
||||
* Not everything has been setup then, and that call will overrule
|
||||
* everything anyway. */
|
||||
for (i = 0; pp[i] != NULL; i++) {
|
||||
do_highlight((char_u *)pp[i], reset, true);
|
||||
}
|
||||
} else if (!had_both) {
|
||||
// Don't do anything before the call with both == TRUE from main().
|
||||
// Not everything has been setup then, and that call will overrule
|
||||
// everything anyway.
|
||||
return;
|
||||
}
|
||||
|
||||
if (*p_bg == 'l')
|
||||
pp = highlight_init_light;
|
||||
else
|
||||
pp = highlight_init_dark;
|
||||
for (i = 0; pp[i] != NULL; ++i)
|
||||
do_highlight((char_u *)pp[i], reset, TRUE);
|
||||
pp = (*p_bg == 'l') ? highlight_init_light : highlight_init_dark;
|
||||
|
||||
for (i = 0; pp[i] != NULL; i++) {
|
||||
do_highlight((char_u *)pp[i], reset, true);
|
||||
}
|
||||
|
||||
/* Reverse looks ugly, but grey may not work for 8 colors. Thus let it
|
||||
* depend on the number of colors available.
|
||||
* With 8 colors brown is equal to yellow, need to use black for Search fg
|
||||
* to avoid Statement highlighted text disappears.
|
||||
* Clear the attributes, needed when changing the t_Co value. */
|
||||
if (t_colors > 8)
|
||||
if (t_colors > 8) {
|
||||
do_highlight(
|
||||
(char_u *)(*p_bg == 'l'
|
||||
? "Visual cterm=NONE ctermbg=LightGrey"
|
||||
: "Visual cterm=NONE ctermbg=DarkGrey"), FALSE,
|
||||
TRUE);
|
||||
else {
|
||||
: "Visual cterm=NONE ctermbg=DarkGrey"), false,
|
||||
true);
|
||||
} else {
|
||||
do_highlight((char_u *)"Visual cterm=reverse ctermbg=NONE",
|
||||
FALSE, TRUE);
|
||||
if (*p_bg == 'l')
|
||||
@ -6112,12 +6142,7 @@ int load_colors(char_u *name)
|
||||
/// "forceit" and "init" both TRUE.
|
||||
/// @param init TRUE when called for initializing
|
||||
void
|
||||
do_highlight(
|
||||
char_u *line,
|
||||
int forceit,
|
||||
int init
|
||||
)
|
||||
{
|
||||
do_highlight(char_u *line, int forceit, int init) {
|
||||
char_u *name_end;
|
||||
char_u *linep;
|
||||
char_u *key_start;
|
||||
@ -6134,15 +6159,16 @@ do_highlight(
|
||||
int dolink = FALSE;
|
||||
int error = FALSE;
|
||||
int color;
|
||||
int is_normal_group = FALSE; /* "Normal" group */
|
||||
bool is_normal_group = false; // "Normal" group
|
||||
|
||||
/*
|
||||
* If no argument, list current highlighting.
|
||||
*/
|
||||
if (ends_excmd(*line)) {
|
||||
for (int i = 1; i <= highlight_ga.ga_len && !got_int; ++i)
|
||||
/* TODO: only call when the group has attributes set */
|
||||
for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
|
||||
// todo(vim): only call when the group has attributes set
|
||||
highlight_list_one(i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -6270,12 +6296,12 @@ do_highlight(
|
||||
return;
|
||||
idx = id - 1; /* index is ID minus one */
|
||||
|
||||
/* Return if "default" was used and the group already has settings. */
|
||||
if (dodefault && hl_has_settings(idx, TRUE))
|
||||
// Return if "default" was used and the group already has settings
|
||||
if (dodefault && hl_has_settings(idx, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
|
||||
is_normal_group = TRUE;
|
||||
is_normal_group = (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0);
|
||||
|
||||
/* Clear the highlighting for ":hi clear {group}" and ":hi clear". */
|
||||
if (doclear || (forceit && init)) {
|
||||
@ -6284,7 +6310,7 @@ do_highlight(
|
||||
HL_TABLE()[idx].sg_set = 0;
|
||||
}
|
||||
|
||||
if (!doclear)
|
||||
if (!doclear) {
|
||||
while (!ends_excmd(*linep)) {
|
||||
key_start = linep;
|
||||
if (*linep == '=') {
|
||||
@ -6390,12 +6416,12 @@ do_highlight(
|
||||
}
|
||||
}
|
||||
} else if (STRCMP(key, "FONT") == 0) {
|
||||
/* in non-GUI fonts are simply ignored */
|
||||
} else if (STRCMP(key,
|
||||
"CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) {
|
||||
// in non-GUI fonts are simply ignored
|
||||
} else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) {
|
||||
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
|
||||
if (!init)
|
||||
if (!init) {
|
||||
HL_TABLE()[idx].sg_set |= SG_CTERM;
|
||||
}
|
||||
|
||||
/* When setting the foreground color, and previously the "bold"
|
||||
* flag was set for a light color, reset it now */
|
||||
@ -6489,9 +6515,10 @@ do_highlight(
|
||||
* colors (on some terminals, e.g. "linux") */
|
||||
if (color & 8) {
|
||||
HL_TABLE()[idx].sg_cterm |= HL_BOLD;
|
||||
HL_TABLE()[idx].sg_cterm_bold = TRUE;
|
||||
} else
|
||||
HL_TABLE()[idx].sg_cterm_bold = true;
|
||||
} else {
|
||||
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
|
||||
}
|
||||
}
|
||||
color &= 7; // truncate to 8 colors
|
||||
} else if (t_colors == 16 || t_colors == 88 || t_colors >= 256) {
|
||||
@ -6603,38 +6630,40 @@ do_highlight(
|
||||
/*
|
||||
* When highlighting has been given for a group, don't link it.
|
||||
*/
|
||||
if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK))
|
||||
if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK)) {
|
||||
HL_TABLE()[idx].sg_link = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Continue with next argument.
|
||||
*/
|
||||
linep = skipwhite(linep);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is an error, and it's a new entry, remove it from the table.
|
||||
*/
|
||||
if (error && idx == highlight_ga.ga_len)
|
||||
if (error && idx == highlight_ga.ga_len) {
|
||||
syn_unadd_group();
|
||||
else {
|
||||
} else {
|
||||
if (is_normal_group) {
|
||||
HL_TABLE()[idx].sg_attr = 0;
|
||||
// Need to update all groups, because they might be using "bg" and/or
|
||||
// "fg", which have been changed now.
|
||||
highlight_attr_set_all();
|
||||
// If the normal group has changed, it is simpler to refresh every UI
|
||||
ui_refresh();
|
||||
} else
|
||||
} else {
|
||||
set_hl_attr(idx);
|
||||
}
|
||||
HL_TABLE()[idx].sg_scriptID = current_SID;
|
||||
redraw_all_later(NOT_VALID);
|
||||
}
|
||||
xfree(key);
|
||||
xfree(arg);
|
||||
|
||||
/* Only call highlight_changed() once, after sourcing a syntax file */
|
||||
need_highlight_changed = TRUE;
|
||||
// Only call highlight_changed() once, after sourcing a syntax file
|
||||
need_highlight_changed = true;
|
||||
}
|
||||
|
||||
#if defined(EXITFREE)
|
||||
@ -6707,14 +6736,15 @@ static void highlight_clear(int idx)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Table with the specifications for an attribute number.
|
||||
* Note that this table is used by ALL buffers. This is required because the
|
||||
* GUI can redraw at any time for any buffer.
|
||||
*/
|
||||
/// Table with the specifications for an attribute number.
|
||||
/// Note that this table is used by ALL buffers. This is required because the
|
||||
/// GUI can redraw at any time for any buffer.
|
||||
static garray_T attr_table = GA_EMPTY_INIT_VALUE;
|
||||
|
||||
#define ATTR_ENTRY(idx) ((attrentry_T *)attr_table.ga_data)[idx]
|
||||
static inline attrentry_T * ATTR_ENTRY(int idx)
|
||||
{
|
||||
return &((attrentry_T *)attr_table.ga_data)[idx];
|
||||
}
|
||||
|
||||
|
||||
/// Return the attr number for a set of colors and font.
|
||||
@ -6804,7 +6834,7 @@ int hl_combine_attr(int char_attr, int prim_attr)
|
||||
{
|
||||
attrentry_T *char_aep = NULL;
|
||||
attrentry_T *spell_aep;
|
||||
attrentry_T new_en;
|
||||
attrentry_T new_en = ATTRENTRY_INIT;
|
||||
|
||||
if (char_attr == 0) {
|
||||
return prim_attr;
|
||||
@ -6820,8 +6850,6 @@ int hl_combine_attr(int char_attr, int prim_attr)
|
||||
if (char_aep != NULL) {
|
||||
// Copy all attributes from char_aep to the new entry
|
||||
new_en = *char_aep;
|
||||
} else {
|
||||
memset(&new_en, 0, sizeof(new_en));
|
||||
}
|
||||
|
||||
spell_aep = syn_cterm_attr2entry(prim_attr);
|
||||
@ -6852,17 +6880,25 @@ int hl_combine_attr(int char_attr, int prim_attr)
|
||||
return get_attr_entry(&new_en);
|
||||
}
|
||||
|
||||
/// \note this function does not apply exclusively to cterm attr contrary
|
||||
/// to what its name implies
|
||||
/// \warn don't call it with attr 0 (i.e., the null attribute)
|
||||
attrentry_T *syn_cterm_attr2entry(int attr)
|
||||
{
|
||||
attr -= ATTR_OFF;
|
||||
if (attr >= attr_table.ga_len) /* did ":syntax clear" */
|
||||
if (attr >= attr_table.ga_len) {
|
||||
// did ":syntax clear"
|
||||
return NULL;
|
||||
return &(ATTR_ENTRY(attr));
|
||||
}
|
||||
return ATTR_ENTRY(attr);
|
||||
}
|
||||
|
||||
/// \addtogroup LIST_XXX
|
||||
/// @{
|
||||
#define LIST_ATTR 1
|
||||
#define LIST_STRING 2
|
||||
#define LIST_INT 3
|
||||
/// @}
|
||||
|
||||
static void highlight_list_one(int id)
|
||||
{
|
||||
@ -6901,7 +6937,13 @@ static void highlight_list_one(int id)
|
||||
last_set_msg(sgp->sg_scriptID);
|
||||
}
|
||||
|
||||
static int highlight_list_arg(int id, int didh, int type, int iarg, char_u *sarg, char *name)
|
||||
/// Outputs a highlight when doing ":hi MyHighlight"
|
||||
///
|
||||
/// @param type one of \ref LIST_XXX
|
||||
/// @param iarg integer argument used if \p type == LIST_INT
|
||||
/// @param sarg string used if \p type == LIST_STRING
|
||||
static int highlight_list_arg(int id, int didh, int type, int iarg,
|
||||
char_u *sarg, const char *name)
|
||||
{
|
||||
char_u buf[100];
|
||||
char_u *ts;
|
||||
@ -7041,24 +7083,23 @@ const char *highlight_color(const int id, const char *const what,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output the syntax list header.
|
||||
* Return TRUE when started a new line.
|
||||
*/
|
||||
static int
|
||||
syn_list_header (
|
||||
int did_header, /* did header already */
|
||||
int outlen, /* length of string that comes */
|
||||
int id /* highlight group id */
|
||||
)
|
||||
/// Output the syntax list header.
|
||||
///
|
||||
/// @param did_header did header already
|
||||
/// @param outlen length of string that comes
|
||||
/// @param id highlight group id
|
||||
/// @return true when started a new line.
|
||||
static int
|
||||
syn_list_header(int did_header, int outlen, int id)
|
||||
{
|
||||
int endcol = 19;
|
||||
int newline = TRUE;
|
||||
|
||||
if (!did_header) {
|
||||
msg_putchar('\n');
|
||||
if (got_int)
|
||||
return TRUE;
|
||||
if (got_int) {
|
||||
return true;
|
||||
}
|
||||
msg_outtrans(HL_TABLE()[id - 1].sg_name);
|
||||
endcol = 15;
|
||||
} else if (msg_col + outlen + 1 >= Columns) {
|
||||
@ -7086,21 +7127,14 @@ syn_list_header (
|
||||
return newline;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the attribute numbers for a highlight group.
|
||||
* Called after one of the attributes has changed.
|
||||
*/
|
||||
static void
|
||||
set_hl_attr (
|
||||
int idx /* index in array */
|
||||
)
|
||||
/// Set the attribute numbers for a highlight group.
|
||||
/// Called after one of the attributes has changed.
|
||||
/// @param idx corrected highlight index
|
||||
static void set_hl_attr(int idx)
|
||||
{
|
||||
attrentry_T at_en;
|
||||
attrentry_T at_en = ATTRENTRY_INIT;
|
||||
struct hl_group *sgp = HL_TABLE() + idx;
|
||||
|
||||
/* The "Normal" group doesn't need an attribute number */
|
||||
if (sgp->sg_name_u != NULL && STRCMP(sgp->sg_name_u, "NORMAL") == 0)
|
||||
return;
|
||||
|
||||
at_en.cterm_ae_attr = sgp->sg_cterm;
|
||||
at_en.cterm_fg_color = sgp->sg_cterm_fg;
|
||||
@ -7124,10 +7158,10 @@ set_hl_attr (
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup a highlight group name and return it's ID.
|
||||
* If it is not found, 0 is returned.
|
||||
*/
|
||||
/// Lookup a highlight group name and return its ID.
|
||||
///
|
||||
/// @param highlight name e.g. 'Cursor', 'Normal'
|
||||
/// @return the highlight id, else 0 if \p name does not exist
|
||||
int syn_name2id(const char_u *name)
|
||||
{
|
||||
int i;
|
||||
@ -7176,7 +7210,7 @@ int syn_namen2id(char_u *linep, int len)
|
||||
return id;
|
||||
}
|
||||
|
||||
/// Find highlight group name in the table and return it's ID.
|
||||
/// Find highlight group name in the table and return its ID.
|
||||
/// If it doesn't exist yet, a new entry is created.
|
||||
///
|
||||
/// @param pp Highlight group name
|
||||
@ -7195,11 +7229,11 @@ int syn_check_group(char_u *pp, int len)
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add new highlight group and return it's ID.
|
||||
* "name" must be an allocated string, it will be consumed.
|
||||
* Return 0 for failure.
|
||||
*/
|
||||
/// Add new highlight group and return it's ID.
|
||||
///
|
||||
/// @param name must be an allocated string, it will be consumed.
|
||||
/// @return 0 for failure, else the allocated group id
|
||||
/// @see syn_check_group syn_unadd_group
|
||||
static int syn_add_group(char_u *name)
|
||||
{
|
||||
char_u *p;
|
||||
@ -7237,25 +7271,26 @@ static int syn_add_group(char_u *name)
|
||||
struct hl_group* hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga);
|
||||
memset(hlgp, 0, sizeof(*hlgp));
|
||||
hlgp->sg_name = name;
|
||||
hlgp->sg_rgb_bg = -1;
|
||||
hlgp->sg_rgb_fg = -1;
|
||||
hlgp->sg_rgb_sp = -1;
|
||||
hlgp->sg_name_u = vim_strsave_up(name);
|
||||
|
||||
return highlight_ga.ga_len; /* ID is index plus one */
|
||||
}
|
||||
|
||||
/*
|
||||
* When, just after calling syn_add_group(), an error is discovered, this
|
||||
* function deletes the new name.
|
||||
*/
|
||||
/// When, just after calling syn_add_group(), an error is discovered, this
|
||||
/// function deletes the new name.
|
||||
static void syn_unadd_group(void)
|
||||
{
|
||||
--highlight_ga.ga_len;
|
||||
highlight_ga.ga_len--;
|
||||
xfree(HL_TABLE()[highlight_ga.ga_len].sg_name);
|
||||
xfree(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a group ID to highlight attributes.
|
||||
*/
|
||||
|
||||
/// Translate a group ID to highlight attributes.
|
||||
/// @see syn_cterm_attr2entry
|
||||
int syn_id2attr(int hl_id)
|
||||
{
|
||||
struct hl_group *sgp;
|
||||
@ -8208,6 +8243,30 @@ RgbValue name_to_color(const uint8_t *name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Gets highlight description for id `attr_id` as a map.
|
||||
Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err)
|
||||
{
|
||||
HlAttrs attrs = HLATTRS_INIT;
|
||||
Dictionary dic = ARRAY_DICT_INIT;
|
||||
|
||||
if (attr_id == 0) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
attrentry_T *aep = syn_cterm_attr2entry((int)attr_id);
|
||||
if (!aep) {
|
||||
api_set_error(err, kErrorTypeException,
|
||||
"Invalid attribute id: %d", attr_id);
|
||||
return dic;
|
||||
}
|
||||
|
||||
attrs = attrentry2hlattrs(aep, rgb);
|
||||
|
||||
end:
|
||||
return hlattrs2dict(attrs);
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* End of Highlighting stuff *
|
||||
**************************************/
|
||||
|
@ -73,4 +73,14 @@ typedef struct attr_entry {
|
||||
int cterm_fg_color, cterm_bg_color;
|
||||
} attrentry_T;
|
||||
|
||||
#define ATTRENTRY_INIT { \
|
||||
.rgb_ae_attr = 0, \
|
||||
.cterm_ae_attr = 0, \
|
||||
.rgb_fg_color = -1, \
|
||||
.rgb_bg_color = -1, \
|
||||
.rgb_sp_color = -1, \
|
||||
.cterm_fg_color = 0, \
|
||||
.cterm_bg_color = 0, \
|
||||
}
|
||||
|
||||
#endif // NVIM_SYNTAX_DEFS_H
|
||||
|
@ -432,14 +432,6 @@ static int terminal_execute(VimState *state, int key)
|
||||
TerminalState *s = (TerminalState *)state;
|
||||
|
||||
switch (key) {
|
||||
case K_FOCUSGAINED: // nvim has been given focus
|
||||
apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
|
||||
break;
|
||||
|
||||
case K_FOCUSLOST: // nvim has lost focus
|
||||
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
|
||||
break;
|
||||
|
||||
// Temporary fix until paste events gets implemented
|
||||
case K_PASTE:
|
||||
break;
|
||||
@ -530,6 +522,12 @@ void terminal_send(Terminal *term, char *data, size_t size)
|
||||
void terminal_send_key(Terminal *term, int c)
|
||||
{
|
||||
VTermModifier mod = VTERM_MOD_NONE;
|
||||
|
||||
// Convert K_ZERO back to ASCII
|
||||
if (c == K_ZERO) {
|
||||
c = Ctrl_AT;
|
||||
}
|
||||
|
||||
VTermKey key = convert_key(c, &mod);
|
||||
|
||||
if (key) {
|
||||
@ -783,26 +781,60 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
|
||||
// }}}
|
||||
// input handling {{{
|
||||
|
||||
static void convert_modifiers(VTermModifier *statep)
|
||||
static void convert_modifiers(int key, VTermModifier *statep)
|
||||
{
|
||||
if (mod_mask & MOD_MASK_SHIFT) { *statep |= VTERM_MOD_SHIFT; }
|
||||
if (mod_mask & MOD_MASK_CTRL) { *statep |= VTERM_MOD_CTRL; }
|
||||
if (mod_mask & MOD_MASK_ALT) { *statep |= VTERM_MOD_ALT; }
|
||||
|
||||
switch (key) {
|
||||
case K_S_TAB:
|
||||
case K_S_UP:
|
||||
case K_S_DOWN:
|
||||
case K_S_LEFT:
|
||||
case K_S_RIGHT:
|
||||
case K_S_F1:
|
||||
case K_S_F2:
|
||||
case K_S_F3:
|
||||
case K_S_F4:
|
||||
case K_S_F5:
|
||||
case K_S_F6:
|
||||
case K_S_F7:
|
||||
case K_S_F8:
|
||||
case K_S_F9:
|
||||
case K_S_F10:
|
||||
case K_S_F11:
|
||||
case K_S_F12:
|
||||
*statep |= VTERM_MOD_SHIFT;
|
||||
break;
|
||||
|
||||
case K_C_LEFT:
|
||||
case K_C_RIGHT:
|
||||
*statep |= VTERM_MOD_CTRL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static VTermKey convert_key(int key, VTermModifier *statep)
|
||||
{
|
||||
convert_modifiers(statep);
|
||||
convert_modifiers(key, statep);
|
||||
|
||||
switch (key) {
|
||||
case K_BS: return VTERM_KEY_BACKSPACE;
|
||||
case K_S_TAB: // FALLTHROUGH
|
||||
case TAB: return VTERM_KEY_TAB;
|
||||
case Ctrl_M: return VTERM_KEY_ENTER;
|
||||
case ESC: return VTERM_KEY_ESCAPE;
|
||||
|
||||
case K_S_UP: // FALLTHROUGH
|
||||
case K_UP: return VTERM_KEY_UP;
|
||||
case K_S_DOWN: // FALLTHROUGH
|
||||
case K_DOWN: return VTERM_KEY_DOWN;
|
||||
case K_S_LEFT: // FALLTHROUGH
|
||||
case K_C_LEFT: // FALLTHROUGH
|
||||
case K_LEFT: return VTERM_KEY_LEFT;
|
||||
case K_S_RIGHT: // FALLTHROUGH
|
||||
case K_C_RIGHT: // FALLTHROUGH
|
||||
case K_RIGHT: return VTERM_KEY_RIGHT;
|
||||
|
||||
case K_INS: return VTERM_KEY_INS;
|
||||
@ -812,22 +844,22 @@ static VTermKey convert_key(int key, VTermModifier *statep)
|
||||
case K_PAGEUP: return VTERM_KEY_PAGEUP;
|
||||
case K_PAGEDOWN: return VTERM_KEY_PAGEDOWN;
|
||||
|
||||
case K_K0:
|
||||
case K_K0: // FALLTHROUGH
|
||||
case K_KINS: return VTERM_KEY_KP_0;
|
||||
case K_K1:
|
||||
case K_K1: // FALLTHROUGH
|
||||
case K_KEND: return VTERM_KEY_KP_1;
|
||||
case K_K2: return VTERM_KEY_KP_2;
|
||||
case K_K3:
|
||||
case K_K3: // FALLTHROUGH
|
||||
case K_KPAGEDOWN: return VTERM_KEY_KP_3;
|
||||
case K_K4: return VTERM_KEY_KP_4;
|
||||
case K_K5: return VTERM_KEY_KP_5;
|
||||
case K_K6: return VTERM_KEY_KP_6;
|
||||
case K_K7:
|
||||
case K_K7: // FALLTHROUGH
|
||||
case K_KHOME: return VTERM_KEY_KP_7;
|
||||
case K_K8: return VTERM_KEY_KP_8;
|
||||
case K_K9:
|
||||
case K_K9: // FALLTHROUGH
|
||||
case K_KPAGEUP: return VTERM_KEY_KP_9;
|
||||
case K_KDEL:
|
||||
case K_KDEL: // FALLTHROUGH
|
||||
case K_KPOINT: return VTERM_KEY_KP_PERIOD;
|
||||
case K_KENTER: return VTERM_KEY_KP_ENTER;
|
||||
case K_KPLUS: return VTERM_KEY_KP_PLUS;
|
||||
@ -835,6 +867,57 @@ static VTermKey convert_key(int key, VTermModifier *statep)
|
||||
case K_KMULTIPLY: return VTERM_KEY_KP_MULT;
|
||||
case K_KDIVIDE: return VTERM_KEY_KP_DIVIDE;
|
||||
|
||||
case K_S_F1: // FALLTHROUGH
|
||||
case K_F1: return VTERM_KEY_FUNCTION(1);
|
||||
case K_S_F2: // FALLTHROUGH
|
||||
case K_F2: return VTERM_KEY_FUNCTION(2);
|
||||
case K_S_F3: // FALLTHROUGH
|
||||
case K_F3: return VTERM_KEY_FUNCTION(3);
|
||||
case K_S_F4: // FALLTHROUGH
|
||||
case K_F4: return VTERM_KEY_FUNCTION(4);
|
||||
case K_S_F5: // FALLTHROUGH
|
||||
case K_F5: return VTERM_KEY_FUNCTION(5);
|
||||
case K_S_F6: // FALLTHROUGH
|
||||
case K_F6: return VTERM_KEY_FUNCTION(6);
|
||||
case K_S_F7: // FALLTHROUGH
|
||||
case K_F7: return VTERM_KEY_FUNCTION(7);
|
||||
case K_S_F8: // FALLTHROUGH
|
||||
case K_F8: return VTERM_KEY_FUNCTION(8);
|
||||
case K_S_F9: // FALLTHROUGH
|
||||
case K_F9: return VTERM_KEY_FUNCTION(9);
|
||||
case K_S_F10: // FALLTHROUGH
|
||||
case K_F10: return VTERM_KEY_FUNCTION(10);
|
||||
case K_S_F11: // FALLTHROUGH
|
||||
case K_F11: return VTERM_KEY_FUNCTION(11);
|
||||
case K_S_F12: // FALLTHROUGH
|
||||
case K_F12: return VTERM_KEY_FUNCTION(12);
|
||||
|
||||
case K_F13: return VTERM_KEY_FUNCTION(13);
|
||||
case K_F14: return VTERM_KEY_FUNCTION(14);
|
||||
case K_F15: return VTERM_KEY_FUNCTION(15);
|
||||
case K_F16: return VTERM_KEY_FUNCTION(16);
|
||||
case K_F17: return VTERM_KEY_FUNCTION(17);
|
||||
case K_F18: return VTERM_KEY_FUNCTION(18);
|
||||
case K_F19: return VTERM_KEY_FUNCTION(19);
|
||||
case K_F20: return VTERM_KEY_FUNCTION(20);
|
||||
case K_F21: return VTERM_KEY_FUNCTION(21);
|
||||
case K_F22: return VTERM_KEY_FUNCTION(22);
|
||||
case K_F23: return VTERM_KEY_FUNCTION(23);
|
||||
case K_F24: return VTERM_KEY_FUNCTION(24);
|
||||
case K_F25: return VTERM_KEY_FUNCTION(25);
|
||||
case K_F26: return VTERM_KEY_FUNCTION(26);
|
||||
case K_F27: return VTERM_KEY_FUNCTION(27);
|
||||
case K_F28: return VTERM_KEY_FUNCTION(28);
|
||||
case K_F29: return VTERM_KEY_FUNCTION(29);
|
||||
case K_F30: return VTERM_KEY_FUNCTION(30);
|
||||
case K_F31: return VTERM_KEY_FUNCTION(31);
|
||||
case K_F32: return VTERM_KEY_FUNCTION(32);
|
||||
case K_F33: return VTERM_KEY_FUNCTION(33);
|
||||
case K_F34: return VTERM_KEY_FUNCTION(34);
|
||||
case K_F35: return VTERM_KEY_FUNCTION(35);
|
||||
case K_F36: return VTERM_KEY_FUNCTION(36);
|
||||
case K_F37: return VTERM_KEY_FUNCTION(37);
|
||||
|
||||
default: return VTERM_KEY_NONE;
|
||||
}
|
||||
}
|
||||
@ -1176,6 +1259,10 @@ static void redraw(bool restore_cursor)
|
||||
update_screen(0);
|
||||
}
|
||||
|
||||
if (need_maketitle) { // Update title in terminal-mode. #7248
|
||||
maketitle();
|
||||
}
|
||||
|
||||
if (restore_cursor) {
|
||||
ui_cursor_goto(save_row, save_col);
|
||||
} else if (term) {
|
||||
|
@ -58,6 +58,8 @@ NEW_TESTS ?= \
|
||||
test_match.res \
|
||||
test_matchadd_conceal.res \
|
||||
test_matchadd_conceal_utf8.res \
|
||||
test_mksession.res \
|
||||
test_mksession_utf8.res \
|
||||
test_nested_function.res \
|
||||
test_normal.res \
|
||||
test_quickfix.res \
|
||||
|
@ -230,12 +230,41 @@ func Test_paste_in_cmdline()
|
||||
|
||||
call feedkeys("f;:aaa \<C-R>\<C-A> bbb\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"aaa a;b-c*d bbb', @:)
|
||||
|
||||
call feedkeys(":\<C-\>etoupper(getline(1))\<CR>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"ASDF.X /TMP/SOME VERYLONGWORD A;B-C*D ', @:)
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_illegal_address()
|
||||
func Test_remove_char_in_cmdline()
|
||||
call feedkeys(":abc def\<S-Left>\<Del>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abc ef', @:)
|
||||
|
||||
call feedkeys(":abc def\<S-Left>\<BS>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abcdef', @:)
|
||||
|
||||
call feedkeys(":abc def ghi\<S-Left>\<C-W>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abc ghi', @:)
|
||||
|
||||
call feedkeys(":abc def\<S-Left>\<C-U>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"def', @:)
|
||||
endfunc
|
||||
|
||||
func Test_illegal_address1()
|
||||
new
|
||||
2;'(
|
||||
2;')
|
||||
quit
|
||||
endfunc
|
||||
|
||||
func Test_illegal_address2()
|
||||
call writefile(['c', 'x', ' x', '.', '1;y'], 'Xtest.vim')
|
||||
new
|
||||
source Xtest.vim
|
||||
" Trigger calling validate_cursor()
|
||||
diffsp Xtest.vim
|
||||
quit!
|
||||
bwipe!
|
||||
call delete('Xtest.vim')
|
||||
endfunc
|
||||
|
||||
|
@ -212,6 +212,7 @@ func Test_diffoff()
|
||||
call setline(1, ['One', '', 'Two', 'Three'])
|
||||
diffthis
|
||||
redraw
|
||||
call assert_notequal(normattr, screenattr(1, 1))
|
||||
diffoff!
|
||||
redraw
|
||||
call assert_equal(normattr, screenattr(1, 1))
|
||||
@ -219,6 +220,42 @@ func Test_diffoff()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_diffoff_hidden()
|
||||
set diffopt=filler,foldcolumn:0
|
||||
e! one
|
||||
call setline(1, ['Two', 'Three'])
|
||||
let normattr = screenattr(1, 1)
|
||||
diffthis
|
||||
botright vert new two
|
||||
call setline(1, ['One', 'Four'])
|
||||
diffthis
|
||||
redraw
|
||||
call assert_notequal(normattr, screenattr(1, 1))
|
||||
set hidden
|
||||
close
|
||||
redraw
|
||||
" diffing with hidden buffer two
|
||||
call assert_notequal(normattr, screenattr(1, 1))
|
||||
diffoff
|
||||
redraw
|
||||
call assert_equal(normattr, screenattr(1, 1))
|
||||
diffthis
|
||||
redraw
|
||||
" still diffing with hidden buffer two
|
||||
call assert_notequal(normattr, screenattr(1, 1))
|
||||
diffoff!
|
||||
redraw
|
||||
call assert_equal(normattr, screenattr(1, 1))
|
||||
diffthis
|
||||
redraw
|
||||
" no longer diffing with hidden buffer two
|
||||
call assert_equal(normattr, screenattr(1, 1))
|
||||
|
||||
bwipe!
|
||||
bwipe!
|
||||
set hidden& diffopt&
|
||||
endfunc
|
||||
|
||||
func Test_setting_cursor()
|
||||
new Xtest1
|
||||
put =range(1,90)
|
||||
|
@ -89,17 +89,8 @@ func s:doc_config_teardown()
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func s:get_cmd_compl_list(cmd)
|
||||
let list = []
|
||||
let str = ''
|
||||
for cnt in range(1, 999)
|
||||
call feedkeys(a:cmd . repeat("\<Tab>", cnt) . "'\<C-B>let str='\<CR>", 'tx')
|
||||
if str ==# a:cmd[1:]
|
||||
break
|
||||
endif
|
||||
call add(list, str)
|
||||
endfor
|
||||
return list
|
||||
func s:get_help_compl_list(cmd)
|
||||
return getcompletion(a:cmd, 'help')
|
||||
endfunc
|
||||
|
||||
func Test_help_complete()
|
||||
@ -111,49 +102,49 @@ func Test_help_complete()
|
||||
if has('multi_lang')
|
||||
set helplang=
|
||||
endif
|
||||
let list = s:get_cmd_compl_list(":h test")
|
||||
call assert_equal(['h test-col', 'h test-char'], list)
|
||||
let list = s:get_help_compl_list("test")
|
||||
call assert_equal(['test-col', 'test-char'], list)
|
||||
|
||||
if has('multi_lang')
|
||||
" 'helplang=ab' and help file lang is 'en'
|
||||
set helplang=ab
|
||||
let list = s:get_cmd_compl_list(":h test")
|
||||
call assert_equal(['h test-col', 'h test-char'], list)
|
||||
let list = s:get_help_compl_list("test")
|
||||
call assert_equal(['test-col', 'test-char'], list)
|
||||
|
||||
" 'helplang=' and help file lang is 'en' and 'ab'
|
||||
set rtp+=Xdir1/doc-ab
|
||||
set helplang=
|
||||
let list = s:get_cmd_compl_list(":h test")
|
||||
call assert_equal(sort(['h test-col@en', 'h test-col@ab',
|
||||
\ 'h test-char@en', 'h test-char@ab']), sort(list))
|
||||
let list = s:get_help_compl_list("test")
|
||||
call assert_equal(sort(['test-col@en', 'test-col@ab',
|
||||
\ 'test-char@en', 'test-char@ab']), sort(list))
|
||||
|
||||
" 'helplang=ab' and help file lang is 'en' and 'ab'
|
||||
set helplang=ab
|
||||
let list = s:get_cmd_compl_list(":h test")
|
||||
call assert_equal(sort(['h test-col', 'h test-col@en',
|
||||
\ 'h test-char', 'h test-char@en']), sort(list))
|
||||
let list = s:get_help_compl_list("test")
|
||||
call assert_equal(sort(['test-col', 'test-col@en',
|
||||
\ 'test-char', 'test-char@en']), sort(list))
|
||||
|
||||
" 'helplang=' and help file lang is 'en', 'ab' and 'ja'
|
||||
set rtp+=Xdir1/doc-ja
|
||||
set helplang=
|
||||
let list = s:get_cmd_compl_list(":h test")
|
||||
call assert_equal(sort(['h test-col@en', 'h test-col@ab',
|
||||
\ 'h test-col@ja', 'h test-char@en',
|
||||
\ 'h test-char@ab', 'h test-char@ja']), sort(list))
|
||||
let list = s:get_help_compl_list("test")
|
||||
call assert_equal(sort(['test-col@en', 'test-col@ab',
|
||||
\ 'test-col@ja', 'test-char@en',
|
||||
\ 'test-char@ab', 'test-char@ja']), sort(list))
|
||||
|
||||
" 'helplang=ab' and help file lang is 'en', 'ab' and 'ja'
|
||||
set helplang=ab
|
||||
let list = s:get_cmd_compl_list(":h test")
|
||||
call assert_equal(sort(['h test-col', 'h test-col@en',
|
||||
\ 'h test-col@ja', 'h test-char',
|
||||
\ 'h test-char@en', 'h test-char@ja']), sort(list))
|
||||
let list = s:get_help_compl_list("test")
|
||||
call assert_equal(sort(['test-col', 'test-col@en',
|
||||
\ 'test-col@ja', 'test-char',
|
||||
\ 'test-char@en', 'test-char@ja']), sort(list))
|
||||
|
||||
" 'helplang=ab,ja' and help file lang is 'en', 'ab' and 'ja'
|
||||
set helplang=ab,ja
|
||||
let list = s:get_cmd_compl_list(":h test")
|
||||
call assert_equal(sort(['h test-col', 'h test-col@ja',
|
||||
\ 'h test-col@en', 'h test-char',
|
||||
\ 'h test-char@ja', 'h test-char@en']), sort(list))
|
||||
let list = s:get_help_compl_list("test")
|
||||
call assert_equal(sort(['test-col', 'test-col@ja',
|
||||
\ 'test-col@en', 'test-char',
|
||||
\ 'test-char@ja', 'test-char@en']), sort(list))
|
||||
endif
|
||||
catch
|
||||
call assert_exception('X')
|
||||
|
155
src/nvim/testdir/test_mksession.vim
Normal file
155
src/nvim/testdir/test_mksession.vim
Normal file
@ -0,0 +1,155 @@
|
||||
" Test for :mksession, :mkview and :loadview in latin1 encoding
|
||||
|
||||
scriptencoding latin1
|
||||
|
||||
if !has('multi_byte') || !has('mksession')
|
||||
finish
|
||||
endif
|
||||
|
||||
func Test_mksession()
|
||||
tabnew
|
||||
let wrap_save = &wrap
|
||||
set sessionoptions=buffers splitbelow fileencoding=latin1
|
||||
call setline(1, [
|
||||
\ 'start:',
|
||||
\ 'no multibyte chAracter',
|
||||
\ ' one leaDing tab',
|
||||
\ ' four leadinG spaces',
|
||||
\ 'two consecutive tabs',
|
||||
\ 'two tabs in one line',
|
||||
\ 'one ä multibyteCharacter',
|
||||
\ 'aä Ä two multiByte characters',
|
||||
\ 'Aäöü three mulTibyte characters'
|
||||
\ ])
|
||||
let tmpfile = 'Xtemp'
|
||||
exec 'w! ' . tmpfile
|
||||
/^start:
|
||||
set wrap
|
||||
vsplit
|
||||
norm! j16|
|
||||
split
|
||||
norm! j16|
|
||||
split
|
||||
norm! j16|
|
||||
split
|
||||
norm! j8|
|
||||
split
|
||||
norm! j8|
|
||||
split
|
||||
norm! j16|
|
||||
split
|
||||
norm! j16|
|
||||
split
|
||||
norm! j16|
|
||||
wincmd l
|
||||
|
||||
set nowrap
|
||||
/^start:
|
||||
norm! j16|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
norm! j08|3zl
|
||||
split
|
||||
norm! j08|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
call wincol()
|
||||
mksession! Xtest_mks.out
|
||||
let li = filter(readfile('Xtest_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"')
|
||||
let expected = [
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 08|',
|
||||
\ 'normal! 08|',
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 016|',
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
|
||||
\ " normal! 08|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
|
||||
\ " normal! 08|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|"
|
||||
\ ]
|
||||
call assert_equal(expected, li)
|
||||
tabclose!
|
||||
|
||||
call delete('Xtest_mks.out')
|
||||
call delete(tmpfile)
|
||||
let &wrap = wrap_save
|
||||
endfunc
|
||||
|
||||
func Test_mksession_winheight()
|
||||
new
|
||||
set winheight=10 winminheight=2
|
||||
mksession! Xtest_mks.out
|
||||
source Xtest_mks.out
|
||||
|
||||
call delete('Xtest_mks.out')
|
||||
endfunc
|
||||
|
||||
" Verify that arglist is stored correctly to the session file.
|
||||
func Test_mksession_arglist()
|
||||
argdel *
|
||||
next file1 file2 file3 file4
|
||||
mksession! Xtest_mks.out
|
||||
source Xtest_mks.out
|
||||
call assert_equal(['file1', 'file2', 'file3', 'file4'], argv())
|
||||
|
||||
call delete('Xtest_mks.out')
|
||||
argdel *
|
||||
endfunc
|
||||
|
||||
|
||||
func Test_mksession_one_buffer_two_windows()
|
||||
edit Xtest1
|
||||
new Xtest2
|
||||
split
|
||||
mksession! Xtest_mks.out
|
||||
let lines = readfile('Xtest_mks.out')
|
||||
let count1 = 0
|
||||
let count2 = 0
|
||||
let count2buf = 0
|
||||
for line in lines
|
||||
if line =~ 'edit \f*Xtest1$'
|
||||
let count1 += 1
|
||||
endif
|
||||
if line =~ 'edit \f\{-}Xtest2'
|
||||
let count2 += 1
|
||||
endif
|
||||
if line =~ 'buffer \f\{-}Xtest2'
|
||||
let count2buf += 1
|
||||
endif
|
||||
endfor
|
||||
call assert_equal(1, count1, 'Xtest1 count')
|
||||
call assert_equal(2, count2, 'Xtest2 count')
|
||||
call assert_equal(2, count2buf, 'Xtest2 buffer count')
|
||||
|
||||
close
|
||||
bwipe!
|
||||
call delete('Xtest_mks.out')
|
||||
endfunc
|
||||
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
104
src/nvim/testdir/test_mksession_utf8.vim
Normal file
104
src/nvim/testdir/test_mksession_utf8.vim
Normal file
@ -0,0 +1,104 @@
|
||||
" Test for :mksession, :mkview and :loadview in utf-8 encoding
|
||||
|
||||
set encoding=utf-8
|
||||
scriptencoding utf-8
|
||||
|
||||
if !has('multi_byte') || !has('mksession')
|
||||
finish
|
||||
endif
|
||||
|
||||
func Test_mksession_utf8()
|
||||
tabnew
|
||||
let wrap_save = &wrap
|
||||
set sessionoptions=buffers splitbelow fileencoding=utf-8
|
||||
call setline(1, [
|
||||
\ 'start:',
|
||||
\ 'no multibyte chAracter',
|
||||
\ ' one leaDing tab',
|
||||
\ ' four leadinG spaces',
|
||||
\ 'two consecutive tabs',
|
||||
\ 'two tabs in one line',
|
||||
\ 'one … multibyteCharacter',
|
||||
\ 'a “b” two multiByte characters',
|
||||
\ '“c”1€ three mulTibyte characters'
|
||||
\ ])
|
||||
let tmpfile = tempname()
|
||||
exec 'w! ' . tmpfile
|
||||
/^start:
|
||||
set wrap
|
||||
vsplit
|
||||
norm! j16|
|
||||
split
|
||||
norm! j16|
|
||||
split
|
||||
norm! j16|
|
||||
split
|
||||
norm! j8|
|
||||
split
|
||||
norm! j8|
|
||||
split
|
||||
norm! j16|
|
||||
split
|
||||
norm! j16|
|
||||
split
|
||||
norm! j16|
|
||||
wincmd l
|
||||
|
||||
set nowrap
|
||||
/^start:
|
||||
norm! j16|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
norm! j08|3zl
|
||||
split
|
||||
norm! j08|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
norm! j016|3zl
|
||||
split
|
||||
call wincol()
|
||||
mksession! test_mks.out
|
||||
let li = filter(readfile('test_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"')
|
||||
let expected = [
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 08|',
|
||||
\ 'normal! 08|',
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 016|',
|
||||
\ 'normal! 016|',
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
|
||||
\ " normal! 08|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
|
||||
\ " normal! 08|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|",
|
||||
\ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
|
||||
\ " normal! 016|"
|
||||
\ ]
|
||||
call assert_equal(expected, li)
|
||||
tabclose!
|
||||
|
||||
call delete('test_mks.out')
|
||||
call delete(tmpfile)
|
||||
let &wrap = wrap_save
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
@ -13,6 +13,12 @@ function! Test_whichwrap()
|
||||
set whichwrap+=h,l
|
||||
call assert_equal('b,s,h,l', &whichwrap)
|
||||
|
||||
set whichwrap=h,h
|
||||
call assert_equal('h', &whichwrap)
|
||||
|
||||
set whichwrap=h,h,h
|
||||
call assert_equal('h', &whichwrap)
|
||||
|
||||
set whichwrap&
|
||||
endfunction
|
||||
|
||||
@ -97,3 +103,13 @@ func Test_keymap_valid()
|
||||
call assert_fails(":set kmp=trunc\x00name", "E544:")
|
||||
call assert_fails(":set kmp=trunc\x00name", "trunc")
|
||||
endfunc
|
||||
|
||||
func Test_complete()
|
||||
" Trailing single backslash used to cause invalid memory access.
|
||||
set complete=s\
|
||||
new
|
||||
call feedkeys("i\<C-N>\<Esc>", 'xt')
|
||||
bwipe!
|
||||
set complete&
|
||||
endfun
|
||||
|
||||
|
@ -7,10 +7,10 @@ func! ListMonths()
|
||||
if g:setting != ''
|
||||
exe ":set" g:setting
|
||||
endif
|
||||
let mth=copy(g:months)
|
||||
let mth = copy(g:months)
|
||||
let entered = strcharpart(getline('.'),0,col('.'))
|
||||
if !empty(entered)
|
||||
let mth=filter(mth, 'v:val=~"^".entered')
|
||||
let mth = filter(mth, 'v:val=~"^".entered')
|
||||
endif
|
||||
call complete(1, mth)
|
||||
return ''
|
||||
@ -468,7 +468,7 @@ endfunc
|
||||
" auto-wrap text.
|
||||
func Test_completion_ctrl_e_without_autowrap()
|
||||
new
|
||||
let tw_save=&tw
|
||||
let tw_save = &tw
|
||||
set tw=78
|
||||
let li = [
|
||||
\ '" zzz',
|
||||
@ -478,7 +478,7 @@ func Test_completion_ctrl_e_without_autowrap()
|
||||
call feedkeys("A\<C-X>\<C-N>\<C-E>\<Esc>", "tx")
|
||||
call assert_equal(li, getline(1, '$'))
|
||||
|
||||
let &tw=tw_save
|
||||
let &tw = tw_save
|
||||
q!
|
||||
endfunc
|
||||
|
||||
@ -541,4 +541,33 @@ func Test_completion_comment_formatting()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
function! DummyCompleteSix()
|
||||
call complete(1, ['Hello', 'World'])
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" complete() correctly clears the list of autocomplete candidates
|
||||
func Test_completion_clear_candidate_list()
|
||||
new
|
||||
%d
|
||||
" select first entry from the completion popup
|
||||
call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>", "tx")
|
||||
call assert_equal('Hello', getline(1))
|
||||
%d
|
||||
" select second entry from the completion popup
|
||||
call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>", "tx")
|
||||
call assert_equal('World', getline(1))
|
||||
%d
|
||||
" select original text
|
||||
call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>", "tx")
|
||||
call assert_equal(' xxx', getline(1))
|
||||
%d
|
||||
" back at first entry from completion list
|
||||
call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>\<C-N>", "tx")
|
||||
call assert_equal('Hello', getline(1))
|
||||
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -24,28 +24,34 @@ func Test_after_comes_later()
|
||||
\ 'set guioptions+=M',
|
||||
\ 'let $HOME = "/does/not/exist"',
|
||||
\ 'set loadplugins',
|
||||
\ 'set rtp=Xhere,Xafter',
|
||||
\ 'set rtp=Xhere,Xafter,Xanother',
|
||||
\ 'set packpath=Xhere,Xafter',
|
||||
\ 'set nomore',
|
||||
\ 'let g:sequence = ""',
|
||||
\ ]
|
||||
let after = [
|
||||
\ 'redir! > Xtestout',
|
||||
\ 'scriptnames',
|
||||
\ 'redir END',
|
||||
\ 'redir! > Xsequence',
|
||||
\ 'echo g:sequence',
|
||||
\ 'redir END',
|
||||
\ 'quit',
|
||||
\ ]
|
||||
call mkdir('Xhere/plugin', 'p')
|
||||
call writefile(['let done = 1'], 'Xhere/plugin/here.vim')
|
||||
call writefile(['let g:sequence .= "here "'], 'Xhere/plugin/here.vim')
|
||||
call mkdir('Xanother/plugin', 'p')
|
||||
call writefile(['let g:sequence .= "another "'], 'Xanother/plugin/another.vim')
|
||||
call mkdir('Xhere/pack/foo/start/foobar/plugin', 'p')
|
||||
call writefile(['let done = 1'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
|
||||
call writefile(['let g:sequence .= "pack "'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
|
||||
|
||||
call mkdir('Xafter/plugin', 'p')
|
||||
call writefile(['let done = 1'], 'Xafter/plugin/later.vim')
|
||||
call writefile(['let g:sequence .= "after "'], 'Xafter/plugin/later.vim')
|
||||
|
||||
if RunVim(before, after, '')
|
||||
|
||||
let lines = readfile('Xtestout')
|
||||
let expected = ['Xbefore.vim', 'here.vim', 'foo.vim', 'later.vim', 'Xafter.vim']
|
||||
let expected = ['Xbefore.vim', 'here.vim', 'another.vim', 'foo.vim', 'later.vim', 'Xafter.vim']
|
||||
let found = []
|
||||
for line in lines
|
||||
for one in expected
|
||||
@ -57,9 +63,45 @@ func Test_after_comes_later()
|
||||
call assert_equal(expected, found)
|
||||
endif
|
||||
|
||||
call assert_equal('here another pack after', substitute(join(readfile('Xsequence', 1), ''), '\s\+$', '', ''))
|
||||
|
||||
call delete('Xtestout')
|
||||
call delete('Xsequence')
|
||||
call delete('Xhere', 'rf')
|
||||
call delete('Xanother', 'rf')
|
||||
call delete('Xafter', 'rf')
|
||||
endfunc
|
||||
|
||||
func Test_pack_in_rtp_when_plugins_run()
|
||||
if !has('packages')
|
||||
return
|
||||
endif
|
||||
let before = [
|
||||
\ 'set nocp viminfo+=nviminfo',
|
||||
\ 'set guioptions+=M',
|
||||
\ 'let $HOME = "/does/not/exist"',
|
||||
\ 'set loadplugins',
|
||||
\ 'set rtp=Xhere',
|
||||
\ 'set packpath=Xhere',
|
||||
\ 'set nomore',
|
||||
\ ]
|
||||
let after = [
|
||||
\ 'quit',
|
||||
\ ]
|
||||
call mkdir('Xhere/plugin', 'p')
|
||||
call writefile(['redir! > Xtestout', 'silent set runtimepath?', 'silent! call foo#Trigger()', 'redir END'], 'Xhere/plugin/here.vim')
|
||||
call mkdir('Xhere/pack/foo/start/foobar/autoload', 'p')
|
||||
call writefile(['function! foo#Trigger()', 'echo "autoloaded foo"', 'endfunction'], 'Xhere/pack/foo/start/foobar/autoload/foo.vim')
|
||||
|
||||
if RunVim(before, after, '')
|
||||
|
||||
let lines = filter(readfile('Xtestout'), '!empty(v:val)')
|
||||
call assert_match('Xhere[/\\]pack[/\\]foo[/\\]start[/\\]foobar', get(lines, 0))
|
||||
call assert_match('autoloaded foo', get(lines, 1))
|
||||
endif
|
||||
|
||||
call delete('Xtestout')
|
||||
call delete('Xhere', 'rf')
|
||||
call delete('Xafter', 'rf')
|
||||
endfunc
|
||||
|
||||
func Test_help_arg()
|
||||
@ -76,11 +118,11 @@ func Test_help_arg()
|
||||
let found = []
|
||||
for line in lines
|
||||
if line =~ '-R.*Read-only mode'
|
||||
call add(found, 'Readonly mode')
|
||||
call add(found, 'Readonly mode')
|
||||
endif
|
||||
" Watch out for a second --version line in the Gnome version.
|
||||
if line =~ '--version.*Print version information and exit'
|
||||
call add(found, "--version")
|
||||
if line =~ '--version.*Print version information'
|
||||
call add(found, "--version")
|
||||
endif
|
||||
endfor
|
||||
call assert_equal(['Readonly mode', '--version'], found)
|
||||
|
@ -50,7 +50,7 @@ func Test_syn_iskeyword()
|
||||
setlocal isk-=_
|
||||
call assert_equal('DLTD_BY', GetSyntaxItem('DLTD'))
|
||||
/\<D\k\+\>/:norm! ygn
|
||||
let b2=@0
|
||||
let b2 = @0
|
||||
call assert_equal('DLTD', @0)
|
||||
|
||||
syn iskeyword clear
|
||||
@ -76,3 +76,85 @@ func Test_syntax_after_reload()
|
||||
call assert_true(exists('g:gotit'))
|
||||
call delete('Xsomefile')
|
||||
endfunc
|
||||
|
||||
func Test_syntime()
|
||||
if !has('profile')
|
||||
return
|
||||
endif
|
||||
|
||||
syntax on
|
||||
syntime on
|
||||
let a = execute('syntime report')
|
||||
call assert_equal("\nNo Syntax items defined for this buffer", a)
|
||||
|
||||
view ../memfile_test.c
|
||||
setfiletype cpp
|
||||
redraw
|
||||
let a = execute('syntime report')
|
||||
call assert_match('^ TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a)
|
||||
call assert_match(' \d*\.\d* \+[^0]\d* .* cppRawString ', a)
|
||||
call assert_match(' \d*\.\d* \+[^0]\d* .* cppNumber ', a)
|
||||
|
||||
syntime off
|
||||
syntime clear
|
||||
let a = execute('syntime report')
|
||||
call assert_match('^ TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a)
|
||||
call assert_notmatch('.* cppRawString *', a)
|
||||
call assert_notmatch('.* cppNumber*', a)
|
||||
call assert_notmatch('[1-9]', a)
|
||||
|
||||
call assert_fails('syntime abc', 'E475')
|
||||
|
||||
syntax clear
|
||||
let a = execute('syntime report')
|
||||
call assert_equal("\nNo Syntax items defined for this buffer", a)
|
||||
|
||||
bd
|
||||
endfunc
|
||||
|
||||
func Test_syntax_list()
|
||||
syntax on
|
||||
let a = execute('syntax list')
|
||||
call assert_equal("\nNo Syntax items defined for this buffer", a)
|
||||
|
||||
view ../memfile_test.c
|
||||
setfiletype c
|
||||
|
||||
let a = execute('syntax list')
|
||||
call assert_match('cInclude*', a)
|
||||
call assert_match('cDefine', a)
|
||||
|
||||
let a = execute('syntax list cDefine')
|
||||
call assert_notmatch('cInclude*', a)
|
||||
call assert_match('cDefine', a)
|
||||
call assert_match(' links to Macro$', a)
|
||||
|
||||
call assert_fails('syntax list ABCD', 'E28:')
|
||||
call assert_fails('syntax list @ABCD', 'E392:')
|
||||
|
||||
syntax clear
|
||||
let a = execute('syntax list')
|
||||
call assert_equal("\nNo Syntax items defined for this buffer", a)
|
||||
|
||||
bd
|
||||
endfunc
|
||||
|
||||
func Test_syntax_completion()
|
||||
call feedkeys(":syn \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"syn case clear cluster conceal enable include iskeyword keyword list manual match off on region reset spell sync', @:)
|
||||
|
||||
call feedkeys(":syn case \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"syn case ignore match', @:)
|
||||
|
||||
call feedkeys(":syn spell \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"syn spell default notoplevel toplevel', @:)
|
||||
|
||||
call feedkeys(":syn sync \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"syn sync ccomment clear fromstart linebreaks= linecont lines= match maxlines= minlines= region', @:)
|
||||
|
||||
call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_match('^"syn list Boolean Character ', @:)
|
||||
|
||||
call feedkeys(":syn match \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_match('^"syn match Boolean Character ', @:)
|
||||
endfunc
|
@ -15,3 +15,23 @@ func Test_block_shift_multibyte()
|
||||
call assert_equal(' ヹxxx', getline(2))
|
||||
q!
|
||||
endfunc
|
||||
|
||||
func Test_Visual_ctrl_o()
|
||||
new
|
||||
call setline(1, ['one', 'two', 'three'])
|
||||
call cursor(1,2)
|
||||
set noshowmode
|
||||
set tw=0
|
||||
call feedkeys("\<c-v>jjlIa\<c-\>\<c-o>:set tw=88\<cr>\<esc>", 'tx')
|
||||
call assert_equal(['oane', 'tawo', 'tahree'], getline(1, 3))
|
||||
call assert_equal(88, &tw)
|
||||
set tw&
|
||||
bw!
|
||||
endfu
|
||||
|
||||
func Test_Visual_vapo()
|
||||
new
|
||||
normal oxx
|
||||
normal vapo
|
||||
bwipe!
|
||||
endfunc
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/ascii.h"
|
||||
#include "nvim/main.h"
|
||||
#include "nvim/aucmd.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/input.h"
|
||||
#include "nvim/event/rstream.h"
|
||||
@ -280,9 +281,9 @@ static void timer_cb(TimeWatcher *watcher, void *data)
|
||||
|
||||
/// Handle focus events.
|
||||
///
|
||||
/// If the upcoming sequence of bytes in the input stream matches either the
|
||||
/// escape code for focus gained `<ESC>[I` or focus lost `<ESC>[O` then consume
|
||||
/// that sequence and push the appropriate event into the input queue
|
||||
/// If the upcoming sequence of bytes in the input stream matches the termcode
|
||||
/// for "focus gained" or "focus lost", consume that sequence and schedule an
|
||||
/// event on the main loop.
|
||||
///
|
||||
/// @param input the input stream
|
||||
/// @return true iff handle_focus_event consumed some input
|
||||
@ -294,11 +295,7 @@ static bool handle_focus_event(TermInput *input)
|
||||
// Advance past the sequence
|
||||
bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I';
|
||||
rbuffer_consumed(input->read_stream.buffer, 3);
|
||||
if (focus_gained) {
|
||||
enqueue_input(input, FOCUSGAINED_KEY, sizeof(FOCUSGAINED_KEY) - 1);
|
||||
} else {
|
||||
enqueue_input(input, FOCUSLOST_KEY, sizeof(FOCUSLOST_KEY) - 1);
|
||||
}
|
||||
aucmd_schedule_focusgained(focus_gained);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -104,7 +104,9 @@ unibi_term *load_builtin_terminfo(const char * term)
|
||||
return unibi_from_mem((const char *)interix_8colour_terminfo,
|
||||
sizeof interix_8colour_terminfo);
|
||||
} else if (terminfo_is_term_family(term, "iterm")
|
||||
|| terminfo_is_term_family(term, "iTerm.app")) {
|
||||
|| terminfo_is_term_family(term, "iterm2")
|
||||
|| terminfo_is_term_family(term, "iTerm.app")
|
||||
|| terminfo_is_term_family(term, "iTerm2.app")) {
|
||||
return unibi_from_mem((const char *)iterm_256colour_terminfo,
|
||||
sizeof iterm_256colour_terminfo);
|
||||
} else if (terminfo_is_term_family(term, "st")) {
|
||||
|
@ -52,6 +52,15 @@
|
||||
#define LINUXSET0C "\x1b[?0c"
|
||||
#define LINUXSET1C "\x1b[?1c"
|
||||
|
||||
#ifdef NVIM_UNIBI_HAS_VAR_FROM
|
||||
#define UNIBI_SET_NUM_VAR(var, num) \
|
||||
do { \
|
||||
(var) = unibi_var_from_num((num)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define UNIBI_SET_NUM_VAR(var, num) (var).i = (num);
|
||||
#endif
|
||||
|
||||
// Per the commentary in terminfo, only a minus sign is a true suffix
|
||||
// separator.
|
||||
bool terminfo_is_term_family(const char *term, const char *family)
|
||||
@ -234,9 +243,9 @@ static void terminfo_start(UI *ui)
|
||||
unibi_out(ui, unibi_keypad_xmit);
|
||||
unibi_out(ui, unibi_clear_screen);
|
||||
// Enable bracketed paste
|
||||
unibi_out(ui, data->unibi_ext.enable_bracketed_paste);
|
||||
unibi_out_ext(ui, data->unibi_ext.enable_bracketed_paste);
|
||||
// Enable focus reporting
|
||||
unibi_out(ui, data->unibi_ext.enable_focus_reporting);
|
||||
unibi_out_ext(ui, data->unibi_ext.enable_focus_reporting);
|
||||
uv_loop_init(&data->write_loop);
|
||||
if (data->out_isatty) {
|
||||
uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0);
|
||||
@ -263,9 +272,9 @@ static void terminfo_stop(UI *ui)
|
||||
unibi_out(ui, unibi_keypad_local);
|
||||
unibi_out(ui, unibi_exit_ca_mode);
|
||||
// Disable bracketed paste
|
||||
unibi_out(ui, data->unibi_ext.disable_bracketed_paste);
|
||||
unibi_out_ext(ui, data->unibi_ext.disable_bracketed_paste);
|
||||
// Disable focus reporting
|
||||
unibi_out(ui, data->unibi_ext.disable_focus_reporting);
|
||||
unibi_out_ext(ui, data->unibi_ext.disable_focus_reporting);
|
||||
flush_buf(ui, true);
|
||||
uv_tty_reset_mode();
|
||||
uv_close((uv_handle_t *)&data->output_handle, NULL);
|
||||
@ -279,7 +288,7 @@ static void terminfo_stop(UI *ui)
|
||||
static void tui_terminal_start(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
data->print_attrs = EMPTY_ATTRS;
|
||||
data->print_attrs = HLATTRS_INIT;
|
||||
ugrid_init(&data->grid);
|
||||
terminfo_start(ui);
|
||||
update_size(ui);
|
||||
@ -391,15 +400,15 @@ static void update_attrs(UI *ui, HlAttrs attrs)
|
||||
|
||||
if (unibi_get_str(data->ut, unibi_set_attributes)) {
|
||||
if (attrs.bold || attrs.reverse || attrs.underline || attrs.undercurl) {
|
||||
data->params[0].i = 0; // standout
|
||||
data->params[1].i = attrs.underline || attrs.undercurl;
|
||||
data->params[2].i = attrs.reverse;
|
||||
data->params[3].i = 0; // blink
|
||||
data->params[4].i = 0; // dim
|
||||
data->params[5].i = attrs.bold;
|
||||
data->params[6].i = 0; // blank
|
||||
data->params[7].i = 0; // protect
|
||||
data->params[8].i = 0; // alternate character set
|
||||
UNIBI_SET_NUM_VAR(data->params[0], 0); // standout
|
||||
UNIBI_SET_NUM_VAR(data->params[1], attrs.underline || attrs.undercurl);
|
||||
UNIBI_SET_NUM_VAR(data->params[2], attrs.reverse);
|
||||
UNIBI_SET_NUM_VAR(data->params[3], 0); // blink
|
||||
UNIBI_SET_NUM_VAR(data->params[4], 0); // dim
|
||||
UNIBI_SET_NUM_VAR(data->params[5], attrs.bold);
|
||||
UNIBI_SET_NUM_VAR(data->params[6], 0); // blank
|
||||
UNIBI_SET_NUM_VAR(data->params[7], 0); // protect
|
||||
UNIBI_SET_NUM_VAR(data->params[8], 0); // alternate character set
|
||||
unibi_out(ui, unibi_set_attributes);
|
||||
} else if (!data->default_attr) {
|
||||
unibi_out(ui, unibi_exit_attribute_mode);
|
||||
@ -423,26 +432,26 @@ static void update_attrs(UI *ui, HlAttrs attrs)
|
||||
}
|
||||
if (ui->rgb) {
|
||||
if (fg != -1) {
|
||||
data->params[0].i = (fg >> 16) & 0xff; // red
|
||||
data->params[1].i = (fg >> 8) & 0xff; // green
|
||||
data->params[2].i = fg & 0xff; // blue
|
||||
unibi_out(ui, data->unibi_ext.set_rgb_foreground);
|
||||
UNIBI_SET_NUM_VAR(data->params[0], (fg >> 16) & 0xff); // red
|
||||
UNIBI_SET_NUM_VAR(data->params[1], (fg >> 8) & 0xff); // green
|
||||
UNIBI_SET_NUM_VAR(data->params[2], fg & 0xff); // blue
|
||||
unibi_out_ext(ui, data->unibi_ext.set_rgb_foreground);
|
||||
}
|
||||
|
||||
if (bg != -1) {
|
||||
data->params[0].i = (bg >> 16) & 0xff; // red
|
||||
data->params[1].i = (bg >> 8) & 0xff; // green
|
||||
data->params[2].i = bg & 0xff; // blue
|
||||
unibi_out(ui, data->unibi_ext.set_rgb_background);
|
||||
UNIBI_SET_NUM_VAR(data->params[0], (bg >> 16) & 0xff); // red
|
||||
UNIBI_SET_NUM_VAR(data->params[1], (bg >> 8) & 0xff); // green
|
||||
UNIBI_SET_NUM_VAR(data->params[2], bg & 0xff); // blue
|
||||
unibi_out_ext(ui, data->unibi_ext.set_rgb_background);
|
||||
}
|
||||
} else {
|
||||
if (fg != -1) {
|
||||
data->params[0].i = fg;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], fg);
|
||||
unibi_out(ui, unibi_set_a_foreground);
|
||||
}
|
||||
|
||||
if (bg != -1) {
|
||||
data->params[0].i = bg;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], bg);
|
||||
unibi_out(ui, unibi_set_a_background);
|
||||
}
|
||||
}
|
||||
@ -558,7 +567,7 @@ static void cursor_goto(UI *ui, int row, int col)
|
||||
unibi_out(ui, unibi_cursor_left);
|
||||
}
|
||||
} else {
|
||||
data->params[0].i = n;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], n);
|
||||
unibi_out(ui, unibi_parm_left_cursor);
|
||||
}
|
||||
ugrid_goto(grid, row, col);
|
||||
@ -570,7 +579,7 @@ static void cursor_goto(UI *ui, int row, int col)
|
||||
unibi_out(ui, unibi_cursor_right);
|
||||
}
|
||||
} else {
|
||||
data->params[0].i = n;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], n);
|
||||
unibi_out(ui, unibi_parm_right_cursor);
|
||||
}
|
||||
ugrid_goto(grid, row, col);
|
||||
@ -585,7 +594,7 @@ static void cursor_goto(UI *ui, int row, int col)
|
||||
unibi_out(ui, unibi_cursor_down);
|
||||
}
|
||||
} else {
|
||||
data->params[0].i = n;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], n);
|
||||
unibi_out(ui, unibi_parm_down_cursor);
|
||||
}
|
||||
ugrid_goto(grid, row, col);
|
||||
@ -597,7 +606,7 @@ static void cursor_goto(UI *ui, int row, int col)
|
||||
unibi_out(ui, unibi_cursor_up);
|
||||
}
|
||||
} else {
|
||||
data->params[0].i = n;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], n);
|
||||
unibi_out(ui, unibi_parm_up_cursor);
|
||||
}
|
||||
ugrid_goto(grid, row, col);
|
||||
@ -619,7 +628,7 @@ static void clear_region(UI *ui, int top, int bot, int left, int right)
|
||||
if (grid->bg == -1 && right == ui->width -1) {
|
||||
// Background is set to the default color and the right edge matches the
|
||||
// screen end, try to use terminal codes for clearing the requested area.
|
||||
HlAttrs clear_attrs = EMPTY_ATTRS;
|
||||
HlAttrs clear_attrs = HLATTRS_INIT;
|
||||
clear_attrs.foreground = grid->fg;
|
||||
clear_attrs.background = grid->bg;
|
||||
update_attrs(ui, clear_attrs);
|
||||
@ -675,19 +684,19 @@ static void set_scroll_region(UI *ui)
|
||||
TUIData *data = ui->data;
|
||||
UGrid *grid = &data->grid;
|
||||
|
||||
data->params[0].i = grid->top;
|
||||
data->params[1].i = grid->bot;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], grid->top);
|
||||
UNIBI_SET_NUM_VAR(data->params[1], grid->bot);
|
||||
unibi_out(ui, unibi_change_scroll_region);
|
||||
if (grid->left != 0 || grid->right != ui->width - 1) {
|
||||
unibi_out(ui, data->unibi_ext.enable_lr_margin);
|
||||
unibi_out_ext(ui, data->unibi_ext.enable_lr_margin);
|
||||
if (data->can_set_lr_margin) {
|
||||
data->params[0].i = grid->left;
|
||||
data->params[1].i = grid->right;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], grid->left);
|
||||
UNIBI_SET_NUM_VAR(data->params[1], grid->right);
|
||||
unibi_out(ui, unibi_set_lr_margin);
|
||||
} else {
|
||||
data->params[0].i = grid->left;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], grid->left);
|
||||
unibi_out(ui, unibi_set_left_margin_parm);
|
||||
data->params[0].i = grid->right;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], grid->right);
|
||||
unibi_out(ui, unibi_set_right_margin_parm);
|
||||
}
|
||||
}
|
||||
@ -700,24 +709,24 @@ static void reset_scroll_region(UI *ui)
|
||||
UGrid *grid = &data->grid;
|
||||
|
||||
if (0 <= data->unibi_ext.reset_scroll_region) {
|
||||
unibi_out(ui, data->unibi_ext.reset_scroll_region);
|
||||
unibi_out_ext(ui, data->unibi_ext.reset_scroll_region);
|
||||
} else {
|
||||
data->params[0].i = 0;
|
||||
data->params[1].i = ui->height - 1;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], 0);
|
||||
UNIBI_SET_NUM_VAR(data->params[1], ui->height - 1);
|
||||
unibi_out(ui, unibi_change_scroll_region);
|
||||
}
|
||||
if (grid->left != 0 || grid->right != ui->width - 1) {
|
||||
if (data->can_set_lr_margin) {
|
||||
data->params[0].i = 0;
|
||||
data->params[1].i = ui->width - 1;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], 0);
|
||||
UNIBI_SET_NUM_VAR(data->params[1], ui->width - 1);
|
||||
unibi_out(ui, unibi_set_lr_margin);
|
||||
} else {
|
||||
data->params[0].i = 0;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], 0);
|
||||
unibi_out(ui, unibi_set_left_margin_parm);
|
||||
data->params[0].i = ui->width - 1;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], ui->width - 1);
|
||||
unibi_out(ui, unibi_set_right_margin_parm);
|
||||
}
|
||||
unibi_out(ui, data->unibi_ext.disable_lr_margin);
|
||||
unibi_out_ext(ui, data->unibi_ext.disable_lr_margin);
|
||||
}
|
||||
unibi_goto(ui, grid->row, grid->col);
|
||||
}
|
||||
@ -728,9 +737,9 @@ static void tui_resize(UI *ui, Integer width, Integer height)
|
||||
ugrid_resize(&data->grid, (int)width, (int)height);
|
||||
|
||||
if (!got_winch) { // Try to resize the terminal window.
|
||||
data->params[0].i = (int)height;
|
||||
data->params[1].i = (int)width;
|
||||
unibi_out(ui, data->unibi_ext.resize_screen);
|
||||
UNIBI_SET_NUM_VAR(data->params[0], (int)height);
|
||||
UNIBI_SET_NUM_VAR(data->params[1], (int)width);
|
||||
unibi_out_ext(ui, data->unibi_ext.resize_screen);
|
||||
// DECSLPP does not reset the scroll region.
|
||||
if (data->scroll_region_is_full_screen) {
|
||||
reset_scroll_region(ui);
|
||||
@ -836,7 +845,7 @@ static void tui_mouse_on(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
if (!data->mouse_enabled) {
|
||||
unibi_out(ui, data->unibi_ext.enable_mouse);
|
||||
unibi_out_ext(ui, data->unibi_ext.enable_mouse);
|
||||
data->mouse_enabled = true;
|
||||
}
|
||||
}
|
||||
@ -845,7 +854,7 @@ static void tui_mouse_off(UI *ui)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
if (data->mouse_enabled) {
|
||||
unibi_out(ui, data->unibi_ext.disable_mouse);
|
||||
unibi_out_ext(ui, data->unibi_ext.disable_mouse);
|
||||
data->mouse_enabled = false;
|
||||
}
|
||||
}
|
||||
@ -863,8 +872,8 @@ static void tui_set_mode(UI *ui, ModeShape mode)
|
||||
int attr = syn_id2attr(c.id);
|
||||
if (attr > 0) {
|
||||
attrentry_T *aep = syn_cterm_attr2entry(attr);
|
||||
data->params[0].i = aep->rgb_bg_color;
|
||||
unibi_out(ui, data->unibi_ext.set_cursor_color);
|
||||
UNIBI_SET_NUM_VAR(data->params[0], aep->rgb_bg_color);
|
||||
unibi_out_ext(ui, data->unibi_ext.set_cursor_color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -874,8 +883,8 @@ static void tui_set_mode(UI *ui, ModeShape mode)
|
||||
case SHAPE_VER: shape = 5; break;
|
||||
default: WLOG("Unknown shape value %d", shape); break;
|
||||
}
|
||||
data->params[0].i = shape + (int)(c.blinkon == 0);
|
||||
unibi_out(ui, data->unibi_ext.set_cursor_style);
|
||||
UNIBI_SET_NUM_VAR(data->params[0], shape + (int)(c.blinkon == 0));
|
||||
unibi_out_ext(ui, data->unibi_ext.set_cursor_style);
|
||||
}
|
||||
|
||||
/// @param mode editor mode
|
||||
@ -917,7 +926,7 @@ static void tui_scroll(UI *ui, Integer count)
|
||||
cursor_goto(ui, grid->top, grid->left);
|
||||
// also set default color attributes or some terminals can become funny
|
||||
if (scroll_clears_to_current_colour) {
|
||||
HlAttrs clear_attrs = EMPTY_ATTRS;
|
||||
HlAttrs clear_attrs = HLATTRS_INIT;
|
||||
clear_attrs.foreground = grid->fg;
|
||||
clear_attrs.background = grid->bg;
|
||||
update_attrs(ui, clear_attrs);
|
||||
@ -927,14 +936,14 @@ static void tui_scroll(UI *ui, Integer count)
|
||||
if (count == 1) {
|
||||
unibi_out(ui, unibi_delete_line);
|
||||
} else {
|
||||
data->params[0].i = (int)count;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], (int)count);
|
||||
unibi_out(ui, unibi_parm_delete_line);
|
||||
}
|
||||
} else {
|
||||
if (count == -1) {
|
||||
unibi_out(ui, unibi_insert_line);
|
||||
} else {
|
||||
data->params[0].i = -(int)count;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], -(int)count);
|
||||
unibi_out(ui, unibi_parm_insert_line);
|
||||
}
|
||||
}
|
||||
@ -1177,30 +1186,33 @@ end:
|
||||
static void unibi_goto(UI *ui, int row, int col)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
data->params[0].i = row;
|
||||
data->params[1].i = col;
|
||||
UNIBI_SET_NUM_VAR(data->params[0], row);
|
||||
UNIBI_SET_NUM_VAR(data->params[1], col);
|
||||
unibi_out(ui, unibi_cursor_address);
|
||||
}
|
||||
|
||||
#define UNIBI_OUT(fn) \
|
||||
do { \
|
||||
TUIData *data = ui->data; \
|
||||
const char *str = NULL; \
|
||||
if (unibi_index >= 0) { \
|
||||
str = fn(data->ut, (unsigned)unibi_index); \
|
||||
} \
|
||||
if (str) { \
|
||||
unibi_var_t vars[26 + 26]; \
|
||||
memset(&vars, 0, sizeof(vars)); \
|
||||
unibi_format(vars, vars + 26, str, data->params, out, ui, NULL, NULL); \
|
||||
} \
|
||||
} while (0)
|
||||
static void unibi_out(UI *ui, int unibi_index)
|
||||
{
|
||||
TUIData *data = ui->data;
|
||||
|
||||
const char *str = NULL;
|
||||
|
||||
if (unibi_index >= 0) {
|
||||
if (unibi_index < unibi_string_begin_) {
|
||||
str = unibi_get_ext_str(data->ut, (unsigned)unibi_index);
|
||||
} else {
|
||||
str = unibi_get_str(data->ut, (unsigned)unibi_index);
|
||||
}
|
||||
}
|
||||
|
||||
if (str) {
|
||||
unibi_var_t vars[26 + 26] = {{0}};
|
||||
unibi_format(vars, vars + 26, str, data->params, out, ui, NULL, NULL);
|
||||
}
|
||||
UNIBI_OUT(unibi_get_str);
|
||||
}
|
||||
static void unibi_out_ext(UI *ui, int unibi_index)
|
||||
{
|
||||
UNIBI_OUT(unibi_get_ext_str);
|
||||
}
|
||||
#undef UNIBI_OUT
|
||||
|
||||
static void out(void *ctx, const char *str, size_t len)
|
||||
{
|
||||
@ -1261,7 +1273,9 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|
||||
bool gnome = terminfo_is_term_family(term, "gnome")
|
||||
|| terminfo_is_term_family(term, "vte");
|
||||
bool iterm = terminfo_is_term_family(term, "iterm")
|
||||
|| terminfo_is_term_family(term, "iTerm.app");
|
||||
|| terminfo_is_term_family(term, "iterm2")
|
||||
|| terminfo_is_term_family(term, "iTerm.app")
|
||||
|| terminfo_is_term_family(term, "iTerm2.app");
|
||||
// None of the following work over SSH; see :help TERM .
|
||||
bool iterm_pretending_xterm = xterm && iterm_env;
|
||||
bool konsole_pretending_xterm = xterm && konsole;
|
||||
@ -1444,7 +1458,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|
||||
// teminfo entries. See
|
||||
// https://github.com/gnachman/iTerm2/pull/92 for more.
|
||||
// xterm even has an extended version that has a vertical bar.
|
||||
if (true_xterm // per xterm ctlseqs doco (since version 282)
|
||||
if (!konsole && (true_xterm // per xterm ctlseqs doco (since version 282)
|
||||
// per MinTTY 0.4.3-1 release notes from 2009
|
||||
|| putty
|
||||
// per https://bugzilla.gnome.org/show_bug.cgi?id=720821
|
||||
@ -1459,7 +1473,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|
||||
// Allows forcing the use of DECSCUSR on linux type terminals, such as
|
||||
// console-terminal-emulator from the nosh toolset, which does indeed
|
||||
// implement the xterm extension:
|
||||
|| (linuxvt && (xterm_version || (vte_version > 0) || colorterm))) {
|
||||
|| (linuxvt && (xterm_version || (vte_version > 0) || colorterm)))) {
|
||||
data->unibi_ext.set_cursor_style =
|
||||
(int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q");
|
||||
if (-1 == data->unibi_ext.reset_cursor_style) {
|
||||
@ -1533,7 +1547,9 @@ static void augment_terminfo(TUIData *data, const char *term,
|
||||
bool screen = terminfo_is_term_family(term, "screen");
|
||||
bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX");
|
||||
bool iterm = terminfo_is_term_family(term, "iterm")
|
||||
|| terminfo_is_term_family(term, "iTerm.app");
|
||||
|| terminfo_is_term_family(term, "iterm2")
|
||||
|| terminfo_is_term_family(term, "iTerm.app")
|
||||
|| terminfo_is_term_family(term, "iTerm2.app");
|
||||
// None of the following work over SSH; see :help TERM .
|
||||
bool iterm_pretending_xterm = xterm && iterm_env;
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
void ugrid_init(UGrid *grid)
|
||||
{
|
||||
grid->attrs = EMPTY_ATTRS;
|
||||
grid->attrs = HLATTRS_INIT;
|
||||
grid->fg = grid->bg = -1;
|
||||
grid->cells = NULL;
|
||||
}
|
||||
@ -118,7 +118,7 @@ UCell *ugrid_put(UGrid *grid, uint8_t *text, size_t size)
|
||||
|
||||
static void clear_region(UGrid *grid, int top, int bot, int left, int right)
|
||||
{
|
||||
HlAttrs clear_attrs = EMPTY_ATTRS;
|
||||
HlAttrs clear_attrs = HLATTRS_INIT;
|
||||
clear_attrs.foreground = grid->fg;
|
||||
clear_attrs.background = grid->bg;
|
||||
UGRID_FOREACH_CELL(grid, top, bot, left, right, {
|
||||
|
@ -21,8 +21,6 @@ struct ugrid {
|
||||
UCell **cells;
|
||||
};
|
||||
|
||||
#define EMPTY_ATTRS ((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
|
||||
|
||||
#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \
|
||||
do { \
|
||||
for (int row = top; row <= bot; row++) { \
|
||||
|
128
src/nvim/ui.c
128
src/nvim/ui.c
@ -71,10 +71,10 @@ static char uilog_last_event[1024] = { 0 };
|
||||
uilog_seen++; \
|
||||
} else { \
|
||||
if (uilog_seen > 0) { \
|
||||
do_log(DEBUG_LOG_LEVEL, "ui", 0, true, \
|
||||
do_log(DEBUG_LOG_LEVEL, "UI: ", NULL, -1, true, \
|
||||
"%s (+%zu times...)", uilog_last_event, uilog_seen); \
|
||||
} \
|
||||
DLOG("ui: " STR(funname)); \
|
||||
do_log(DEBUG_LOG_LEVEL, "UI: ", NULL, -1, true, STR(funname)); \
|
||||
uilog_seen = 0; \
|
||||
xstrlcpy(uilog_last_event, STR(funname), sizeof(uilog_last_event)); \
|
||||
} \
|
||||
@ -166,6 +166,90 @@ void ui_event(char *name, Array args)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Converts an attrentry_T into an HlAttrs
|
||||
///
|
||||
/// @param[in] aep data to convert
|
||||
/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*'
|
||||
HlAttrs attrentry2hlattrs(const attrentry_T *aep, bool use_rgb)
|
||||
{
|
||||
assert(aep);
|
||||
|
||||
HlAttrs attrs = HLATTRS_INIT;
|
||||
int mask = 0;
|
||||
|
||||
mask = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr;
|
||||
|
||||
attrs.bold = mask & HL_BOLD;
|
||||
attrs.underline = mask & HL_UNDERLINE;
|
||||
attrs.undercurl = mask & HL_UNDERCURL;
|
||||
attrs.italic = mask & HL_ITALIC;
|
||||
attrs.reverse = mask & (HL_INVERSE | HL_STANDOUT);
|
||||
|
||||
if (use_rgb) {
|
||||
if (aep->rgb_fg_color != -1) {
|
||||
attrs.foreground = aep->rgb_fg_color;
|
||||
}
|
||||
|
||||
if (aep->rgb_bg_color != -1) {
|
||||
attrs.background = aep->rgb_bg_color;
|
||||
}
|
||||
|
||||
if (aep->rgb_sp_color != -1) {
|
||||
attrs.special = aep->rgb_sp_color;
|
||||
}
|
||||
} else {
|
||||
if (cterm_normal_fg_color != aep->cterm_fg_color) {
|
||||
attrs.foreground = aep->cterm_fg_color - 1;
|
||||
}
|
||||
|
||||
if (cterm_normal_bg_color != aep->cterm_bg_color) {
|
||||
attrs.background = aep->cterm_bg_color - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return attrs;
|
||||
}
|
||||
|
||||
Dictionary hlattrs2dict(HlAttrs attrs)
|
||||
{
|
||||
Dictionary hl = ARRAY_DICT_INIT;
|
||||
|
||||
if (attrs.bold) {
|
||||
PUT(hl, "bold", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.underline) {
|
||||
PUT(hl, "underline", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.undercurl) {
|
||||
PUT(hl, "undercurl", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.italic) {
|
||||
PUT(hl, "italic", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.reverse) {
|
||||
PUT(hl, "reverse", BOOLEAN_OBJ(true));
|
||||
}
|
||||
|
||||
if (attrs.foreground != -1) {
|
||||
PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground));
|
||||
}
|
||||
|
||||
if (attrs.background != -1) {
|
||||
PUT(hl, "background", INTEGER_OBJ(attrs.background));
|
||||
}
|
||||
|
||||
if (attrs.special != -1) {
|
||||
PUT(hl, "special", INTEGER_OBJ(attrs.special));
|
||||
}
|
||||
|
||||
return hl;
|
||||
}
|
||||
|
||||
void ui_refresh(void)
|
||||
{
|
||||
if (!ui_active()) {
|
||||
@ -405,54 +489,20 @@ void ui_flush(void)
|
||||
|
||||
static void set_highlight_args(int attr_code)
|
||||
{
|
||||
HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1, -1 };
|
||||
HlAttrs rgb_attrs = HLATTRS_INIT;
|
||||
HlAttrs cterm_attrs = rgb_attrs;
|
||||
|
||||
if (attr_code == HL_NORMAL) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
int rgb_mask = 0;
|
||||
int cterm_mask = 0;
|
||||
attrentry_T *aep = syn_cterm_attr2entry(attr_code);
|
||||
|
||||
if (!aep) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
rgb_mask = aep->rgb_ae_attr;
|
||||
cterm_mask = aep->cterm_ae_attr;
|
||||
|
||||
rgb_attrs.bold = rgb_mask & HL_BOLD;
|
||||
rgb_attrs.underline = rgb_mask & HL_UNDERLINE;
|
||||
rgb_attrs.undercurl = rgb_mask & HL_UNDERCURL;
|
||||
rgb_attrs.italic = rgb_mask & HL_ITALIC;
|
||||
rgb_attrs.reverse = rgb_mask & (HL_INVERSE | HL_STANDOUT);
|
||||
cterm_attrs.bold = cterm_mask & HL_BOLD;
|
||||
cterm_attrs.underline = cterm_mask & HL_UNDERLINE;
|
||||
cterm_attrs.undercurl = cterm_mask & HL_UNDERCURL;
|
||||
cterm_attrs.italic = cterm_mask & HL_ITALIC;
|
||||
cterm_attrs.reverse = cterm_mask & (HL_INVERSE | HL_STANDOUT);
|
||||
|
||||
if (aep->rgb_fg_color != normal_fg) {
|
||||
rgb_attrs.foreground = aep->rgb_fg_color;
|
||||
}
|
||||
|
||||
if (aep->rgb_bg_color != normal_bg) {
|
||||
rgb_attrs.background = aep->rgb_bg_color;
|
||||
}
|
||||
|
||||
if (aep->rgb_sp_color != normal_sp) {
|
||||
rgb_attrs.special = aep->rgb_sp_color;
|
||||
}
|
||||
|
||||
if (cterm_normal_fg_color != aep->cterm_fg_color) {
|
||||
cterm_attrs.foreground = aep->cterm_fg_color - 1;
|
||||
}
|
||||
|
||||
if (cterm_normal_bg_color != aep->cterm_bg_color) {
|
||||
cterm_attrs.background = aep->cterm_bg_color - 1;
|
||||
}
|
||||
rgb_attrs = attrentry2hlattrs(aep, true);
|
||||
cterm_attrs = attrentry2hlattrs(aep, false);
|
||||
|
||||
end:
|
||||
UI_CALL(highlight_set, (ui->rgb ? rgb_attrs : cterm_attrs));
|
||||
|
@ -21,6 +21,9 @@ typedef struct {
|
||||
int foreground, background, special;
|
||||
} HlAttrs;
|
||||
|
||||
#define HLATTRS_INIT \
|
||||
((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
|
||||
|
||||
typedef struct ui_t UI;
|
||||
|
||||
struct ui_t {
|
||||
|
@ -77,6 +77,157 @@ static char *features[] = {
|
||||
|
||||
// clang-format off
|
||||
static const int included_patches[] = {
|
||||
// 1026,
|
||||
1025,
|
||||
1024,
|
||||
// 1023,
|
||||
// 1022,
|
||||
// 1021,
|
||||
// 1020,
|
||||
// 1019,
|
||||
// 1018,
|
||||
// 1017,
|
||||
// 1016,
|
||||
// 1015,
|
||||
// 1014,
|
||||
// 1013,
|
||||
// 1012,
|
||||
// 1011,
|
||||
// 1010,
|
||||
// 1009,
|
||||
// 1008,
|
||||
// 1007,
|
||||
// 1006,
|
||||
// 1005,
|
||||
// 1004,
|
||||
// 1003,
|
||||
// 1002,
|
||||
// 1001,
|
||||
// 1000,
|
||||
// 999,
|
||||
// 998,
|
||||
// 997,
|
||||
// 996,
|
||||
// 995,
|
||||
// 994,
|
||||
// 993,
|
||||
// 992,
|
||||
// 991,
|
||||
// 990,
|
||||
// 989,
|
||||
// 988,
|
||||
// 987,
|
||||
// 986,
|
||||
// 985,
|
||||
// 984,
|
||||
// 983,
|
||||
// 982,
|
||||
// 981,
|
||||
// 980,
|
||||
// 979,
|
||||
// 978,
|
||||
// 977,
|
||||
// 976,
|
||||
// 975,
|
||||
// 974,
|
||||
// 973,
|
||||
// 972,
|
||||
// 971,
|
||||
// 970,
|
||||
// 969,
|
||||
// 968,
|
||||
// 967,
|
||||
// 966,
|
||||
// 965,
|
||||
// 964,
|
||||
// 963,
|
||||
// 962,
|
||||
// 961,
|
||||
// 960,
|
||||
// 959,
|
||||
// 958,
|
||||
// 957,
|
||||
// 956,
|
||||
// 955,
|
||||
// 954,
|
||||
// 953,
|
||||
// 952,
|
||||
// 951,
|
||||
// 950,
|
||||
// 949,
|
||||
// 948,
|
||||
// 947,
|
||||
// 946,
|
||||
// 945,
|
||||
// 944,
|
||||
// 943,
|
||||
// 942,
|
||||
// 941,
|
||||
// 940,
|
||||
// 939,
|
||||
// 938,
|
||||
// 937,
|
||||
// 936,
|
||||
// 935,
|
||||
// 934,
|
||||
// 933,
|
||||
// 932,
|
||||
// 931,
|
||||
// 930,
|
||||
// 929,
|
||||
// 928,
|
||||
// 927,
|
||||
// 926,
|
||||
// 925,
|
||||
// 924,
|
||||
// 923,
|
||||
// 922,
|
||||
// 921,
|
||||
// 920,
|
||||
// 919,
|
||||
// 918,
|
||||
// 917,
|
||||
// 916,
|
||||
// 915,
|
||||
// 914,
|
||||
// 913,
|
||||
// 912,
|
||||
// 911,
|
||||
// 910,
|
||||
// 909,
|
||||
// 908,
|
||||
// 907,
|
||||
// 906,
|
||||
// 905,
|
||||
// 904,
|
||||
// 903,
|
||||
// 902,
|
||||
// 901,
|
||||
// 900,
|
||||
// 899,
|
||||
// 898,
|
||||
// 897,
|
||||
// 896,
|
||||
// 895,
|
||||
// 894,
|
||||
// 893,
|
||||
// 892,
|
||||
// 891,
|
||||
// 890,
|
||||
// 889,
|
||||
// 888,
|
||||
// 887,
|
||||
// 886,
|
||||
// 885,
|
||||
// 884,
|
||||
// 883,
|
||||
// 882,
|
||||
// 881,
|
||||
// 880,
|
||||
// 879,
|
||||
// 878,
|
||||
// 877,
|
||||
// 876,
|
||||
// 875,
|
||||
// 874,
|
||||
// 873,
|
||||
@ -272,7 +423,7 @@ static const int included_patches[] = {
|
||||
// 683,
|
||||
// 682,
|
||||
// 681,
|
||||
// 680,
|
||||
680,
|
||||
679,
|
||||
678,
|
||||
// 677,
|
||||
@ -340,7 +491,7 @@ static const int included_patches[] = {
|
||||
// 615,
|
||||
614,
|
||||
// 613,
|
||||
// 612,
|
||||
612,
|
||||
// 611,
|
||||
// 610,
|
||||
// 609,
|
||||
@ -515,7 +666,7 @@ static const int included_patches[] = {
|
||||
// 440,
|
||||
// 439,
|
||||
// 438,
|
||||
// 437,
|
||||
437,
|
||||
// 436,
|
||||
// 435,
|
||||
// 434,
|
||||
@ -619,16 +770,16 @@ static const int included_patches[] = {
|
||||
// 336,
|
||||
// 335,
|
||||
// 334,
|
||||
// 333,
|
||||
333,
|
||||
// 332,
|
||||
331,
|
||||
// 330,
|
||||
330,
|
||||
// 329,
|
||||
// 328,
|
||||
// 327,
|
||||
// 326,
|
||||
// 325,
|
||||
// 324,
|
||||
328,
|
||||
327,
|
||||
326,
|
||||
325,
|
||||
324,
|
||||
// 323,
|
||||
322,
|
||||
// 321,
|
||||
@ -644,24 +795,24 @@ static const int included_patches[] = {
|
||||
311,
|
||||
// 310,
|
||||
// 309,
|
||||
// 308,
|
||||
308,
|
||||
307,
|
||||
// 306,
|
||||
// 305,
|
||||
305,
|
||||
// 304,
|
||||
// 303,
|
||||
// 302,
|
||||
// 302, NA
|
||||
// 301,
|
||||
// 300,
|
||||
300,
|
||||
// 299,
|
||||
// 298,
|
||||
297,
|
||||
// 296,
|
||||
// 295,
|
||||
// 294,
|
||||
294,
|
||||
// 293,
|
||||
// 292,
|
||||
// 291,
|
||||
291,
|
||||
290,
|
||||
// 289,
|
||||
// 288 NA
|
||||
@ -670,7 +821,7 @@ static const int included_patches[] = {
|
||||
// 285 NA
|
||||
// 284 NA
|
||||
// 283,
|
||||
// 282,
|
||||
282,
|
||||
// 281 NA
|
||||
280,
|
||||
// 279 NA
|
||||
@ -694,18 +845,18 @@ static const int included_patches[] = {
|
||||
// 261,
|
||||
// 260 NA
|
||||
259,
|
||||
// 258,
|
||||
258,
|
||||
// 257 NA
|
||||
// 256,
|
||||
// 255,
|
||||
// 254,
|
||||
// 253,
|
||||
253,
|
||||
// 252,
|
||||
// 251,
|
||||
250,
|
||||
// 249 NA
|
||||
// 248,
|
||||
// 247,
|
||||
247,
|
||||
// 246 NA
|
||||
// 245,
|
||||
// 244,
|
||||
@ -743,7 +894,7 @@ static const int included_patches[] = {
|
||||
// 212,
|
||||
// 211 NA
|
||||
// 210,
|
||||
// 209,
|
||||
209,
|
||||
208,
|
||||
// 207,
|
||||
// 206,
|
||||
@ -764,14 +915,14 @@ static const int included_patches[] = {
|
||||
// 191 NA
|
||||
190,
|
||||
// 189,
|
||||
// 188,
|
||||
188,
|
||||
// 187 NA
|
||||
// 186,
|
||||
186,
|
||||
// 185,
|
||||
// 184,
|
||||
// 183,
|
||||
// 182,
|
||||
// 181,
|
||||
182,
|
||||
181,
|
||||
// 180,
|
||||
179,
|
||||
178,
|
||||
@ -788,29 +939,29 @@ static const int included_patches[] = {
|
||||
167,
|
||||
// 166,
|
||||
165,
|
||||
// 164,
|
||||
164,
|
||||
// 163 NA
|
||||
// 162 NA
|
||||
// 161 NA
|
||||
// 160,
|
||||
159,
|
||||
158,
|
||||
// 157,
|
||||
157,
|
||||
156,
|
||||
// 155,
|
||||
155,
|
||||
// 154,
|
||||
// 153,
|
||||
// 152 NA
|
||||
// 151,
|
||||
150,
|
||||
149,
|
||||
// 148,
|
||||
148,
|
||||
147,
|
||||
146,
|
||||
// 145 NA
|
||||
// 144 NA
|
||||
143,
|
||||
// 142,
|
||||
142,
|
||||
// 141,
|
||||
// 140,
|
||||
// 139 NA
|
||||
@ -820,14 +971,14 @@ static const int included_patches[] = {
|
||||
135,
|
||||
134,
|
||||
133,
|
||||
// 132,
|
||||
// 131,
|
||||
132,
|
||||
131,
|
||||
// 130 NA
|
||||
// 129 NA
|
||||
128,
|
||||
127,
|
||||
126,
|
||||
// 125,
|
||||
125,
|
||||
124,
|
||||
// 123 NA
|
||||
// 122 NA
|
||||
@ -840,7 +991,7 @@ static const int included_patches[] = {
|
||||
// 115 NA
|
||||
// 114 NA
|
||||
// 113 NA
|
||||
// 112,
|
||||
112,
|
||||
111,
|
||||
110,
|
||||
// 109 NA
|
||||
@ -860,8 +1011,8 @@ static const int included_patches[] = {
|
||||
// 95 NA
|
||||
// 94 NA
|
||||
// 93 NA
|
||||
// 92,
|
||||
// 91,
|
||||
92,
|
||||
91,
|
||||
90,
|
||||
// 89 NA
|
||||
88,
|
||||
@ -1089,13 +1240,7 @@ static void list_features(void)
|
||||
msg_putchar('\n');
|
||||
}
|
||||
} else {
|
||||
while (msg_col % width) {
|
||||
int old_msg_col = msg_col;
|
||||
msg_putchar(' ');
|
||||
if (old_msg_col == msg_col) {
|
||||
break; // XXX: Avoid infinite loop.
|
||||
}
|
||||
}
|
||||
msg_putchar(' ');
|
||||
}
|
||||
} else {
|
||||
if (msg_col > 0) {
|
||||
@ -1103,7 +1248,7 @@ static void list_features(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
MSG_PUTS("For differences from Vim, see :help vim-differences\n\n");
|
||||
MSG_PUTS("See \":help feature-compile\"\n\n");
|
||||
}
|
||||
|
||||
void list_version(void)
|
||||
@ -1144,7 +1289,7 @@ void list_version(void)
|
||||
}
|
||||
#endif // ifdef HAVE_PATHDEF
|
||||
|
||||
version_msg(_("\n\nOptional features included (+) or not (-): "));
|
||||
version_msg(_("\n\nFeatures: "));
|
||||
|
||||
list_features();
|
||||
|
||||
@ -1216,7 +1361,6 @@ void intro_message(int colon)
|
||||
static char *(lines[]) = {
|
||||
N_(NVIM_VERSION_LONG),
|
||||
"",
|
||||
N_("by al."),
|
||||
N_("Nvim is open source and freely distributable"),
|
||||
N_("https://neovim.io/community"),
|
||||
"",
|
||||
|
@ -5515,11 +5515,14 @@ void restore_buffer(bufref_T *save_curbuf)
|
||||
}
|
||||
|
||||
|
||||
// Add match to the match list of window 'wp'. The pattern 'pat' will be
|
||||
// highlighted with the group 'grp' with priority 'prio'.
|
||||
// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
|
||||
// If no particular ID is desired, -1 must be specified for 'id'.
|
||||
// Return ID of added match, -1 on failure.
|
||||
/// Add match to the match list of window 'wp'. The pattern 'pat' will be
|
||||
/// highlighted with the group 'grp' with priority 'prio'.
|
||||
/// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
|
||||
///
|
||||
/// @param[in] id a desired ID 'id' can be specified
|
||||
/// (greater than or equal to 1). -1 must be specified if no
|
||||
/// particular ID is desired
|
||||
/// @return ID of added match, -1 on failure.
|
||||
int match_add(win_T *wp, const char *const grp, const char *const pat,
|
||||
int prio, int id, list_T *pos_list,
|
||||
const char *const conceal_char)
|
||||
@ -5697,10 +5700,9 @@ fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete match with ID 'id' in the match list of window 'wp'.
|
||||
* Print error messages if 'perr' is TRUE.
|
||||
*/
|
||||
|
||||
/// Delete match with ID 'id' in the match list of window 'wp'.
|
||||
/// Print error messages if 'perr' is TRUE.
|
||||
int match_delete(win_T *wp, int id, int perr)
|
||||
{
|
||||
matchitem_T *cur = wp->w_match_head;
|
||||
|
@ -17,4 +17,4 @@ ignore = {
|
||||
}
|
||||
|
||||
-- Ignore whitespace issues in converted Vim legacy tests.
|
||||
files["functional/legacy"] = {ignore = { "611", "612", "613", "621" }}
|
||||
--files["functional/legacy"] = {ignore = { "611", "612", "613", "621" }}
|
||||
|
103
test/functional/api/highlight_spec.lua
Normal file
103
test/functional/api/highlight_spec.lua
Normal file
@ -0,0 +1,103 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, nvim = helpers.clear, helpers.nvim
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local eq, eval = helpers.eq, helpers.eval
|
||||
local command = helpers.command
|
||||
local meths = helpers.meths
|
||||
|
||||
describe('highlight api',function()
|
||||
local expected_rgb = {
|
||||
background = Screen.colors.Yellow,
|
||||
foreground = Screen.colors.Red,
|
||||
special = Screen.colors.Blue,
|
||||
bold = true,
|
||||
}
|
||||
local expected_cterm = {
|
||||
background = 10,
|
||||
underline = true,
|
||||
}
|
||||
local expected_rgb2 = {
|
||||
background = Screen.colors.Yellow,
|
||||
foreground = Screen.colors.Red,
|
||||
special = Screen.colors.Blue,
|
||||
bold = true,
|
||||
italic = true,
|
||||
reverse = true,
|
||||
undercurl = true,
|
||||
underline = true,
|
||||
}
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
command("hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold")
|
||||
end)
|
||||
|
||||
it("nvim_get_hl_by_id", function()
|
||||
local hl_id = eval("hlID('NewHighlight')")
|
||||
eq(expected_cterm, nvim("get_hl_by_id", hl_id, false))
|
||||
|
||||
hl_id = eval("hlID('NewHighlight')")
|
||||
-- Test valid id.
|
||||
eq(expected_rgb, nvim("get_hl_by_id", hl_id, true))
|
||||
|
||||
-- Test invalid id.
|
||||
local err, emsg = pcall(meths.get_hl_by_id, 30000, false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*'))
|
||||
|
||||
-- Test all highlight properties.
|
||||
command('hi NewHighlight gui=underline,bold,undercurl,italic,reverse')
|
||||
eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true))
|
||||
|
||||
-- Test nil argument.
|
||||
err, emsg = pcall(meths.get_hl_by_id, { nil }, false)
|
||||
eq(false, err)
|
||||
eq('Wrong type for argument 1, expecting Integer',
|
||||
string.match(emsg, 'Wrong.*'))
|
||||
|
||||
-- Test 0 argument.
|
||||
err, emsg = pcall(meths.get_hl_by_id, 0, false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight id: 0',
|
||||
string.match(emsg, 'Invalid.*'))
|
||||
|
||||
-- Test -1 argument.
|
||||
err, emsg = pcall(meths.get_hl_by_id, -1, false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight id: -1',
|
||||
string.match(emsg, 'Invalid.*'))
|
||||
end)
|
||||
|
||||
it("nvim_get_hl_by_name", function()
|
||||
local expected_normal = { background = Screen.colors.Yellow,
|
||||
foreground = Screen.colors.Red }
|
||||
|
||||
-- Test `Normal` default values.
|
||||
eq({}, nvim("get_hl_by_name", 'Normal', true))
|
||||
|
||||
eq(expected_cterm, nvim("get_hl_by_name", 'NewHighlight', false))
|
||||
eq(expected_rgb, nvim("get_hl_by_name", 'NewHighlight', true))
|
||||
|
||||
-- Test `Normal` modified values.
|
||||
command('hi Normal guifg=red guibg=yellow')
|
||||
eq(expected_normal, nvim("get_hl_by_name", 'Normal', true))
|
||||
|
||||
-- Test invalid name.
|
||||
local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight', false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight name: unknown_highlight',
|
||||
string.match(emsg, 'Invalid.*'))
|
||||
|
||||
-- Test nil argument.
|
||||
err, emsg = pcall(meths.get_hl_by_name , { nil }, false)
|
||||
eq(false, err)
|
||||
eq('Wrong type for argument 1, expecting String',
|
||||
string.match(emsg, 'Wrong.*'))
|
||||
|
||||
-- Test empty string argument.
|
||||
err, emsg = pcall(meths.get_hl_by_name , '', false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight name: ',
|
||||
string.match(emsg, 'Invalid.*'))
|
||||
end)
|
||||
end)
|
@ -20,6 +20,22 @@ describe('server -> client', function()
|
||||
cid = nvim('get_api_info')[1]
|
||||
end)
|
||||
|
||||
it('handles unexpected closed stream while preparing RPC response', function()
|
||||
source([[
|
||||
let g:_nvim_args = [v:progpath, '--embed', '-n', '-u', 'NONE', '-i', 'NONE', ]
|
||||
let ch1 = jobstart(g:_nvim_args, {'rpc': v:true})
|
||||
let child1_ch = rpcrequest(ch1, "nvim_get_api_info")[0]
|
||||
call rpcnotify(ch1, 'nvim_eval', 'rpcrequest('.child1_ch.', "nvim_get_api_info")')
|
||||
|
||||
let ch2 = jobstart(g:_nvim_args, {'rpc': v:true})
|
||||
let child2_ch = rpcrequest(ch2, "nvim_get_api_info")[0]
|
||||
call rpcnotify(ch2, 'nvim_eval', 'rpcrequest('.child2_ch.', "nvim_get_api_info")')
|
||||
|
||||
call jobstop(ch1)
|
||||
]])
|
||||
eq(2, eval("1+1")) -- Still alive?
|
||||
end)
|
||||
|
||||
describe('simple call', function()
|
||||
it('works', function()
|
||||
local function on_setup()
|
||||
@ -141,7 +157,7 @@ describe('server -> client', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('when the client is a recursive vim instance', function()
|
||||
describe('recursive (child) nvim client', function()
|
||||
if os.getenv("TRAVIS") and helpers.os_name() == "osx" then
|
||||
-- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
|
||||
pending("[Hangs on Travis macOS. #5002]", function() end)
|
||||
@ -155,7 +171,7 @@ describe('server -> client', function()
|
||||
|
||||
after_each(function() command('call rpcstop(vim)') end)
|
||||
|
||||
it('can send/recieve notifications and make requests', function()
|
||||
it('can send/receive notifications and make requests', function()
|
||||
nvim('command', "call rpcnotify(vim, 'vim_set_current_line', 'SOME TEXT')")
|
||||
|
||||
-- Wait for the notification to complete.
|
||||
@ -188,7 +204,7 @@ describe('server -> client', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('when using jobstart', function()
|
||||
describe('jobstart()', function()
|
||||
local jobid
|
||||
before_each(function()
|
||||
local channel = nvim('get_api_info')[1]
|
||||
@ -227,7 +243,7 @@ describe('server -> client', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('when connecting to another nvim instance', function()
|
||||
describe('connecting to another (peer) nvim', function()
|
||||
local function connect_test(server, mode, address)
|
||||
local serverpid = funcs.getpid()
|
||||
local client = spawn(nvim_argv)
|
||||
@ -256,7 +272,7 @@ describe('server -> client', function()
|
||||
client:close()
|
||||
end
|
||||
|
||||
it('over a named pipe', function()
|
||||
it('via named pipe', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverlist()[1]
|
||||
@ -265,7 +281,7 @@ describe('server -> client', function()
|
||||
connect_test(server, 'pipe', address)
|
||||
end)
|
||||
|
||||
it('to an ip adress', function()
|
||||
it('via ip address', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverstart("127.0.0.1:")
|
||||
@ -273,7 +289,7 @@ describe('server -> client', function()
|
||||
connect_test(server, 'tcp', address)
|
||||
end)
|
||||
|
||||
it('to a hostname', function()
|
||||
it('via hostname', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverstart("localhost:")
|
||||
|
@ -329,24 +329,92 @@ describe('api', function()
|
||||
}
|
||||
eq({ { {mode='n', blocking=false},
|
||||
13,
|
||||
{mode='n', blocking=false}, -- TODO: should be blocked=true
|
||||
{mode='n', blocking=false}, -- TODO: should be blocked=true ?
|
||||
1 },
|
||||
NIL}, meths.call_atomic(req))
|
||||
eq({mode='r', blocking=true}, nvim("get_mode"))
|
||||
end)
|
||||
-- TODO: bug #6166
|
||||
it("during insert-mode map-pending, returns blocking=true #6166", function()
|
||||
command("inoremap xx foo")
|
||||
nvim("input", "ix")
|
||||
eq({mode='i', blocking=true}, nvim("get_mode"))
|
||||
end)
|
||||
-- TODO: bug #6166
|
||||
it("during normal-mode gU, returns blocking=false #6166", function()
|
||||
nvim("input", "gu")
|
||||
eq({mode='no', blocking=false}, nvim("get_mode"))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('RPC (K_EVENT) #6166', function()
|
||||
it('does not complete ("interrupt") normal-mode operator-pending', function()
|
||||
helpers.insert([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
nvim('input', 'gg')
|
||||
nvim('input', 'gu')
|
||||
-- Make any RPC request (can be non-async: op-pending does not block).
|
||||
nvim('get_current_buf')
|
||||
-- Buffer should not change.
|
||||
helpers.expect([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
-- Now send input to complete the operator.
|
||||
nvim('input', 'j')
|
||||
helpers.expect([[
|
||||
first line
|
||||
second line]])
|
||||
end)
|
||||
|
||||
it('does not complete ("interrupt") `d` #3732', function()
|
||||
local screen = Screen.new(20, 4)
|
||||
screen:attach()
|
||||
command('set listchars=eol:$')
|
||||
command('set list')
|
||||
feed('ia<cr>b<cr>c<cr><Esc>kkk')
|
||||
feed('d')
|
||||
-- Make any RPC request (can be non-async: op-pending does not block).
|
||||
nvim('get_current_buf')
|
||||
screen:expect([[
|
||||
^a$ |
|
||||
b$ |
|
||||
c$ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('does not complete ("interrupt") normal-mode map-pending', function()
|
||||
command("nnoremap dd :let g:foo='it worked...'<CR>")
|
||||
helpers.insert([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
nvim('input', 'gg')
|
||||
nvim('input', 'd')
|
||||
-- Make any RPC request (must be async, because map-pending blocks).
|
||||
nvim('get_api_info')
|
||||
-- Send input to complete the mapping.
|
||||
nvim('input', 'd')
|
||||
helpers.expect([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
eq('it worked...', helpers.eval('g:foo'))
|
||||
end)
|
||||
it('does not complete ("interrupt") insert-mode map-pending', function()
|
||||
command('inoremap xx foo')
|
||||
command('set timeoutlen=9999')
|
||||
helpers.insert([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
nvim('input', 'ix')
|
||||
-- Make any RPC request (must be async, because map-pending blocks).
|
||||
nvim('get_api_info')
|
||||
-- Send input to complete the mapping.
|
||||
nvim('input', 'x')
|
||||
helpers.expect([[
|
||||
FIRST LINE
|
||||
SECOND LINfooE]])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_replace_termcodes', function()
|
||||
it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function()
|
||||
eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true))
|
||||
|
@ -57,7 +57,9 @@ describe('TermClose event', function()
|
||||
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)
|
||||
-- nvim starts sending kill after 2*KILL_TIMEOUT_MS
|
||||
helpers.ok(4 <= duration)
|
||||
helpers.ok(duration <= 7) -- <= 4 + delta because of slow CI
|
||||
end)
|
||||
|
||||
it('reports the correct <abuf>', function()
|
||||
|
@ -4,6 +4,8 @@ local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local feed_command, expect, eq, eval = helpers.feed_command, helpers.expect, helpers.eq, helpers.eval
|
||||
local command = helpers.command
|
||||
local meths = helpers.meths
|
||||
|
||||
local function basic_register_test(noblock)
|
||||
insert("some words")
|
||||
@ -80,15 +82,73 @@ local function basic_register_test(noblock)
|
||||
expect("two and three and one")
|
||||
end
|
||||
|
||||
describe('the unnamed register', function()
|
||||
describe('clipboard', function()
|
||||
before_each(clear)
|
||||
it('works without provider', function()
|
||||
|
||||
it('unnamed register works without provider', function()
|
||||
eq('"', eval('v:register'))
|
||||
basic_register_test()
|
||||
end)
|
||||
|
||||
it('`:redir @+>` with invalid g:clipboard shows exactly one error #7184',
|
||||
function()
|
||||
local screen = Screen.new(72, 4)
|
||||
screen:attach()
|
||||
command("let g:clipboard = 'bogus'")
|
||||
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
clipboard: No provider. Try ":CheckHealth" or ":h clipboard". |
|
||||
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
|
||||
end)
|
||||
|
||||
it('`:redir @+>|bogus_cmd|redir END` + invalid g:clipboard must not recurse #7184',
|
||||
function()
|
||||
local screen = Screen.new(72, 4)
|
||||
screen:attach()
|
||||
command("let g:clipboard = 'bogus'")
|
||||
feed_command('redir @+> | bogus_cmd | redir END')
|
||||
screen:expect([[
|
||||
~ |
|
||||
clipboard: No provider. Try ":CheckHealth" or ":h clipboard". |
|
||||
E492: Not an editor command: bogus_cmd | redir END |
|
||||
Press ENTER or type command to continue^ |
|
||||
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
|
||||
end)
|
||||
|
||||
it('invalid g:clipboard shows hint if :redir is not active', function()
|
||||
command("let g:clipboard = 'bogus'")
|
||||
eq('', eval('provider#clipboard#Executable()'))
|
||||
eq('clipboard: invalid g:clipboard', eval('provider#clipboard#Error()'))
|
||||
|
||||
local screen = Screen.new(72, 4)
|
||||
screen:attach()
|
||||
command("let g:clipboard = 'bogus'")
|
||||
-- Explicit clipboard attempt, should show a hint message.
|
||||
feed_command('let @+="foo"')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
clipboard: No provider. Try ":CheckHealth" or ":h clipboard". |
|
||||
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
|
||||
end)
|
||||
|
||||
it('valid g:clipboard', function()
|
||||
-- provider#clipboard#Executable() only checks the structure.
|
||||
meths.set_var('clipboard', {
|
||||
['name'] = 'clippy!',
|
||||
['copy'] = { ['+'] = 'any command', ['*'] = 'some other' },
|
||||
['paste'] = { ['+'] = 'any command', ['*'] = 'some other' },
|
||||
})
|
||||
eq('clippy!', eval('provider#clipboard#Executable()'))
|
||||
eq('', eval('provider#clipboard#Error()'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('clipboard usage', function()
|
||||
describe('clipboard', function()
|
||||
local function reset(...)
|
||||
clear('--cmd', 'let &rtp = "test/functional/fixtures,".&rtp', ...)
|
||||
end
|
||||
@ -98,7 +158,36 @@ describe('clipboard usage', function()
|
||||
feed_command('call getreg("*")') -- force load of provider
|
||||
end)
|
||||
|
||||
it('has independent "* and unnamed registers per default', function()
|
||||
it('`:redir @+>` invokes clipboard once-per-message', function()
|
||||
eq(0, eval("g:clip_called_set"))
|
||||
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
|
||||
-- Assuming CONTRIBUTING.md has >100 lines.
|
||||
assert(eval("g:clip_called_set") > 100)
|
||||
end)
|
||||
|
||||
it('`:redir @">` does NOT invoke clipboard', function()
|
||||
-- :redir to a non-clipboard register, with `:set clipboard=unnamed` does
|
||||
-- NOT propagate to the clipboard. This is consistent with Vim.
|
||||
command("set clipboard=unnamedplus")
|
||||
eq(0, eval("g:clip_called_set"))
|
||||
feed_command('redir @"> | :silent echo system("cat CONTRIBUTING.md") | redir END')
|
||||
eq(0, eval("g:clip_called_set"))
|
||||
end)
|
||||
|
||||
it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184',
|
||||
function()
|
||||
local screen = Screen.new(72, 4)
|
||||
screen:attach()
|
||||
feed_command('redir @+> | bogus_cmd | redir END')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
E492: Not an editor command: bogus_cmd | redir END |
|
||||
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
|
||||
end)
|
||||
|
||||
it('has independent "* and unnamed registers by default', function()
|
||||
insert("some words")
|
||||
feed('^"*dwdw"*P')
|
||||
expect('some ')
|
||||
@ -139,7 +228,7 @@ describe('clipboard usage', function()
|
||||
eq({'some\ntext', '\nvery binary\n'}, eval("getreg('*', 1, 1)"))
|
||||
end)
|
||||
|
||||
it('support autodectection of regtype', function()
|
||||
it('autodetects regtype', function()
|
||||
feed_command("let g:test_clip['*'] = ['linewise stuff','']")
|
||||
feed_command("let g:test_clip['+'] = ['charwise','stuff']")
|
||||
eq("V", eval("getregtype('*')"))
|
||||
@ -169,7 +258,7 @@ describe('clipboard usage', function()
|
||||
eq({{' much', 'ktext', ''}, 'b'}, eval("g:test_clip['+']"))
|
||||
end)
|
||||
|
||||
it('supports setreg', function()
|
||||
it('supports setreg()', function()
|
||||
feed_command('call setreg("*", "setted\\ntext", "c")')
|
||||
feed_command('call setreg("+", "explicitly\\nlines", "l")')
|
||||
feed('"+P"*p')
|
||||
@ -187,7 +276,7 @@ describe('clipboard usage', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
it('supports let @+ (issue #1427)', function()
|
||||
it('supports :let @+ (issue #1427)', function()
|
||||
feed_command("let @+ = 'some'")
|
||||
feed_command("let @* = ' other stuff'")
|
||||
eq({{'some'}, 'v'}, eval("g:test_clip['+']"))
|
||||
@ -303,9 +392,16 @@ describe('clipboard usage', function()
|
||||
eq('---', eval('getreg("*")'))
|
||||
end)
|
||||
|
||||
it('works in the cmdline window', function()
|
||||
feed('q:itext<esc>yy')
|
||||
eq({{'text', ''}, 'V'}, eval("g:test_clip['*']"))
|
||||
command("let g:test_clip['*'] = [['star'], 'c']")
|
||||
feed('p')
|
||||
eq('textstar', meths.get_current_line())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with clipboard=unnamedplus', function()
|
||||
describe('clipboard=unnamedplus', function()
|
||||
before_each(function()
|
||||
feed_command('set clipboard=unnamedplus')
|
||||
end)
|
||||
@ -349,6 +445,7 @@ describe('clipboard usage', function()
|
||||
really unnamed
|
||||
the plus]])
|
||||
end)
|
||||
|
||||
it('is updated on global changes', function()
|
||||
insert([[
|
||||
text
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user