diff options
-rw-r--r-- | README.md | 53 | ||||
-rw-r--r-- | runtime/doc/api.txt | 21 | ||||
-rw-r--r-- | runtime/doc/develop.txt | 7 | ||||
-rw-r--r-- | runtime/doc/eval.txt | 27 | ||||
-rw-r--r-- | runtime/doc/if_pyth.txt | 23 | ||||
-rw-r--r-- | runtime/doc/insert.txt | 2 | ||||
-rw-r--r-- | runtime/doc/options.txt | 14 | ||||
-rw-r--r-- | runtime/doc/starting.txt | 4 | ||||
-rw-r--r-- | runtime/doc/syntax.txt | 6 | ||||
-rw-r--r-- | runtime/doc/various.txt | 7 | ||||
-rw-r--r-- | runtime/nvim.appdata.xml | 37 | ||||
-rw-r--r-- | runtime/plugin/rplugin.vim | 30 | ||||
-rw-r--r-- | runtime/syntax/help.vim | 1 | ||||
-rw-r--r-- | runtime/syntax/vim.vim | 2 | ||||
-rwxr-xr-x | scripts/genappimage.sh | 2 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 18 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 279 | ||||
-rw-r--r-- | src/nvim/os/env.c | 2 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 12 | ||||
-rw-r--r-- | test/README.md | 2 | ||||
-rw-r--r-- | test/functional/legacy/packadd_spec.lua | 88 |
21 files changed, 417 insertions, 220 deletions
@@ -44,6 +44,15 @@ Features See [`:help nvim-features`][nvim-features] for the full list! +Install from package +-------------------- + +Pre-built packages for Windows, macOS, and Linux are found on the +[Releases](https://github.com/neovim/neovim/releases/) page. + +Managed packages are in [Homebrew], [Debian], [Ubuntu], [Fedora], [Arch Linux], [Gentoo], +and [more](https://github.com/neovim/neovim/wiki/Installing-Neovim)! + Install from source ------------------- @@ -55,26 +64,36 @@ To install to a non-default location, set `CMAKE_INSTALL_PREFIX`: make CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=/full/path/" make install -To list all targets: - - cmake --build build --target help - -To skip "bundled" dependencies (`third-party/*`) define `USE_BUNDLED=NO`: - - sudo apt install gperf libluajit-5.1-dev libunibilium-dev libmsgpack-dev libtermkey-dev libvterm-dev libjemalloc-dev - make USE_BUNDLED=NO +To skip bundled (`third-party/*`) dependencies: + +1. Install the dependencies using a package manager. + ``` + sudo apt install gperf luajit luarocks libuv1-dev libluajit-5.1-dev libunibilium-dev libmsgpack-dev libtermkey-dev libvterm-dev libjemalloc-dev + sudo luarocks build mpack + sudo luarocks build lpeg + sudo luarocks build inspect + ``` +2. Build with `USE_BUNDLED=OFF`: + ``` + make CMAKE_BUILD_TYPE=RelWithDebInfo USE_BUNDLED=OFF + sudo make install + ``` + +CMake features: + +- List all build targets: + ``` + cmake --build build --target help + ``` +- Print all variable definitions: + ``` + cmake -LAH + ``` +- `build/CMakeCache.txt` contains the resolved values of all CMake variables. +- `build/compile_commands.json` shows the full compiler invocations for each translation unit. See the [Building Neovim](https://github.com/neovim/neovim/wiki/Building-Neovim) wiki page for details. -Install from package --------------------- - -Pre-built packages for Windows, macOS, and Linux are found on the -[Releases](https://github.com/neovim/neovim/releases/) page. - -Managed packages are in [Homebrew], [Debian], [Ubuntu], [Fedora], [Arch Linux], [Gentoo], -and [more](https://github.com/neovim/neovim/wiki/Installing-Neovim)! - Transitioning from Vim -------------------- diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 7dab69df22..2520a15890 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -546,25 +546,24 @@ nvim_set_current_tabpage({tabpage}) *nvim_set_current_tabpage()* {tabpage} Tabpage handle nvim_create_namespace({name}) *nvim_create_namespace()* - create a new namespace, or get one with an exisiting name + Creates a new namespace, or gets an existing one - Namespaces are currently used for buffer highlighting and - virtual text, see |nvim_buf_add_highlight| and - |nvim_buf_set_virtual_text|. + Namespaces are used for buffer highlights and virtual text, + see |nvim_buf_add_highlight()| and + |nvim_buf_set_virtual_text()|. - Namespaces can have a name of be anonymous. If `name` is a - non-empty string, and a namespace already exists with that - name,the existing namespace id is returned. If an empty string - is used, a new anonymous namespace is returned. + Namespaces can be named or anonymous. If `name` matches an + existing namespace, the associated id is returned. If `name` + is an empty string a new, anonymous namespace is created. Parameters: ~ - {name} Name of the namespace or empty string + {name} Namespace name or empty string Return: ~ - the namespace id + Namespace id nvim_get_namespaces() *nvim_get_namespaces()* - Get existing named namespaces + Gets existing, non-anonymous namespaces Return: ~ dict that maps from names to namespace ids. diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index 2c919f9104..e244072c66 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -137,6 +137,13 @@ DOCUMENTATION *dev-doc* "the user host terminal". - Use "tui-" to prefix help tags related to the host terminal, and "TUI" in prose if possible. +- Docstrings: do not start parameter descriptions with "The" or "A" unless it + is critical to avoid ambiguity. + GOOD: > + /// @param dirname Path fragment before `pend` +< BAD: > + /// @param dirname The path fragment before `pend` +< API *dev-api* diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 6dffd6f05e..e9579d5c86 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1886,8 +1886,6 @@ v:termresponse The escape sequence returned by the terminal for the DA *v:testing* *testing-variable* v:testing Must be set before using `test_garbagecollect_now()`. - Also, when set certain error messages won't be shown for 2 - seconds. (e.g. "'dictionary' option is empty") *v:this_session* *this_session-variable* v:this_session Full filename of the last loaded or saved session file. See @@ -2781,7 +2779,7 @@ changenr() *changenr()* redo it is the number of the redone change. After undo it is one less than the number of the undone change. -chanclose({id}[, {stream}]) {Nvim} *chanclose()* +chanclose({id}[, {stream}]) *chanclose()* Close a channel or a specific stream associated with it. For a job, {stream} can be one of "stdin", "stdout", "stderr" or "rpc" (closes stdin/stdout for a job started @@ -2791,7 +2789,7 @@ chanclose({id}[, {stream}]) {Nvim} *chanclose()* For a socket, there is only one stream, and {stream} should be ommited. -chansend({id}, {data}) {Nvim} *chansend()* +chansend({id}, {data}) *chansend()* Send data to channel {id}. For a job, it writes it to the stdin of the process. For the stdio channel |channel-stdio|, it writes to Nvim's stdout. Returns the number of bytes @@ -3822,8 +3820,7 @@ garbagecollect([{atexit}]) *garbagecollect()* The garbage collection is not done immediately but only when it's safe to perform. This is when waiting for the user to - type a character. To force garbage collection immediately use - |test_garbagecollect_now()|. + type a character. get({list}, {idx} [, {default}]) *get()* Get item {idx} from |List| {list}. When this item is not @@ -5728,7 +5725,7 @@ mkdir({name} [, {path} [, {prot}]]) the new directory. The default is 0755 (rwxr-xr-x: r/w for the user readable for others). Use 0700 to make it unreadable for others. - {Nvim} + {prot} is applied for all parts of {name}. Thus if you create /tmp/foo/bar then /tmp/foo will be created with 0700. Example: > :call mkdir($HOME . "/tmp/foo/bar", "p", 0700) @@ -5771,7 +5768,7 @@ mode([expr]) Return a string that indicates the current mode. "c" or "n". Also see |visualmode()|. -msgpackdump({list}) {Nvim} *msgpackdump()* +msgpackdump({list}) *msgpackdump()* Convert a list of VimL objects to msgpack. Returned value is |readfile()|-style list. Example: > call writefile(msgpackdump([{}]), 'fname.mpack', 'b') @@ -5786,7 +5783,7 @@ msgpackdump({list}) {Nvim} *msgpackdump()* 4. Other strings are always dumped as BIN strings. 5. Points 3. and 4. do not apply to |msgpack-special-dict|s. -msgpackparse({list}) {Nvim} *msgpackparse()* +msgpackparse({list}) *msgpackparse()* Convert a |readfile()|-style list to a list of VimL objects. Example: > let fname = expand('~/.config/nvim/shada/main.shada') @@ -6404,25 +6401,25 @@ round({expr}) *round()* echo round(-4.5) < -5.0 -rpcnotify({channel}, {event}[, {args}...]) {Nvim} *rpcnotify()* +rpcnotify({channel}, {event}[, {args}...]) *rpcnotify()* Sends {event} to {channel} via |RPC| and returns immediately. If {channel} is 0, the event is broadcast to all channels. Example: > :au VimLeave call rpcnotify(0, "leaving") -rpcrequest({channel}, {method}[, {args}...]) {Nvim} *rpcrequest()* +rpcrequest({channel}, {method}[, {args}...]) *rpcrequest()* Sends a request to {channel} to invoke {method} via |RPC| and blocks until a response is received. Example: > :let result = rpcrequest(rpc_chan, "func", 1, 2, 3) -rpcstart({prog}[, {argv}]) {Nvim} *rpcstart()* +rpcstart({prog}[, {argv}]) *rpcstart()* Deprecated. Replace > :let id = rpcstart('prog', ['arg1', 'arg2']) < with > :let id = jobstart(['prog', 'arg1', 'arg2'], {'rpc': v:true}) -rpcstop({channel}) {Nvim} *rpcstop()* +rpcstop({channel}) *rpcstop()* Deprecated. Instead use |jobstop()| to stop any job, and chanclose(id, "rpc") to close RPC communication without stopping the job. Use chanclose(id) to close any socket. @@ -7889,7 +7886,7 @@ tempname() *tempname()* *temp-file-name* For MS-Windows forward slashes are used when the 'shellslash' option is set or when 'shellcmdflag' starts with '-'. -termopen({cmd}[, {opts}]) {Nvim} *termopen()* +termopen({cmd}[, {opts}]) *termopen()* Spawns {cmd} in a new pseudo-terminal session connected to the current buffer. {cmd} is the same as the one passed to |jobstart()|. This function fails if the current buffer is @@ -7904,7 +7901,7 @@ termopen({cmd}[, {opts}]) {Nvim} *termopen()* See |terminal| for more information. test_garbagecollect_now() *test_garbagecollect_now()* - Like garbagecollect(), but executed right away. This must + Like |garbagecollect()|, but executed right away. This must only be called directly to avoid any structure to exist internally, and |v:testing| must have been set before calling any function. diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt index 81a7816c93..2da2e5147b 100644 --- a/runtime/doc/if_pyth.txt +++ b/runtime/doc/if_pyth.txt @@ -6,7 +6,7 @@ The Python Interface to Vim *if_pyth* *python* *Python* -See |provider-python| for more information. {Nvim} +See |provider-python| for more information. Type |gO| to see the table of contents. @@ -722,26 +722,5 @@ You can test what Python version is available with: > echo 'there is Python 3.x' endif -Note however, that if Python 2 and 3 are both available, but not loaded, -these has() calls will try to load them. - -To avoid loading the dynamic library, only check if Vim was compiled with -python support: > - if has('python_compiled') - echo 'compiled with Python 2.x support' - if has('python_dynamic') - echo 'Python 2.x dynamically loaded' - endif - endif - if has('python3_compiled') - echo 'compiled with Python 3.x support' - if has('python3_dynamic') - echo 'Python 3.x dynamically loaded' - endif - endif - -This also tells you whether Python is dynamically loaded, which will fail if -the runtime library cannot be found. - ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 81eeae80ed..f22f90548b 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1429,7 +1429,7 @@ automatically switch to HTML/CSS/JavaScript completion. Note: contrary to original HTML files completion of tags (and only tags) isn't context aware. -RUBY *ft-ruby-omni* {Nvim} +RUBY *ft-ruby-omni* NOTE: |compl-omni| for Ruby code requires |provider-ruby| to be installed. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 9aaae6a527..534b2025cd 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -459,7 +459,7 @@ For example, to use a modeline only for Vim 7.0: To use a modeline for Vim after version 7.2: /* vim>702: set cole=2: */ ~ There can be no blanks between "vim" and the ":". -The modeline is ignored if {vers} does not fit in an integer. {Nvim} +The modeline is ignored if {vers} does not fit in an integer. The number of lines that are checked can be set with the 'modelines' option. @@ -908,13 +908,13 @@ A jump table for the options with a short description can be found at |Q_op|. the newly created file). Also see 'backupcopy' and |crontab|. *'balloondelay'* *'bdlay'* -'balloondelay' 'bdlay' Removed. {Nvim} +'balloondelay' 'bdlay' Removed. *'ballooneval'* *'beval'* *'noballooneval'* *'nobeval'* -'ballooneval' 'beval' Removed. {Nvim} +'ballooneval' 'beval' Removed. *'balloonexpr'* *'bexpr'* -'balloonexpr' 'bexpr' Removed. {Nvim} +'balloonexpr' 'bexpr' Removed. *'belloff'* *'bo'* 'belloff' 'bo' string (default "all") @@ -3475,7 +3475,7 @@ A jump table for the options with a short description can be found at |Q_op|. help. (Note that previously setting the global option to the empty value did this, which is now deprecated.) When the first character is ":", the command is invoked as a Vim - command prefixed with [count]. {Nvim} + command prefixed with [count]. When "man" or "man -s" is used, Vim will automatically translate a [count] for the "K" command to a section number. See |option-backslash| about including spaces and backslashes. @@ -3795,7 +3795,7 @@ A jump table for the options with a short description can be found at |Q_op|. set a time. This is to be compatible with Nvi. *'maxcombine'* *'mco'* -'maxcombine' 'mco' Removed. |vim-differences| {Nvim} +'maxcombine' 'mco' Removed. |vim-differences| Nvim always displays up to 6 combining characters. You can still edit text with more than 6 combining characters, you just can't see them. Use |g8| or |ga|. See |mbyte-combining|. @@ -6219,7 +6219,7 @@ A jump table for the options with a short description can be found at |Q_op|. to be garbled (e.g., when it contains a CR or NL character). *'ttyfast'* *'tf'* *'nottyfast'* *'notf'* -'ttyfast' 'tf' Removed. |vim-differences| {Nvim} +'ttyfast' 'tf' Removed. |vim-differences| *'undodir'* *'udir'* *E5003* 'undodir' 'udir' string (default "$XDG_DATA_HOME/nvim/undo") diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 82e73035d8..12794b6cc0 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -1025,7 +1025,7 @@ Use the "r" flag in 'shada' to specify for which files no marks should be remembered. MERGING *shada-merging* - {Nvim} + When writing ShaDa files with |:wshada| without bang or at regular exit information in the existing ShaDa file is merged with information from current Neovim instance. For this purpose ShaDa files store timestamps associated @@ -1055,7 +1055,7 @@ with ShaDa entries. Specifically the following is being done: Neovim instance which was last writing the file. |shada-%| COMPATIBILITY *shada-compatibility* - {Nvim} + ShaDa files are forward and backward compatible. This means that 1. Entries which have unknown type (i.e. that hold unidentified data) are diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 4c3c7d329a..684830b78d 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -4907,12 +4907,12 @@ DiffChange diff mode: Changed line |diff.txt| DiffDelete diff mode: Deleted line |diff.txt| *hl-DiffText* DiffText diff mode: Changed text within a changed line |diff.txt| - {Nvim} *hl-EndOfBuffer* + *hl-EndOfBuffer* EndOfBuffer filler lines (~) after the end of the buffer. By default, this is highlighted like |hl-NonText|. - {Nvim} *hl-TermCursor* + *hl-TermCursor* TermCursor cursor in a focused terminal - {Nvim} *hl-TermCursorNC* + *hl-TermCursorNC* TermCursorNC cursor in an unfocused terminal *hl-ErrorMsg* ErrorMsg error messages on the command line diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index d78dd90f18..dbbafd1576 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -215,11 +215,12 @@ g8 Print the hex values of the bytes used in the ":normal" command without a range. *:sh* *:shell* *E371* *E360* -:sh[ell] Removed. |vim-differences| {Nvim} +:sh[ell] Removed. |vim-differences| *:terminal* *:te* -:te[rminal][!] [{cmd}] Execute {cmd} with 'shell' in a new |terminal-emulator| - buffer. Without {cmd}, start an interactive 'shell'. +:te[rminal][!] [{cmd}] Run {cmd} in a non-interactive 'shell' in a new + |terminal-emulator| buffer. Without {cmd}, start an + interactive 'shell'. Type |i| to enter |Terminal-mode|, then keys are sent to the job running in the terminal. Type <C-\><C-N> to diff --git a/runtime/nvim.appdata.xml b/runtime/nvim.appdata.xml new file mode 100644 index 0000000000..095e6c6fa8 --- /dev/null +++ b/runtime/nvim.appdata.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2018 Neovim contributors + + See also: + https://appimage.github.io/neovim/ + https://github.com/flathub/io.neovim.nvim +--> +<component type="desktop-application"> + <id>nvim</id> + <project_license>Apache-2.0</project_license> + <metadata_license>CC0-1.0</metadata_license> + <name>Neovim</name> + <summary>Vim-fork focused on extensibility and usability</summary> + + <description> + <p>Neovim is a refactor of the Vim text editor designed to encourage new features, advanced UIs, and powerful extensions.</p> + </description> + + <screenshots> + <screenshot type="default"> + <caption>Live :substitute feature</caption> + <image>https://neovim.io/images/nvim-screenshot-1.png</image> + </screenshot> + </screenshots> + + <launchable type="desktop-id">nvim.desktop</launchable> + <url type="homepage">https://neovim.io/</url> + <url type="bugtracker">https://github.com/neovim/neovim/issues</url> + <url type="faq">https://github.com/neovim/neovim/wiki/FAQ</url> + <url type="help">https://neovim.io/doc/</url> + <url type="donation">https://neovim.io/#sponsor</url> + <url type="translate">https://github.com/neovim/neovim/tree/master/src/nvim/po</url> + <provides> + <binary>nvim</binary> + </provides> +</component> diff --git a/runtime/plugin/rplugin.vim b/runtime/plugin/rplugin.vim index 56163c894e..122d8d47f8 100644 --- a/runtime/plugin/rplugin.vim +++ b/runtime/plugin/rplugin.vim @@ -11,14 +11,8 @@ function! s:GetManifestPath() abort return fnamemodify($NVIM_RPLUGIN_MANIFEST, ':p') endif - let dest = has('win32') ? '$LOCALAPPDATA' : '$XDG_DATA_HOME' - if !exists(dest) - let dest = has('win32') ? '~/AppData/Local' : '~/.local/share' - endif - - let dest = fnamemodify(expand(dest), ':p') + let dest = stdpath('data') if !empty(dest) - let dest .= ('/' ==# dest[-1:] ? '' : '/') . 'nvim' if !isdirectory(dest) call mkdir(dest, 'p', 0700) endif @@ -29,22 +23,32 @@ function! s:GetManifestPath() abort endfunction " Old manifest file based on known script locations. -function! s:GetOldManifestPath() abort +function! s:GetOldManifestPaths() abort let prefix = exists('$MYVIMRC') \ ? $MYVIMRC \ : matchstr(get(split(execute('scriptnames'), '\n'), 0, ''), '\f\+$') - return fnamemodify(expand(prefix, 1), ':h') + let origpath = fnamemodify(expand(prefix, 1), ':h') \.'/.'.fnamemodify(prefix, ':t').'-rplugin~' + if !has('win32') + return [origpath] + endif + " Windows used to use $APPLOCALDATA/nvim but stdpath('data') is + " $XDG_DATA_DIR/nvim-data + let pseudostdpath = exists('$LOCALAPPDATA') ? '$LOCALAPPDATA' : '~/AppData/Local' + let pseudostdpath = fnamemodify(expand(pseudostdpath), ':p') + return [substitute(pseudostdpath, '[/\\]\=$', '/', '') . 'nvim/rplugin.vim', origpath] endfunction function! s:GetManifest() abort let manifest = s:GetManifestPath() if !filereadable(manifest) " Check if an old manifest file exists and move it to the new location. - let old_manifest = s:GetOldManifestPath() - if filereadable(old_manifest) - call rename(old_manifest, manifest) - endif + for old_manifest in s:GetOldManifestPaths() + if filereadable(old_manifest) + call rename(old_manifest, manifest) + break + endif + endfor endif return manifest endfunction diff --git a/runtime/syntax/help.vim b/runtime/syntax/help.vim index 972970f619..db5ad3728c 100644 --- a/runtime/syntax/help.vim +++ b/runtime/syntax/help.vim @@ -36,7 +36,6 @@ syn match helpNormal "|||" syn match helpNormal ":|vim:|" " for :help modeline syn match helpVim "\<Vim version [0-9][0-9.a-z]*" syn match helpVim "VIM REFERENCE.*" -syn match helpVim "\<Nvim\." syn match helpVim "NVIM REFERENCE.*" syn match helpOption "'[a-z]\{2,\}'" syn match helpOption "'t_..'" diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index 5dc4f333e4..444b6d8d17 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -397,7 +397,7 @@ syn match vimMenuBang "!" contained skipwhite nextgroup=@vimMenuList " Angle-Bracket Notation (tnx to Michael Geddes) {{{2 " ====================== syn case ignore -syn match vimNotation "\%#=1\(\\\|<lt>\)\=<\([scamd]-\)\{0,4}x\=\(f\d\{1,2}\|[^ \t:]\|cr\|lf\|linefeed\|return\|k\=del\%[ete]\|bs\|backspace\|tab\|esc\|right\|left\|help\|undo\|insert\|ins\|mouse\|k\=home\|k\=end\|kplus\|kminus\|kdivide\|kmultiply\|kenter\|kpoint\|space\|k\=\(page\)\=\(\|down\|up\|k\d\>\)\)>" contains=vimBracket +syn match vimNotation "\%#=1\(\\\|<lt>\)\=<\([scamd]-\)\{0,4}x\=\(f\d\{1,2}\|[^ \t:]\|cmd\|cr\|lf\|linefeed\|return\|k\=del\%[ete]\|bs\|backspace\|tab\|esc\|right\|left\|help\|undo\|insert\|ins\|mouse\|k\=home\|k\=end\|kplus\|kminus\|kdivide\|kmultiply\|kenter\|kpoint\|space\|k\=\(page\)\=\(\|down\|up\|k\d\>\)\)>" contains=vimBracket syn match vimNotation "\%#=1\(\\\|<lt>\)\=<\([scam2-4]-\)\{0,4}\(right\|left\|middle\)\(mouse\)\=\(drag\|release\)\=>" contains=vimBracket syn match vimNotation "\%#=1\(\\\|<lt>\)\=<\(bslash\|plug\|sid\|space\|bar\|nop\|nul\|lt\)>" contains=vimBracket syn match vimNotation '\(\\\|<lt>\)\=<C-R>[0-9a-z"%#:.\-=]'he=e-1 contains=vimBracket diff --git a/scripts/genappimage.sh b/scripts/genappimage.sh index ed008938f3..c0ef2a8591 100755 --- a/scripts/genappimage.sh +++ b/scripts/genappimage.sh @@ -45,6 +45,8 @@ curl -Lo "$APP_BUILD_DIR"/appimage_functions.sh https://github.com/AppImage/AppI # get_desktop cp "$ROOT_DIR/runtime/nvim.desktop" "$APP_DIR/" cp "$ROOT_DIR/runtime/nvim.png" "$APP_DIR/" +mkdir "$APP_DIR/usr/share/metainfo/" +cp "$ROOT_DIR/runtime/nvim.appdata.xml" "$APP_DIR/usr/share/metainfo/" cd "$APP_DIR" diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 4da61a30ef..ecfff1ea8f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -905,17 +905,17 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) } } -/// create a new namespace, or get one with an exisiting name +/// Creates a new namespace, or gets an existing one /// -/// Namespaces are currently used for buffer highlighting and virtual text, see -/// |nvim_buf_add_highlight| and |nvim_buf_set_virtual_text|. +/// Namespaces are used for buffer highlights and virtual text, see +/// |nvim_buf_add_highlight()| and |nvim_buf_set_virtual_text()|. /// -/// Namespaces can have a name of be anonymous. If `name` is a non-empty string, -/// and a namespace already exists with that name,the existing namespace id is -/// returned. If an empty string is used, a new anonymous namespace is returned. +/// Namespaces can be named or anonymous. If `name` matches an existing +/// namespace, the associated id is returned. If `name` is an empty string +/// a new, anonymous namespace is created. /// -/// @param name Name of the namespace or empty string -/// @return the namespace id +/// @param name Namespace name or empty string +/// @return Namespace id Integer nvim_create_namespace(String name) FUNC_API_SINCE(5) { @@ -931,7 +931,7 @@ Integer nvim_create_namespace(String name) return (Integer)id; } -/// Get existing named namespaces +/// Gets existing, non-anonymous namespaces /// /// @return dict that maps from names to namespace ids. Dictionary nvim_get_namespaces(void) diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index c9b6d19aaa..1ffcf67ef7 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -2536,48 +2536,50 @@ static void source_all_matches(char_u *pat) } } -// used for "cookie" of add_pack_plugin() -static int APP_ADD_DIR; -static int APP_LOAD; -static int APP_BOTH; - -static void add_pack_plugin(char_u *fname, void *cookie) +/// Add the package directory to 'runtimepath' +static int add_pack_dir_to_rtp(char_u *fname) { char_u *p4, *p3, *p2, *p1, *p; char_u *buf = NULL; + char *afterdir = NULL; + int retval = FAIL; + p4 = p3 = p2 = p1 = get_past_head(fname); + for (p = p1; *p; MB_PTR_ADV(p)) { + if (vim_ispathsep_nocolon(*p)) { + p4 = p3; p3 = p2; p2 = p1; p1 = p; + } + } + + // now we have: + // rtp/pack/name/start/name + // p4 p3 p2 p1 + // + // find the part up to "pack" in 'runtimepath' + p4++; // append pathsep in order to expand symlink + char_u c = *p4; + *p4 = NUL; char *const ffname = fix_fname((char *)fname); + *p4 = c; if (ffname == NULL) { - return; + return FAIL; } - if (cookie != &APP_LOAD && strstr((char *)p_rtp, ffname) == NULL) { - // directory is not yet in 'runtimepath', add it - p4 = p3 = p2 = p1 = get_past_head((char_u *)ffname); - for (p = p1; *p; MB_PTR_ADV(p)) { - if (vim_ispathsep_nocolon(*p)) { - p4 = p3; p3 = p2; p2 = p1; p1 = p; - } - } - - // now we have: - // rtp/pack/name/start/name - // p4 p3 p2 p1 - // - // find the part up to "pack" in 'runtimepath' - char_u c = *p4; - *p4 = NUL; + // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences + // Also stop at the first "after" directory + size_t fname_len = strlen(ffname); + buf = try_malloc(MAXPATHL); + if (buf == NULL) { + goto theend; + } + const char *insp = NULL; + const char *after_insp = NULL; + for (const char *entry = (const char *)p_rtp; *entry != NUL; ) { + const char *cur_entry = entry; - // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences - size_t fname_len = strlen(ffname); - const char *insp = (const char *)p_rtp; - buf = try_malloc(MAXPATHL); - if (buf == NULL) { - goto theend; - } - while (*insp != NUL) { - copy_option_part((char_u **)&insp, buf, MAXPATHL, ","); + copy_option_part((char_u **)&entry, buf, MAXPATHL, ","); + if (insp == NULL) { add_pathsep((char *)buf); char *const rtp_ffname = fix_fname((char *)buf); if (rtp_ffname == NULL) { @@ -2586,87 +2588,164 @@ static void add_pack_plugin(char_u *fname, void *cookie) bool match = path_fnamencmp(rtp_ffname, ffname, fname_len) == 0; xfree(rtp_ffname); if (match) { - break; + // Insert "ffname" after this entry (and comma). + insp = entry; } } - if (*insp == NUL) { - // not found, append at the end - insp = (const char *)p_rtp + STRLEN(p_rtp); - } else { - // append after the matching directory. - insp--; - } - *p4 = c; - - // check if rtp/pack/name/start/name/after exists - char *afterdir = concat_fnames(ffname, "after", true); - size_t afterlen = 0; - if (os_isdir((char_u *)afterdir)) { - afterlen = strlen(afterdir) + 1; // add one for comma - } - - const size_t oldlen = STRLEN(p_rtp); - const size_t addlen = strlen(ffname) + 1; // add one for comma - const size_t new_rtp_len = oldlen + addlen + afterlen + 1; - // add one for NUL -------------------------------------^ - char *const new_rtp = try_malloc(new_rtp_len); - if (new_rtp == NULL) { - goto theend; - } - const size_t keep = (size_t)(insp - (const char *)p_rtp); - size_t new_rtp_fill = 0; - memmove(new_rtp, p_rtp, keep); - new_rtp_fill += keep; - new_rtp[new_rtp_fill++] = ','; - memmove(new_rtp + new_rtp_fill, ffname, addlen); - new_rtp_fill += addlen - 1; - assert(new_rtp[new_rtp_fill] == NUL || new_rtp[new_rtp_fill] == ','); - if (p_rtp[keep] != NUL) { - memmove(new_rtp + new_rtp_fill, p_rtp + keep, oldlen - keep + 1); - new_rtp_fill += oldlen - keep; - } - if (afterlen > 0) { - assert(new_rtp[new_rtp_fill] == NUL); - new_rtp[new_rtp_fill++] = ','; - memmove(new_rtp + new_rtp_fill, afterdir, afterlen - 1); - new_rtp_fill += afterlen - 1; - } - new_rtp[new_rtp_fill] = NUL; - set_option_value("rtp", 0L, new_rtp, 0); - xfree(new_rtp); - xfree(afterdir); + if ((p = (char_u *)strstr((char *)buf, "after")) != NULL + && p > buf + && vim_ispathsep(p[-1]) + && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',')) { + if (insp == NULL) { + // Did not find "ffname" before the first "after" directory, + // insert it before this entry. + insp = cur_entry; + } + after_insp = cur_entry; + break; + } } - if (cookie != &APP_ADD_DIR) { - static const char *plugpat = "%s/plugin/**/*.vim"; // NOLINT - static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT + if (insp == NULL) { + // Both "fname" and "after" not found, append at the end. + insp = (const char *)p_rtp + STRLEN(p_rtp); + } - size_t len = strlen(ffname) + STRLEN(ftpat); - char_u *pat = try_malloc(len + 1); - if (pat == NULL) { - goto theend; - } - vim_snprintf((char *)pat, len, plugpat, ffname); - source_all_matches(pat); + // check if rtp/pack/name/start/name/after exists + afterdir = concat_fnames((char *)fname, "after", true); + size_t afterlen = 0; + if (os_isdir((char_u *)afterdir)) { + afterlen = strlen(afterdir) + 1; // add one for comma + } - char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes"); + const size_t oldlen = STRLEN(p_rtp); + const size_t addlen = STRLEN(fname) + 1; // add one for comma + const size_t new_rtp_capacity = oldlen + addlen + afterlen + 1; + // add one for NUL ------------------------------------------^ + char *const new_rtp = try_malloc(new_rtp_capacity); + if (new_rtp == NULL) { + goto theend; + } - // If runtime/filetype.vim wasn't loaded yet, the scripts will be - // found when it loads. - if (eval_to_number(cmd) > 0) { - do_cmdline_cmd("augroup filetypedetect"); - vim_snprintf((char *)pat, len, ftpat, ffname); - source_all_matches(pat); - do_cmdline_cmd("augroup END"); - } - xfree(cmd); - xfree(pat); + // We now have 'rtp' parts: {keep}{keep_after}{rest}. + // Create new_rtp, first: {keep},{fname} + size_t keep = (size_t)(insp - (const char *)p_rtp); + memmove(new_rtp, p_rtp, keep); + size_t new_rtp_len = keep; + if (*insp == NUL) { + new_rtp[new_rtp_len++] = ','; // add comma before + } + memmove(new_rtp + new_rtp_len, fname, addlen - 1); + new_rtp_len += addlen - 1; + if (*insp != NUL) { + new_rtp[new_rtp_len++] = ','; // add comma after + } + + if (afterlen > 0 && after_insp != NULL) { + size_t keep_after = (size_t)(after_insp - (const char *)p_rtp); + + // Add to new_rtp: {keep},{fname}{keep_after},{afterdir} + memmove(new_rtp + new_rtp_len, p_rtp + keep, keep_after - keep); + new_rtp_len += keep_after - keep; + memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1); + new_rtp_len += afterlen - 1; + new_rtp[new_rtp_len++] = ','; + keep = keep_after; + } + + if (p_rtp[keep] != NUL) { + // Append rest: {keep},{fname}{keep_after},{afterdir}{rest} + memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1); + } else { + new_rtp[new_rtp_len] = NUL; + } + + if (afterlen > 0 && after_insp == NULL) { + // Append afterdir when "after" was not found: + // {keep},{fname}{rest},{afterdir} + xstrlcat(new_rtp, ",", new_rtp_capacity); + xstrlcat(new_rtp, afterdir, new_rtp_capacity); } + set_option_value("rtp", 0L, new_rtp, 0); + xfree(new_rtp); + retval = OK; + theend: xfree(buf); xfree(ffname); + xfree(afterdir); + return retval; +} + +/// Load scripts in "plugin" and "ftdetect" directories of the package. +static int load_pack_plugin(char_u *fname) +{ + static const char *plugpat = "%s/plugin/**/*.vim"; // NOLINT + static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT + + int retval = FAIL; + char *const ffname = fix_fname((char *)fname); + size_t len = strlen(ffname) + STRLEN(ftpat); + char_u *pat = try_malloc(len + 1); + if (pat == NULL) { + goto theend; + } + vim_snprintf((char *)pat, len, plugpat, ffname); + source_all_matches(pat); + + char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes"); + + // If runtime/filetype.vim wasn't loaded yet, the scripts will be + // found when it loads. + if (eval_to_number(cmd) > 0) { + do_cmdline_cmd("augroup filetypedetect"); + vim_snprintf((char *)pat, len, ftpat, ffname); + source_all_matches(pat); + do_cmdline_cmd("augroup END"); + } + xfree(cmd); + xfree(pat); + retval = OK; + +theend: + xfree(ffname); + + return retval; +} + +// used for "cookie" of add_pack_plugin() +static int APP_ADD_DIR; +static int APP_LOAD; +static int APP_BOTH; + +static void add_pack_plugin(char_u *fname, void *cookie) +{ + if (cookie != &APP_LOAD) { + char *buf = xmalloc(MAXPATHL); + bool found = false; + + const char *p = (const char *)p_rtp; + while (*p != NUL) { + copy_option_part((char_u **)&p, (char_u *)buf, MAXPATHL, ","); + if (path_fnamecmp(buf, (char *)fname) == 0) { + found = true; + break; + } + } + xfree(buf); + if (!found) { + // directory is not yet in 'runtimepath', add it + if (add_pack_dir_to_rtp(fname) == FAIL) { + return; + } + } + } + + if (cookie != &APP_ADD_DIR) { + load_pack_plugin(fname); + } } /// Add all packages in the "start" directory to 'runtimepath'. diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index fe01787f9e..c6794e4be5 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -779,7 +779,7 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char *homedir_env_mod = (char *)homedir_env; bool must_free = false; - if (homedir_env_mod != NULL && strchr(homedir_env_mod, '~') != NULL) { + if (homedir_env_mod != NULL && *homedir_env_mod == '~') { must_free = true; size_t usedlen = 0; size_t flen = strlen(homedir_env_mod); diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 426605b785..d1e456f185 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1589,9 +1589,9 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, unibi_set_if_empty(ut, unibi_exit_italics_mode, "\x1b[23m"); unibi_set_if_empty(ut, unibi_to_status_line, "\x1b]2"); unibi_set_if_empty(ut, unibi_from_status_line, "\x07"); - // 2017-04 terminfo.src has older control sequences. - unibi_set_str(ut, unibi_enter_ca_mode, "\x1b[?1049h"); - unibi_set_str(ut, unibi_exit_ca_mode, "\x1b[?1049l"); + // Enter/exit alternate screen with "title stacking". #4063 + unibi_set_str(ut, unibi_enter_ca_mode, "\x1b[?1049h\x1b[22;0;0t"); + unibi_set_str(ut, unibi_exit_ca_mode, "\x1b[?1049l\x1b[23;0;0t"); } else if (screen) { // per the screen manual; 2017-04 terminfo.src lacks these. unibi_set_if_empty(ut, unibi_to_status_line, "\x1b_"); @@ -1611,9 +1611,9 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, } else if (putty) { // No bugs in the vanilla terminfo for our purposes. } else if (iterm) { - // 2017-04 terminfo.src has older control sequences. - unibi_set_str(ut, unibi_enter_ca_mode, "\x1b[?1049h"); - unibi_set_str(ut, unibi_exit_ca_mode, "\x1b[?1049l"); + // Enter/exit alternate screen with "title stacking". #4063 + unibi_set_str(ut, unibi_enter_ca_mode, "\x1b[?1049h\x1b[22;0;0t"); + unibi_set_str(ut, unibi_exit_ca_mode, "\x1b[?1049l\x1b[23;0;0t"); // 2017-04 terminfo.src lacks these. unibi_set_if_empty(ut, unibi_set_tb_margin, "\x1b[%i%p1%d;%p2%dr"); unibi_set_if_empty(ut, unibi_orig_pair, "\x1b[39;49m"); diff --git a/test/README.md b/test/README.md index 1a5dc022f4..d3f421e8fc 100644 --- a/test/README.md +++ b/test/README.md @@ -205,7 +205,7 @@ Tests in `/test/unit` and `/test/functional` are divided into groups by the semantic component they are testing. - _Unit tests_ - ([test/unit](https://github.com/neovim/neovim/tree/master/test/unit)) should + ([test/unit](https://github.com/neovim/neovim/tree/master/test/unit)) should match 1-to-1 with the structure of `src/nvim/`, because they are testing functions directly. E.g. unit-tests for `src/nvim/undo.c` should live in `test/unit/undo_spec.lua`. diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua index 7c3d48317b..609f825177 100644 --- a/test/functional/legacy/packadd_spec.lua +++ b/test/functional/legacy/packadd_spec.lua @@ -14,6 +14,10 @@ describe('packadd', function() clear() source([=[ + func Escape(s) + return escape(a:s, '\~') + endfunc + func SetUp() let s:topdir = expand(getcwd() . '/Xdir') exe 'set packpath=' . s:topdir @@ -25,6 +29,11 @@ describe('packadd', function() endfunc func Test_packadd() + if !exists('s:plugdir') + echomsg 'when running this test manually, call SetUp() first' + return + endif + call mkdir(s:plugdir . '/plugin/also', 'p') call mkdir(s:plugdir . '/ftdetect', 'p') call mkdir(s:plugdir . '/after', 'p') @@ -32,6 +41,14 @@ describe('packadd', function() let rtp = &rtp filetype on + let rtp_entries = split(rtp, ',') + for entry in rtp_entries + if entry =~? '\<after\>' + let first_after_entry = entry + break + endif + endfor + exe 'split ' . s:plugdir . '/plugin/test.vim' call setline(1, 'let g:plugin_works = 42') wq @@ -50,8 +67,23 @@ describe('packadd', function() call assert_equal(77, g:plugin_also_works) call assert_true(17, g:ftdetect_works) call assert_true(len(&rtp) > len(rtp)) - call assert_true(&rtp =~ (escape(s:plugdir, '\') . '\($\|,\)')) - call assert_true(&rtp =~ escape(expand(s:plugdir . '/after$'), '\')) + call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp) + + let new_after = match(&rtp, Escape(expand(s:plugdir . '/after') . ',')) + let forwarded = substitute(first_after_entry, '\\', '[/\\\\]', 'g') + let old_after = match(&rtp, ',' . escape(forwarded, '~') . '\>') + call assert_true(new_after > 0, 'rtp is ' . &rtp) + call assert_true(old_after > 0, 'match ' . forwarded . ' in ' . &rtp) + call assert_true(new_after < old_after, 'rtp is ' . &rtp) + + " NOTE: '/.../opt/myte' forwardly matches with '/.../opt/mytest' + call mkdir(fnamemodify(s:plugdir, ':h') . '/myte', 'p') + let rtp = &rtp + packadd myte + + " Check the path of 'myte' is added + call assert_true(len(&rtp) > len(rtp)) + call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp) " Check exception call assert_fails("packadd directorynotfound", 'E919:') @@ -73,7 +105,7 @@ describe('packadd', function() call assert_equal(24, g:plugin_works) call assert_true(len(&rtp) > len(rtp)) - call assert_true(&rtp =~ (escape(plugdir, '\') . '\($\|,\)')) + call assert_match(Escape(plugdir) . '\($\|,\)', &rtp) endfunc func Test_packadd_noload() @@ -90,7 +122,7 @@ describe('packadd', function() packadd! mytest call assert_true(len(&rtp) > len(rtp)) - call assert_true(&rtp =~ (escape(s:plugdir, '\') . '\($\|,\)')) + call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp) call assert_equal(0, g:plugin_works) " check the path is not added twice @@ -122,7 +154,7 @@ describe('packadd', function() packadd mytest " Must have been inserted in the middle, not at the end - call assert_true(&rtp =~ escape(expand('/pack/mine/opt/mytest').',', '\')) + call assert_match(Escape(expand('/pack/mine/opt/mytest').','), &rtp) call assert_equal(44, g:plugin_works) " No change when doing it again. @@ -135,6 +167,48 @@ describe('packadd', function() exec "silent !" (has('win32') ? "rd /q/s" : "rm") top2_dir endfunc + func Test_packadd_symlink_dir2() + let top2_dir = expand(s:topdir . '/Xdir2') + let real_dir = expand(s:topdir . '/Xsym/pack') + call mkdir(top2_dir, 'p') + call mkdir(real_dir, 'p') + let &rtp = top2_dir . ',' . top2_dir . '/after' + let &packpath = &rtp + + if has('win32') + exec "silent! !mklink /d" top2_dir "Xsym" + else + exec "silent !ln -s ../Xsym/pack" top2_dir . '/pack' + endif + let s:plugdir = expand(top2_dir . '/pack/mine/opt/mytest') + call mkdir(s:plugdir . '/plugin', 'p') + + exe 'split ' . s:plugdir . '/plugin/test.vim' + call setline(1, 'let g:plugin_works = 48') + wq + let g:plugin_works = 0 + + packadd mytest + + " Must have been inserted in the middle, not at the end + call assert_match(Escape(expand('/Xdir2/pack/mine/opt/mytest').','), &rtp) + call assert_equal(48, g:plugin_works) + + " No change when doing it again. + let rtp_before = &rtp + packadd mytest + call assert_equal(rtp_before, &rtp) + + set rtp& + let rtp = &rtp + if has('win32') + exec "silent !rd /q/s" top2_dir + else + exec "silent !rm" top2_dir . '/pack' + exec "silent !rmdir" top2_dir + endif + endfunc + func Test_packloadall() " plugin foo with an autoload directory let fooplugindir = &packpath . '/pack/mine/start/foo/plugin' @@ -190,9 +264,9 @@ describe('packadd', function() helptags ALL let tags1 = readfile(docdir1 . '/tags') - call assert_true(tags1[0] =~ 'look-here') + call assert_match('look-here', tags1[0]) let tags2 = readfile(docdir2 . '/tags') - call assert_true(tags2[0] =~ 'look-away') + call assert_match('look-away', tags2[0]) endfunc func Test_colorscheme() |