aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml27
-rw-r--r--.github/workflows/release.yml31
-rw-r--r--.travis.yml38
-rw-r--r--README.md1
-rw-r--r--appveyor.yml39
-rw-r--r--ci/build.ps138
-rw-r--r--contrib/flake.nix2
-rw-r--r--runtime/doc/api.txt2
-rw-r--r--runtime/doc/change.txt10
-rw-r--r--runtime/doc/lsp.txt4
-rw-r--r--runtime/filetype.vim3
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua4
-rw-r--r--runtime/lua/vim/lsp/handlers.lua39
-rw-r--r--runtime/lua/vim/lsp/protocol.lua10
-rw-r--r--src/nvim/arabic.c4
-rw-r--r--src/nvim/ascii.h12
-rw-r--r--src/nvim/buffer.c21
-rw-r--r--src/nvim/diff.c5
-rw-r--r--src/nvim/edit.c27
-rw-r--r--src/nvim/eval.c38
-rw-r--r--src/nvim/eval/funcs.c6
-rw-r--r--src/nvim/eval/userfunc.c4
-rw-r--r--src/nvim/ex_cmds.c15
-rw-r--r--src/nvim/ex_cmds2.c10
-rw-r--r--src/nvim/ex_docmd.c36
-rw-r--r--src/nvim/ex_getln.c14
-rw-r--r--src/nvim/ex_session.c34
-rw-r--r--src/nvim/fileio.c18
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/memline.c6
-rw-r--r--src/nvim/move.c552
-rw-r--r--src/nvim/msgpack_rpc/channel.c6
-rw-r--r--src/nvim/normal.c40
-rw-r--r--src/nvim/ops.c44
-rw-r--r--src/nvim/option.c9
-rw-r--r--src/nvim/options.lua1
-rw-r--r--src/nvim/popupmnu.c2
-rw-r--r--src/nvim/quickfix.c4
-rw-r--r--src/nvim/regexp.c7
-rw-r--r--src/nvim/regexp_nfa.c3
-rw-r--r--src/nvim/screen.c16
-rw-r--r--src/nvim/sign.c70
-rw-r--r--src/nvim/sign_defs.h16
-rw-r--r--src/nvim/syntax.c35
-rw-r--r--src/nvim/testdir/check.vim11
-rw-r--r--src/nvim/testdir/test_clientserver.vim9
-rw-r--r--src/nvim/testdir/test_cmdline.vim111
-rw-r--r--src/nvim/testdir/test_digraph.vim22
-rw-r--r--src/nvim/testdir/test_filetype.vim1
-rw-r--r--src/nvim/testdir/test_global.vim11
-rw-r--r--src/nvim/testdir/test_mksession.vim169
-rw-r--r--src/nvim/testdir/test_registers.vim50
-rw-r--r--src/nvim/testdir/test_signs.vim8
-rw-r--r--src/nvim/testdir/test_tabpage.vim107
-rw-r--r--src/nvim/testdir/test_window_cmd.vim8
-rw-r--r--src/nvim/window.c39
-rw-r--r--test/functional/api/server_notifications_spec.lua16
-rw-r--r--test/functional/provider/clipboard_spec.lua8
-rw-r--r--test/functional/ui/searchhl_spec.lua29
-rw-r--r--test/functional/ui/sign_spec.lua66
61 files changed, 1336 insertions, 636 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fcd6114d65..3653f04d5d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,9 +6,10 @@ on:
branches: 'master'
jobs:
- build:
+ unixish:
name: ${{ matrix.os }} ${{ matrix.flavor }} (cc=${{ matrix.cc }})
strategy:
+ fail-fast: false
matrix:
include:
- flavor: asan
@@ -82,3 +83,27 @@ jobs:
- name: Cache dependencies
if: ${{ success() }}
run: ./ci/before_cache.sh
+
+ windows:
+ runs-on: windows-2016
+ env:
+ DEPS_BUILD_DIR: "C:/projects/nvim-deps"
+ DEPS_PREFIX: "C:/projects/nvim-deps/usr"
+
+ strategy:
+ fail-fast: false
+ matrix:
+ config: [ MINGW_64-gcov, MINGW_32, MSVC_64, MSVC_32 ]
+ name: windows (${{ matrix.config }})
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: actions/cache@v2
+ with:
+ path: C:\projects\nvim-deps
+ key: ${{ matrix.config }}-${{ hashFiles('third-party\**') }}
+
+ - name: Run CI
+ run: powershell ci\build.ps1
+ env:
+ CONFIGURATION: ${{ matrix.config }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6905f8dd35..7587f62e59 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -105,8 +105,35 @@ jobs:
path: build/release/nvim-macos.tar.gz
retention-days: 1
+ windows:
+ runs-on: windows-2016
+ env:
+ DEPS_BUILD_DIR: "C:/projects/nvim-deps"
+ DEPS_PREFIX: "C:/projects/nvim-deps/usr"
+ strategy:
+ matrix:
+ include:
+ - config: MSVC_64
+ archive: nvim-win64
+ - config: MSVC_32
+ archive: nvim-win32
+ name: windows (${{ matrix.config }})
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - run: powershell ci\build.ps1 -NoTests
+ env:
+ CONFIGURATION: ${{ matrix.config }}
+ - run: move build\Neovim.zip build\${{ matrix.archive }}.zip
+ - uses: actions/upload-artifact@v2
+ with:
+ name: ${{ matrix.archive }}
+ path: build/${{ matrix.archive }}.zip
+ retention-days: 1
+
publish:
- needs: [linux, appimage, macOS]
+ needs: [linux, appimage, macOS, windows]
runs-on: ubuntu-20.04
steps:
- uses: actions/download-artifact@v2
@@ -143,6 +170,8 @@ jobs:
nvim-linux64.tar.gz:./nvim-linux64/nvim-linux64.tar.gz
nvim.appimage:./appimage/nvim.appimage
nvim.appimage.zsync:./appimage/nvim.appimage.zsync
+ nvim-win32.zip:./nvim-win32/nvim-win32.zip
+ nvim-win64.zip:./nvim-win64/nvim-win64.zip
body: |
${{ env.SUBJECT }}
```
diff --git a/.travis.yml b/.travis.yml
index b68f4f1bc1..06547febba 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -96,24 +96,6 @@ addons:
jobs:
include:
- - stage: baseline
- name: clang-asan
- os: linux
- compiler: clang-11
- # Use Lua so that ASAN can test our embedded Lua support. 8fec4d53d0f6
- env:
- - CLANG_SANITIZER=ASAN_UBSAN
- - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
- - SYMBOLIZER=asan_symbolize-11
- - *common-job-env
- addons:
- apt:
- sources:
- - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main'
- key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- packages:
- - *common-apt-packages
- - clang-11
- name: gcc-coverage (gcc 9)
os: linux
compiler: gcc-9
@@ -134,20 +116,6 @@ jobs:
packages:
- *common-apt-packages
- gcc-9
- - if: branch = master AND commit_message !~ /\[skip.lint\]/
- name: lint
- os: linux
- env:
- - CI_TARGET=lint
- - *common-job-env
-
- - stage: second stage
- name: "macOS: clang"
- os: osx
- compiler: clang
- osx_image: xcode10.2 # macOS 10.14
- env:
- - *common-job-env
- name: gcc-functionaltest-lua
os: linux
compiler: gcc
@@ -188,12 +156,6 @@ jobs:
- python3-setuptools
- python-dev
- python3-dev
- - name: clang-tsan
- os: linux
- compiler: clang
- env:
- - CLANG_SANITIZER=TSAN
- - *common-job-env
- if: type != pull_request
name: snap
os: linux
diff --git a/README.md b/README.md
index e2c82fa6e7..180fc1df14 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,6 @@
[Twitter](https://twitter.com/Neovim)
[![GitHub CI](https://github.com/neovim/neovim/workflows/CI/badge.svg)](https://github.com/neovim/neovim/actions?query=workflow%3A%22CI%22)
-[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/urdqjrik5u521fac/branch/master?svg=true)](https://ci.appveyor.com/project/neovim/neovim/branch/master)
[![Codecov coverage](https://img.shields.io/codecov/c/github/neovim/neovim.svg)](https://codecov.io/gh/neovim/neovim)
[![Coverity Scan analysis](https://scan.coverity.com/projects/2227/badge.svg)](https://scan.coverity.com/projects/2227)
[![Clang analysis](https://neovim.io/doc/reports/clang/badge.svg)](https://neovim.io/doc/reports/clang)
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 01ca16f930..0000000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-version: '{build}'
-environment:
- APPVEYOR_CACHE_ENTRY_ZIP_ARGS: "-t7z -m0=lzma -mx=9"
- DEPS_BUILD_DIR: "C:/projects/nvim-deps"
- DEPS_PREFIX: "C:/projects/nvim-deps/usr"
- # Silence/redirect errors due to missing locking support (via libgcov).
- GCOV_ERROR_FILE: "$(TEMP)/libgcov-errors.log"
-image: Visual Studio 2017
-configuration:
-- MINGW_64-gcov
-- MINGW_32
-- MSVC_64
-- MSVC_32
-init:
-- ps: |
- # Pull requests: skip some build configurations to save time.
- if ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -and $env:CONFIGURATION -match '^(MSVC_64|MINGW_32)$') {
- $env:APPVEYOR_CACHE_SKIP_SAVE = "true"
- Exit-AppVeyorBuild
- }
-# RDP
-#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
-matrix:
- fast_finish: true
-build_script:
-- powershell ci\build.ps1
-after_build:
-- ps: |
- if (Test-Path $env:GCOV_ERROR_FILE) {
- Get-Content $env:GCOV_ERROR_FILE -Head 10
- Get-Content $env:GCOV_ERROR_FILE -Tail 10
- } else {
- write-host "no GCOV_ERROR_FILE"
- }
-cache:
-- C:\projects\nvim-deps -> third-party\**
-artifacts:
-- path: build/Neovim.zip
-- path: build/bin/nvim.exe
diff --git a/ci/build.ps1 b/ci/build.ps1
index dbc43aecf3..db7026ac66 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -3,7 +3,6 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
-$isPullRequest = ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -ne $null)
$env:CONFIGURATION -match '^(?<compiler>\w+)_(?<bits>32|64)(?:-(?<option>\w+))?$'
$compiler = $Matches.compiler
$compileOption = if ($Matches -contains 'option') {$Matches.option} else {''}
@@ -29,27 +28,9 @@ function exitIfFailed() {
}
}
-# https://github.com/lukesampson/scoop#installation
-$scoop = (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
-& {
- Set-StrictMode -Off
- Invoke-Expression $scoop
-}
-
-scoop install perl
-perl --version
-cpanm.bat --version
-
if (-not $NoTests) {
- scoop install nodejs-lts
node --version
npm.cmd --version
-
- cpanm.bat -n Neovim::Ext
- if ($LastExitCode -ne 0) {
- Get-Content -Path "$env:USERPROFILE\.cpanm\build.log"
- }
- perl -W -e 'use Neovim::Ext; print $Neovim::Ext::VERSION'; exitIfFailed
}
if (-Not (Test-Path -PathType container $env:DEPS_BUILD_DIR)) {
@@ -91,14 +72,7 @@ if ($compiler -eq 'MINGW') {
& C:\msys64\usr\bin\mkdir -p /var/cache/pacman/pkg
# Build third-party dependencies
- C:\msys64\usr\bin\bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz" ; exitIfFailed
- C:\msys64\usr\bin\bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig" ; exitIfFailed
- C:\msys64\usr\bin\bash -lc "pacman-key --verify msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig" ; exitIfFailed
- C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -U msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz" ; exitIfFailed
- # If there are still processes using msys-2.0.dll, after the base system update is finished, it will wait for input from the user.
- # To prevent this, we will terminate all processes that use msys-2.0.dll.
- Get-Process | Where-Object { $_.path -like 'C:\msys64*' } | Stop-Process
- C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Syu" ; exitIfFailed
+ C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Su" ; exitIfFailed
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S $mingwPackages" ; exitIfFailed
}
elseif ($compiler -eq 'MSVC') {
@@ -113,16 +87,16 @@ elseif ($compiler -eq 'MSVC') {
if (-not $NoTests) {
# Setup python (use AppVeyor system python)
- C:\Python27\python.exe -m pip install pynvim ; exitIfFailed
- C:\Python35\python.exe -m pip install pynvim ; exitIfFailed
+
+ C:\hostedtoolcache\windows\Python\2.7.18\x64\python.exe -m pip install pynvim ; exitIfFailed
+ C:\hostedtoolcache\windows\Python\3.5.4\x64\python.exe -m pip install pynvim ; exitIfFailed
# Disambiguate python3
- move c:\Python35\python.exe c:\Python35\python3.exe
- $env:PATH = "C:\Python35;C:\Python27;$env:PATH"
+ move C:\hostedtoolcache\windows\Python\3.5.4\x64\python.exe C:\hostedtoolcache\windows\Python\3.5.4\x64\python3.exe
+ $env:PATH = "C:\hostedtoolcache\windows\Python\3.5.4\x64;C:\hostedtoolcache\windows\Python\2.7.18\x64;$env:PATH"
# Sanity check
python -c "import pynvim; print(str(pynvim))" ; exitIfFailed
python3 -c "import pynvim; print(str(pynvim))" ; exitIfFailed
- $env:PATH = "C:\Ruby24\bin;$env:PATH"
gem.cmd install --pre neovim
Get-Command -CommandType Application neovim-ruby-host.bat
diff --git a/contrib/flake.nix b/contrib/flake.nix
index a75e584075..86e4b37cfa 100644
--- a/contrib/flake.nix
+++ b/contrib/flake.nix
@@ -44,7 +44,7 @@
pythonEnv = legacyPkgs.python3;
luacheck = legacyPkgs.luaPackages.luacheck;
in
- neovim-debug.overrideAttrs(oa: {
+ (neovim-debug.override({doCheck = true;})).overrideAttrs(oa: {
cmakeFlags = oa.cmakeFlags ++ [
"-DLUACHECK_PRG=${luacheck}/bin/luacheck"
"-DMIN_LOG_LEVEL=0"
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 7a3af78ab4..c4b4594290 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -376,7 +376,7 @@ on writing and loading a buffer to file, nor in undo/redo cycles.
Highlights are registered using the |nvim_buf_add_highlight()| function. If an
external highlighter plugin wants to add many highlights in a batch,
performance can be improved by calling |nvim_buf_add_highlight()| as an
-asynchronous notification, after first (synchronously) reqesting a source id.
+asynchronous notification, after first (synchronously) requesting a source id.
Example using the Python API client (|pynvim|):
>
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 5c67359002..f3ed086933 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -954,9 +954,13 @@ inside of strings can change! Also see 'softtabstop' option. >
delete and yank) ({.%#:} only work with put).
*:reg* *:registers*
-:reg[isters] Display the contents of all numbered and named
- registers. If a register is written to for |:redir|
- it will not be listed.
+:reg[isters] Display the type and contents of all numbered and
+ named registers. If a register is written to for
+ |:redir| it will not be listed.
+ Type can be one of:
+ "c" for |characterwise| text
+ "l" for |linewise| text
+ "b" for |blockwise-visual| text
:reg[isters] {arg} Display the contents of the numbered and named
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 67e2815715..8e93b188e9 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -118,7 +118,7 @@ FAQ *lsp-faq*
<
*vim.lsp.callbacks*
- Q: What happened to `vim.lsp.callbacks`?
- A: After better defining the interface of |lsp-hander|s, we thought it best
+ A: After better defining the interface of |lsp-handler|s, we thought it best
to remove the generic usage of `callbacks` and transform to `handlers`.
Due to this, `vim.lsp.callbacks` was renamed to |vim.lsp.handlers|.
@@ -257,7 +257,7 @@ For |lsp-notification|, each |lsp-handler| has this signature: >
*lsp-handler-configuration*
-To configure the behavior of a builtin |lsp-handler|, the conenvience method
+To configure the behavior of a builtin |lsp-handler|, the convenient method
|vim.lsp.with()| is provided for users.
To configure the behavior of |vim.lsp.diagnostic.on_publish_diagnostics()|,
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index ed3204c537..d2083b23d3 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -623,6 +623,9 @@ au BufNewFile,BufRead *.mo,*.gdmo setf gdmo
" Gedcom
au BufNewFile,BufRead *.ged,lltxxxxx.txt setf gedcom
+" Gift (Moodle)
+autocmd BufRead,BufNewFile *.gift setf gift
+
" Git
au BufNewFile,BufRead COMMIT_EDITMSG,MERGE_MSG,TAG_EDITMSG setf gitcommit
au BufNewFile,BufRead *.git/config,.gitconfig,/etc/gitconfig setf gitconfig
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index c98fde3696..072349b226 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -1044,6 +1044,8 @@ function M.display(diagnostics, bufnr, client_id, config)
diagnostics = diagnostics or M.get(bufnr, client_id)
+ vim.api.nvim_command("doautocmd <nomodeline> User LspDiagnosticsChanged")
+
if not diagnostics or vim.tbl_isempty(diagnostics) then
return
end
@@ -1062,8 +1064,6 @@ function M.display(diagnostics, bufnr, client_id, config)
if signs_opts then
M.set_signs(diagnostics, bufnr, client_id, nil, signs_opts)
end
-
- vim.api.nvim_command("doautocmd <nomodeline> User LspDiagnosticsChanged")
end
-- }}}
-- Diagnostic User Functions {{{
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index a3bf61ba0b..fd23a6a547 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -63,8 +63,44 @@ local function progress_callback(_, _, params, client_id)
vim.api.nvim_command("doautocmd <nomodeline> User LspProgressUpdate")
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress
M['$/progress'] = progress_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create
+M['window/workDoneProgress/create'] = function(_, _, params, client_id)
+ local client = vim.lsp.get_client_by_id(client_id)
+ local token = params.token -- string or number
+ if not client then
+ err_message("LSP[", client_id, "] client has shut down after sending the message")
+ end
+ client.messages.progress[token] = {}
+ return vim.NIL
+end
+
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest
+M['window/showMessageRequest'] = function(_, _, params)
+
+ local actions = params.actions
+ print(params.message)
+ local option_strings = {params.message, "\nRequest Actions:"}
+ for i, action in ipairs(actions) do
+ local title = action.title:gsub('\r\n', '\\r\\n')
+ title = title:gsub('\n', '\\n')
+ table.insert(option_strings, string.format("%d. %s", i, title))
+ end
+
+ -- window/showMessageRequest can return either MessageActionItem[] or null.
+ local choice = vim.fn.inputlist(option_strings)
+ if choice < 1 or choice > #actions then
+ return vim.NIL
+ else
+ local action_chosen = actions[choice]
+ return {
+ title = action_chosen;
+ }
+ end
+end
+
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
M['textDocument/codeAction'] = function(_, _, actions)
if actions == nil or vim.tbl_isempty(actions) then
@@ -253,9 +289,8 @@ M['textDocument/signatureHelp'] = function(_, method, result)
end
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
-M['textDocument/documentHighlight'] = function(_, _, result, _)
+M['textDocument/documentHighlight'] = function(_, _, result, _, bufnr, _)
if not result then return end
- local bufnr = api.nvim_get_current_buf()
util.buf_highlight_references(bufnr, result)
end
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index b785d2f586..b2d3d0641c 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -730,7 +730,15 @@ function protocol.make_client_capabilities()
experimental = nil;
window = {
workDoneProgress = true;
- }
+ showMessage = {
+ messageActionItem = {
+ additionalPropertiesSupport = false;
+ };
+ };
+ showDocument = {
+ support = false;
+ };
+ };
}
end
diff --git a/src/nvim/arabic.c b/src/nvim/arabic.c
index 7f12c0c798..9fba38a49f 100644
--- a/src/nvim/arabic.c
+++ b/src/nvim/arabic.c
@@ -719,9 +719,7 @@ int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1,
// half-shape current and previous character
int shape_c = half_shape(prev_c);
- // Save away current character
- int curr_c = c;
-
+ int curr_c;
int curr_laa = A_firstc_laa(c, *c1p);
int prev_laa = A_firstc_laa(prev_c, prev_c1);
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h
index 2397af27cc..f41068ea70 100644
--- a/src/nvim/ascii.h
+++ b/src/nvim/ascii.h
@@ -89,6 +89,10 @@ static inline bool ascii_iswhite(int)
REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE;
+static inline bool ascii_iswhite_or_nul(int)
+ REAL_FATTR_CONST
+ REAL_FATTR_ALWAYS_INLINE;
+
static inline bool ascii_isdigit(int)
REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE;
@@ -117,6 +121,14 @@ static inline bool ascii_iswhite(int c)
return c == ' ' || c == '\t';
}
+/// Checks if `c` is a space or tab character or NUL.
+///
+/// @see {ascii_isdigit}
+static inline bool ascii_iswhite_or_nul(int c)
+{
+ return ascii_iswhite(c) || c == NUL;
+}
+
/// Check whether character is a decimal digit.
///
/// Library isdigit() function is officially locale-dependent and, for
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index a5e8097133..93a03986e5 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1587,7 +1587,7 @@ void enter_buffer(buf_T *buf)
need_fileinfo = true; // display file info after redraw
}
// check if file changed
- (void)buf_check_timestamp(curbuf, false);
+ (void)buf_check_timestamp(curbuf);
curwin->w_topline = 1;
curwin->w_topfill = 0;
@@ -4706,7 +4706,6 @@ do_arg_all(
int keep_tabs // keep current tabs, for ":tab drop file"
)
{
- int i;
char_u *opened; // Array of weight for which args are open:
// 0: not opened
// 1: opened in other tab
@@ -4715,6 +4714,7 @@ do_arg_all(
int opened_len; // length of opened[]
int use_firstwin = false; // use first window for arglist
+ bool tab_drop_empty_window = false;
int split_ret = OK;
bool p_ea_save;
alist_T *alist; // argument list to be used
@@ -4762,6 +4762,7 @@ do_arg_all(
win_T *wpnext = NULL;
tpnext = curtab->tp_next;
for (win_T *wp = firstwin; wp != NULL; wp = wpnext) {
+ int i;
wpnext = wp->w_next;
buf = wp->w_buffer;
if (buf->b_ffname == NULL
@@ -4867,14 +4868,15 @@ do_arg_all(
last_curwin = curwin;
last_curtab = curtab;
win_enter(lastwin, false);
- // ":drop all" should re-use an empty window to avoid "--remote-tab"
+ // ":tab drop file" should re-use an empty window to avoid "--remote-tab"
// leaving an empty tab page when executed locally.
if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1
&& curbuf->b_ffname == NULL && !curbuf->b_changed) {
use_firstwin = true;
+ tab_drop_empty_window = true;
}
- for (i = 0; i < count && i < opened_len && !got_int; i++) {
+ for (int i = 0; i < count && !got_int; i++) {
if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) {
arg_had_last = true;
}
@@ -4894,6 +4896,10 @@ do_arg_all(
}
}
} else if (split_ret == OK) {
+ // trigger events for tab drop
+ if (tab_drop_empty_window && i == count - 1) {
+ autocmd_no_enter--;
+ }
if (!use_firstwin) { // split current window
p_ea_save = p_ea;
p_ea = true; // use space from all windows
@@ -4919,6 +4925,9 @@ do_arg_all(
|| bufIsChanged(curwin->w_buffer))
? ECMD_HIDE : 0) + ECMD_OLDBUF,
curwin);
+ if (tab_drop_empty_window && i == count - 1) {
+ autocmd_no_enter++;
+ }
if (use_firstwin) {
autocmd_no_leave++;
}
@@ -5470,7 +5479,9 @@ int buf_signcols(buf_T *buf)
curline = sign->lnum;
linesum = 0;
}
- linesum++;
+ if (sign->has_text_or_icon) {
+ linesum++;
+ }
}
if (linesum > buf->b_signcols_max) {
buf->b_signcols_max = linesum;
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 1cdf84f9d0..93bc34fa4b 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -805,7 +805,7 @@ static void diff_try_update(diffio_T *dio,
for (idx_new = idx_orig; idx_new < DB_COUNT; idx_new++) {
buf = curtab->tp_diffbuf[idx_new];
if (buf_valid(buf)) {
- buf_check_timestamp(buf, false);
+ buf_check_timestamp(buf);
}
}
}
@@ -1225,8 +1225,7 @@ void ex_diffpatch(exarg_T *eap)
EMSG(_("E816: Cannot read patch output"));
} else {
if (curbuf->b_fname != NULL) {
- newname = vim_strnsave(curbuf->b_fname,
- (int)(STRLEN(curbuf->b_fname) + 4));
+ newname = vim_strnsave(curbuf->b_fname, STRLEN(curbuf->b_fname) + 4);
STRCAT(newname, ".new");
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 2d9dba839d..876e53e3cd 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -381,7 +381,7 @@ static void insert_enter(InsertState *s)
// Need to recompute the cursor position, it might move when the cursor is
// on a TAB or special character.
- curs_columns(true);
+ curs_columns(curwin, true);
// Enable langmap or IME, indicated by 'iminsert'.
// Note that IME may enabled/disabled without us noticing here, thus the
@@ -594,7 +594,7 @@ static int insert_check(VimState *state)
if (curwin->w_wcol < s->mincol - curbuf->b_p_ts
&& curwin->w_wrow == curwin->w_winrow
- + curwin->w_height_inner - 1 - get_scrolloff_value()
+ + curwin->w_height_inner - 1 - get_scrolloff_value(curwin)
&& (curwin->w_cursor.lnum != curwin->w_topline
|| curwin->w_topfill > 0)) {
if (curwin->w_topfill > 0) {
@@ -608,7 +608,7 @@ static int insert_check(VimState *state)
}
// May need to adjust w_topline to show the cursor.
- update_topline();
+ update_topline(curwin);
s->did_backspace = false;
@@ -1561,7 +1561,7 @@ void edit_putchar(int c, bool highlight)
int attr;
if (curwin->w_grid.chars != NULL || default_grid.chars != NULL) {
- update_topline(); // just in case w_topline isn't valid
+ update_topline(curwin); // just in case w_topline isn't valid
validate_cursor();
if (highlight) {
attr = HL_ATTR(HLF_8);
@@ -1677,7 +1677,7 @@ void display_dollar(colnr_T col)
// If on the last byte of a multi-byte move to the first byte.
char_u *p = get_cursor_line_ptr();
curwin->w_cursor.col -= utf_head_off(p, p + col);
- curs_columns(false); // Recompute w_wrow and w_wcol
+ curs_columns(curwin, false); // Recompute w_wrow and w_wcol
if (curwin->w_wcol < curwin->w_grid.Columns) {
edit_putchar('$', false);
dollar_vcol = curwin->w_virtcol;
@@ -3423,7 +3423,7 @@ static void ins_compl_addleader(int c)
xfree(compl_leader);
compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col,
- (int)(curwin->w_cursor.col - compl_col));
+ curwin->w_cursor.col - compl_col);
ins_compl_new_leader();
}
@@ -3810,10 +3810,10 @@ static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
*/
static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
{
- static win_T *wp;
+ static win_T *wp = NULL;
if (flag == 'w') { // just windows
- if (buf == curbuf) { // first call for this flag/expansion
+ if (buf == curbuf || wp == NULL) { // first call for this flag/expansion
wp = curwin;
}
assert(wp);
@@ -5327,8 +5327,9 @@ static int ins_complete(int c, bool enable_pum)
compl_curr_match->cp_number);
edit_submode_extra = match_ref;
edit_submode_highl = HLF_R;
- if (dollar_vcol >= 0)
- curs_columns(FALSE);
+ if (dollar_vcol >= 0) {
+ curs_columns(curwin, false);
+ }
}
}
}
@@ -6158,7 +6159,7 @@ internal_format (
curwin->w_p_lbr = has_lbr;
if (!format_only && haveto_redraw) {
- update_topline();
+ update_topline(curwin);
redraw_curbuf_later(VALID);
}
}
@@ -6807,7 +6808,7 @@ cursor_up (
coladvance(curwin->w_curswant);
if (upd_topline) {
- update_topline(); // make sure curwin->w_topline is valid
+ update_topline(curwin); // make sure curwin->w_topline is valid
}
return OK;
@@ -6858,7 +6859,7 @@ cursor_down (
coladvance(curwin->w_curswant);
if (upd_topline) {
- update_topline(); // make sure curwin->w_topline is valid
+ update_topline(curwin); // make sure curwin->w_topline is valid
}
return OK;
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a7a860ba72..f60504de5e 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -76,9 +76,6 @@ static char_u * const namespace_char = (char_u *)"abglstvw";
/// Variable used for g:
static ScopeDictDictItem globvars_var;
-/// g: value
-#define globvarht globvardict.dv_hashtab
-
/*
* Old Vim variables such as "v:version" are also available without the "v:".
* Also in functions. We need a special hashtable for them.
@@ -2556,6 +2553,7 @@ void free_for_info(void *fi_void)
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
+ FUNC_ATTR_NONNULL_ALL
{
int got_eq = FALSE;
int c;
@@ -2638,6 +2636,23 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
}
}
}
+
+ // ":exe one two" completes "two"
+ if ((cmdidx == CMD_execute
+ || cmdidx == CMD_echo
+ || cmdidx == CMD_echon
+ || cmdidx == CMD_echomsg)
+ && xp->xp_context == EXPAND_EXPRESSION) {
+ for (;;) {
+ char_u *const n = skiptowhite(arg);
+
+ if (n == arg || ascii_iswhite_or_nul(*skipwhite(n))) {
+ break;
+ }
+ arg = skipwhite(n);
+ }
+ }
+
xp->xp_pattern = arg;
}
@@ -5404,7 +5419,7 @@ static int get_literal_key(char_u **arg, typval_T *tv)
for (p = *arg; ASCII_ISALNUM(*p) || *p == '_' || *p == '-'; p++) {
}
tv->v_type = VAR_STRING;
- tv->vval.v_string = vim_strnsave(*arg, (int)(p - *arg));
+ tv->vval.v_string = vim_strnsave(*arg, p - *arg);
*arg = skipwhite(p);
return OK;
@@ -7070,7 +7085,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append,
}
}
check_cursor_col();
- update_topline();
+ update_topline(curwin);
}
if (!is_curbuf) {
@@ -7782,13 +7797,13 @@ pos_T *var2fpos(const typval_T *const tv, const int dollar_lnum,
if (name[0] == 'w' && dollar_lnum) {
pos.col = 0;
if (name[1] == '0') { // "w0": first visible line
- update_topline();
+ update_topline(curwin);
// In silent Ex mode topline is zero, but that's not a valid line
// number; use one instead.
pos.lnum = curwin->w_topline > 0 ? curwin->w_topline : 1;
return &pos;
} else if (name[1] == '$') { // "w$": last visible line
- validate_botline();
+ validate_botline(curwin);
// In silent Ex mode botline is zero, return zero then.
pos.lnum = curwin->w_botline > 0 ? curwin->w_botline - 1 : 0;
return &pos;
@@ -10246,9 +10261,6 @@ repeat:
if (src[*usedlen] == ':'
&& (src[*usedlen + 1] == 's'
|| (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's'))) {
- char_u *str;
- char_u *pat;
- char_u *sub;
int sep;
char_u *flags;
int didit = FALSE;
@@ -10265,13 +10277,13 @@ repeat:
// find end of pattern
p = vim_strchr(s, sep);
if (p != NULL) {
- pat = vim_strnsave(s, (int)(p - s));
+ char_u *const pat = vim_strnsave(s, p - s);
s = p + 1;
// find end of substitution
p = vim_strchr(s, sep);
if (p != NULL) {
- sub = vim_strnsave(s, (int)(p - s));
- str = vim_strnsave(*fnamep, *fnamelen);
+ char_u *const sub = vim_strnsave(s, p - s);
+ char_u *const str = vim_strnsave(*fnamep, *fnamelen);
*usedlen = (size_t)(p + 1 - src);
s = do_string_sub(str, pat, sub, NULL, flags);
*fnamep = s;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 89d9a85775..16eb6f8898 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -4206,6 +4206,8 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
n = true;
} else if (STRICMP(name, "syntax_items") == 0) {
n = syntax_present(curwin);
+ } else if (STRICMP(name, "clipboard_working") == 0) {
+ n = eval_has_provider("clipboard");
#ifdef UNIX
} else if (STRICMP(name, "unnamedplus") == 0) {
n = eval_has_provider("clipboard");
@@ -6551,7 +6553,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (prevlen == 0) {
assert(len < INT_MAX);
- s = vim_strnsave(start, (int)len);
+ s = vim_strnsave(start, len);
} else {
/* Change "prev" buffer to be the right size. This way
* the bytes are only copied once, and very long lines are
@@ -10853,7 +10855,7 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
}
- rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
+ rettv->vval.v_string = vim_strnsave(head, tail - head);
}
/*
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 4e8b98d723..70c998ef39 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -2297,9 +2297,9 @@ void ex_function(exarg_T *eap)
// Ignore leading white space.
p = skipwhite(p + 4);
heredoc_trimmed =
- vim_strnsave(theline, (int)(skipwhite(theline) - theline));
+ vim_strnsave(theline, skipwhite(theline) - theline);
}
- skip_until = vim_strnsave(p, (int)(skiptowhite(p) - p));
+ skip_until = vim_strnsave(p, skiptowhite(p) - p);
do_concat = false;
is_heredoc = true;
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index b23209e1b6..ae389a6727 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -2323,7 +2323,7 @@ int do_ecmd(
// Existing memfile.
oldbuf = true;
set_bufref(&bufref, buf);
- (void)buf_check_timestamp(buf, false);
+ (void)buf_check_timestamp(buf);
// Check if autocommands made buffer invalid or changed the current
// buffer.
if (!bufref_valid(&bufref) || curbuf != old_curbuf.br_buf) {
@@ -2706,7 +2706,7 @@ int do_ecmd(
if (topline == 0 && command == NULL) {
*so_ptr = 999; // force cursor to be vertically centered in the window
}
- update_topline();
+ update_topline(curwin);
curwin->w_scbind_pos = curwin->w_topline;
*so_ptr = n;
redraw_curbuf_later(NOT_VALID); // redraw this buffer later
@@ -2796,9 +2796,10 @@ void ex_append(exarg_T *eap)
p = vim_strchr(eap->nextcmd, NL);
if (p == NULL)
p = eap->nextcmd + STRLEN(eap->nextcmd);
- theline = vim_strnsave(eap->nextcmd, (int)(p - eap->nextcmd));
- if (*p != NUL)
- ++p;
+ theline = vim_strnsave(eap->nextcmd, p - eap->nextcmd);
+ if (*p != NUL) {
+ p++;
+ }
eap->nextcmd = p;
} else {
// Set State to avoid the cursor shape to be set to INSERT mode
@@ -3705,7 +3706,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
+ len_change;
highlight_match = TRUE;
- update_topline();
+ update_topline(curwin);
validate_cursor();
update_screen(SOME_VALID);
highlight_match = false;
@@ -5740,7 +5741,7 @@ static buf_T *show_sub(exarg_T *eap, pos_T old_cusr,
redraw_later(curwin, SOME_VALID);
win_enter(save_curwin, false); // Return to original window
- update_topline();
+ update_topline(curwin);
// Update screen now.
int save_rd = RedrawingDisabled;
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 3b9c44c3cd..bde584d27e 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -3392,7 +3392,7 @@ void ex_checktime(exarg_T *eap)
} else {
buf = buflist_findnr((int)eap->line2);
if (buf != NULL) { // cannot happen?
- (void)buf_check_timestamp(buf, false);
+ (void)buf_check_timestamp(buf);
}
}
no_check_timestamps = save_no_check_timestamps;
@@ -3790,6 +3790,14 @@ void ex_drop(exarg_T *eap)
if (wp->w_buffer == buf) {
goto_tabpage_win(tp, wp);
curwin->w_arg_idx = 0;
+ if (!bufIsChanged(curbuf)) {
+ const int save_ar = curbuf->b_p_ar;
+
+ // reload the file if it is newer
+ curbuf->b_p_ar = 1;
+ buf_check_timestamp(curbuf);
+ curbuf->b_p_ar = save_ar;
+ }
return;
}
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index a5eccc12b9..003c78b241 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -2979,6 +2979,15 @@ const char * set_one_cmd_context(
const char *arg = (const char *)skipwhite((const char_u *)p);
+ // Skip over ++argopt argument
+ if ((ea.argt & ARGOPT) && *arg != NUL && strncmp(arg, "++", 2) == 0) {
+ p = arg;
+ while (*p && !ascii_isspace(*p)) {
+ MB_PTR_ADV(p);
+ }
+ arg = (const char *)skipwhite((const char_u *)p);
+ }
+
if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) {
if (*arg == '>') { // Append.
if (*++arg == '>') {
@@ -4760,10 +4769,8 @@ static void ex_abclear(exarg_T *eap)
static void ex_autocmd(exarg_T *eap)
{
- /*
- * Disallow auto commands from .exrc and .vimrc in current
- * directory for security reasons.
- */
+ // Disallow autocommands from .exrc and .vimrc in current
+ // directory for security reasons.
if (secure) {
secure = 2;
eap->errmsg = e_curdir;
@@ -4979,7 +4986,6 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
FUNC_ATTR_NONNULL_ARG(1, 3)
{
ucmd_T *cmd = NULL;
- char_u *p;
int i;
int cmp = 1;
char_u *rep_buf = NULL;
@@ -5039,7 +5045,7 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
if (cmp != 0) {
ga_grow(gap, 1);
- p = vim_strnsave(name, (int)name_len);
+ char_u *const p = vim_strnsave(name, name_len);
cmd = USER_CMD_GA(gap, i);
memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T));
@@ -6188,8 +6194,9 @@ int parse_compl_arg(const char_u *value, int vallen, int *complp,
return FAIL;
}
- if (arg != NULL)
- *compl_arg = vim_strnsave(arg, (int)arglen);
+ if (arg != NULL) {
+ *compl_arg = vim_strnsave(arg, arglen);
+ }
return OK;
}
@@ -7362,7 +7369,7 @@ static void ex_syncbind(exarg_T *eap)
topline = curwin->w_topline;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_p_scb && wp->w_buffer) {
- y = wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value();
+ y = wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value(curwin);
if (topline > y) {
topline = y;
}
@@ -8050,7 +8057,7 @@ static void ex_redraw(exarg_T *eap)
RedrawingDisabled = 0;
p_lz = FALSE;
validate_cursor();
- update_topline();
+ update_topline(curwin);
if (eap->forceit) {
redraw_all_later(NOT_VALID);
}
@@ -8199,10 +8206,11 @@ static void ex_mark(exarg_T *eap)
*/
void update_topline_cursor(void)
{
- check_cursor(); /* put cursor on valid line */
- update_topline();
- if (!curwin->w_p_wrap)
+ check_cursor(); // put cursor on valid line
+ update_topline(curwin);
+ if (!curwin->w_p_wrap) {
validate_cursor();
+ }
update_curswant();
}
@@ -9282,7 +9290,7 @@ static void ex_match(exarg_T *eap)
} else {
p = skiptowhite(eap->arg);
if (!eap->skip) {
- g = vim_strnsave(eap->arg, (int)(p - eap->arg));
+ g = vim_strnsave(eap->arg, p - eap->arg);
}
p = skipwhite(p);
if (*p == NUL) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 53dd2776c1..0f50d5153d 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -523,7 +523,7 @@ static void may_do_incsearch_highlighting(int firstc, long count,
// positioned in the same way as the actual search command
restore_viewstate(&s->old_viewstate);
changed_cline_bef_curs();
- update_topline();
+ update_topline(curwin);
if (found != 0) {
pos_T save_pos = curwin->w_cursor;
@@ -1082,6 +1082,7 @@ static int command_line_execute(VimState *state, int key)
if (s->c == K_DOWN && ccline.cmdpos > 0
&& ccline.cmdbuff[ccline.cmdpos - 1] == '.') {
s->c = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
} else if (s->c == K_UP) {
// Hitting <Up>: Remove one submenu name in front of the
// cursor
@@ -1112,6 +1113,7 @@ static int command_line_execute(VimState *state, int key)
cmdline_del(i);
}
s->c = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
s->xpc.xp_context = EXPAND_NOTHING;
}
}
@@ -1134,6 +1136,7 @@ static int command_line_execute(VimState *state, int key)
|| ccline.cmdbuff[ccline.cmdpos - 3] != '.')) {
// go down a directory
s->c = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
} else if (STRNCMP(s->xpc.xp_pattern, upseg + 1, 3) == 0
&& s->c == K_DOWN) {
// If in a direct ancestor, strip off one ../ to go down
@@ -1154,6 +1157,7 @@ static int command_line_execute(VimState *state, int key)
&& (vim_ispathsep(ccline.cmdbuff[j - 3]) || j == i + 2)) {
cmdline_del(j - 2);
s->c = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
}
} else if (s->c == K_UP) {
// go up a directory
@@ -1546,7 +1550,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count,
set_search_match(&s->match_end);
curwin->w_cursor = s->match_start;
changed_cline_bef_curs();
- update_topline();
+ update_topline(curwin);
validate_cursor();
highlight_match = true;
save_viewstate(&s->old_viewstate);
@@ -2235,7 +2239,7 @@ static int command_line_changed(CommandLineState *s)
// Restore the window "view".
curwin->w_cursor = s->is_state.save_cursor;
restore_viewstate(&s->is_state.old_viewstate);
- update_topline();
+ update_topline(curwin);
redrawcmdline();
@@ -2244,7 +2248,9 @@ static int command_line_changed(CommandLineState *s)
close_preview_windows();
update_screen(SOME_VALID); // Clear 'inccommand' preview.
} else {
- may_do_incsearch_highlighting(s->firstc, s->count, &s->is_state);
+ if (s->xpc.xp_context == EXPAND_NOTHING) {
+ may_do_incsearch_highlighting(s->firstc, s->count, &s->is_state);
+ }
}
if (cmdmsg_rl || (p_arshape && !p_tbidi)) {
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index d831ffc050..14dac9a126 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -526,8 +526,12 @@ static int makeopens(FILE *fd, char_u *dirnow)
}
}
- // Close all windows but one.
+ // Close all windows and tabs but one.
PUTLINE_FAIL("silent only");
+ if ((ssop_flags & SSOP_TABPAGES)
+ && put_line(fd, "silent tabonly") == FAIL) {
+ return FAIL;
+ }
//
// Now a :cd command to the session directory or the current directory
@@ -606,13 +610,26 @@ static int makeopens(FILE *fd, char_u *dirnow)
//
tab_firstwin = firstwin; // First window in tab page "tabnr".
tab_topframe = topframe;
+ if ((ssop_flags & SSOP_TABPAGES)) {
+ // Similar to ses_win_rec() below, populate the tab pages first so
+ // later local options won't be copied to the new tabs.
+ FOR_ALL_TABS(tp) {
+ if (tp->tp_next != NULL && put_line(fd, "tabnew") == FAIL) {
+ return FAIL;
+ }
+ }
+
+ if (first_tabpage->tp_next != NULL && put_line(fd, "tabrewind") == FAIL) {
+ return FAIL;
+ }
+ }
for (tabnr = 1;; tabnr++) {
tabpage_T *tp = find_tabpage(tabnr);
if (tp == NULL) {
break; // done all tab pages
}
- int need_tabnew = false;
+ bool need_tabnext = false;
int cnr = 1;
if ((ssop_flags & SSOP_TABPAGES)) {
@@ -624,7 +641,7 @@ static int makeopens(FILE *fd, char_u *dirnow)
tab_topframe = tp->tp_topframe;
}
if (tabnr > 1) {
- need_tabnew = true;
+ need_tabnext = true;
}
}
@@ -639,11 +656,15 @@ static int makeopens(FILE *fd, char_u *dirnow)
&& !bt_help(wp->w_buffer)
&& !bt_nofile(wp->w_buffer)
) {
- if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0
+ if (need_tabnext && put_line(fd, "tabnext") == FAIL) {
+ return FAIL;
+ }
+ need_tabnext = false;
+
+ if (fputs("edit ", fd) < 0
|| ses_fname(fd, wp->w_buffer, &ssop_flags, true) == FAIL) {
return FAIL;
}
- need_tabnew = false;
if (!wp->w_arg_idx_invalid) {
edited_win = wp;
}
@@ -652,7 +673,7 @@ static int makeopens(FILE *fd, char_u *dirnow)
}
// If no file got edited create an empty tab page.
- if (need_tabnew && put_line(fd, "tabnew") == FAIL) {
+ if (need_tabnext && put_line(fd, "tabnext") == FAIL) {
return FAIL;
}
@@ -775,6 +796,7 @@ static int makeopens(FILE *fd, char_u *dirnow)
//
if (fprintf(fd, "%s",
"if exists('s:wipebuf') "
+ "&& len(win_findbuf(s:wipebuf)) == 0"
"&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'\n"
" silent exe 'bwipe ' . s:wipebuf\n"
"endif\n"
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 3a84b5d41c..a542bb19dd 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1652,9 +1652,6 @@ failed:
# ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
iconv_close(iconv_fd);
-# ifndef __clang_analyzer__
- iconv_fd = (iconv_t)-1;
-# endif
}
# endif
@@ -2032,7 +2029,7 @@ static char_u *next_fenc(char_u **pp, bool *alloced)
r = enc_canonize(*pp);
*pp += STRLEN(*pp);
} else {
- r = vim_strnsave(*pp, (int)(p - *pp));
+ r = vim_strnsave(*pp, p - *pp);
*pp = p + 1;
p = enc_canonize(r);
xfree(r);
@@ -4675,7 +4672,6 @@ check_timestamps(
)
{
int didit = 0;
- int n;
/* Don't check timestamps while system() or another low-level function may
* cause us to lose and gain focus. */
@@ -4703,7 +4699,7 @@ check_timestamps(
if (buf->b_nwindows > 0) {
bufref_T bufref;
set_bufref(&bufref, buf);
- n = buf_check_timestamp(buf, focus);
+ const int n = buf_check_timestamp(buf);
if (didit < n) {
didit = n;
}
@@ -4773,11 +4769,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
* return 2 if a message has been displayed.
* return 0 otherwise.
*/
-int
-buf_check_timestamp(
- buf_T *buf,
- int focus /* called for GUI focus event */
-)
+int buf_check_timestamp(buf_T *buf)
FUNC_ATTR_NONNULL_ALL
{
int retval = 0;
@@ -5105,8 +5097,8 @@ void buf_reload(buf_T *buf, int orig_mode)
curwin->w_topline = old_topline;
curwin->w_cursor = old_cursor;
check_cursor();
- update_topline();
- keep_filetype = FALSE;
+ update_topline(curwin);
+ keep_filetype = false;
/* Update folds unless they are defined manually. */
FOR_ALL_TAB_WINDOWS(tp, wp) {
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index c53c1546a4..31b905e858 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -215,6 +215,8 @@ EXTERN bool emsg_severe INIT(= false); // use message of next of several
EXTERN int did_endif INIT(= false); // just had ":endif"
EXTERN dict_T vimvardict; // Dictionary with v: variables
EXTERN dict_T globvardict; // Dictionary with g: variables
+/// g: value
+#define globvarht globvardict.dv_hashtab
EXTERN int did_emsg; // set by emsg() when the message
// is displayed or thrown
EXTERN bool called_vim_beep; // set if vim_beep() is called
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 41ae78e996..8bf745966e 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -539,7 +539,7 @@ int main(int argc, char **argv)
// When a startup script or session file setup for diff'ing and
// scrollbind, sync the scrollbind now.
if (curwin->w_p_diff && curwin->w_p_scb) {
- update_topline();
+ update_topline(curwin);
check_scrollbind((linenr_T)0, 0L);
TIME_MSG("diff scrollbinding");
}
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 70225484ec..31dc6b3649 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -975,9 +975,9 @@ void ml_recover(bool checkext)
if (b0p->b0_flags & B0_HAS_FENC) {
int fnsize = B0_FNAME_SIZE_NOCRYPT;
- for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; --p)
- ;
- b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + fnsize - p));
+ for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; p--) {
+ }
+ b0_fenc = vim_strnsave(p, b0p->b0_fname + fnsize - p);
}
mf_put(mfp, hp, false, false); /* release block 0 */
diff --git a/src/nvim/move.c b/src/nvim/move.c
index fdcf6bb189..a6afdc27d9 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -129,98 +129,99 @@ void redraw_for_cursorline(win_T *wp)
*/
void update_topline_redraw(void)
{
- update_topline();
- if (must_redraw)
+ update_topline(curwin);
+ if (must_redraw) {
update_screen(0);
+ }
}
/*
* Update curwin->w_topline to move the cursor onto the screen.
*/
-void update_topline(void)
+void update_topline(win_T *wp)
{
linenr_T old_topline;
int old_topfill;
bool check_topline = false;
bool check_botline = false;
- long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
+ long *so_ptr = wp->w_p_so >= 0 ? &wp->w_p_so : &p_so;
long save_so = *so_ptr;
// If there is no valid screen and when the window height is zero just use
// the cursor line.
- if (!default_grid.chars || curwin->w_height_inner == 0) {
- curwin->w_topline = curwin->w_cursor.lnum;
- curwin->w_botline = curwin->w_topline;
- curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
- curwin->w_viewport_invalid = true;
- curwin->w_scbind_pos = 1;
+ if (!default_grid.chars || wp->w_height_inner == 0) {
+ wp->w_topline = wp->w_cursor.lnum;
+ wp->w_botline = wp->w_topline;
+ wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
+ wp->w_viewport_invalid = true;
+ wp->w_scbind_pos = 1;
return;
}
- check_cursor_moved(curwin);
- if (curwin->w_valid & VALID_TOPLINE)
+ check_cursor_moved(wp);
+ if (wp->w_valid & VALID_TOPLINE) {
return;
+ }
// When dragging with the mouse, don't scroll that quickly
if (mouse_dragging > 0) {
*so_ptr = mouse_dragging - 1;
}
- old_topline = curwin->w_topline;
- old_topfill = curwin->w_topfill;
+ old_topline = wp->w_topline;
+ old_topfill = wp->w_topfill;
// If the buffer is empty, always set topline to 1.
if (BUFEMPTY()) { // special case - file is empty
- if (curwin->w_topline != 1) {
- redraw_later(curwin, NOT_VALID);
+ if (wp->w_topline != 1) {
+ redraw_later(wp, NOT_VALID);
}
- curwin->w_topline = 1;
- curwin->w_botline = 2;
- curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
- curwin->w_viewport_invalid = true;
- curwin->w_scbind_pos = 1;
- }
- /*
- * If the cursor is above or near the top of the window, scroll the window
- * to show the line the cursor is in, with 'scrolloff' context.
- */
- else {
- if (curwin->w_topline > 1) {
- /* If the cursor is above topline, scrolling is always needed.
- * If the cursor is far below topline and there is no folding,
- * scrolling down is never needed. */
- if (curwin->w_cursor.lnum < curwin->w_topline)
+ wp->w_topline = 1;
+ wp->w_botline = 2;
+ wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
+ wp->w_viewport_invalid = true;
+ wp->w_scbind_pos = 1;
+ } else {
+ // If the cursor is above or near the top of the window, scroll the window
+ // to show the line the cursor is in, with 'scrolloff' context.
+ if (wp->w_topline > 1) {
+ // If the cursor is above topline, scrolling is always needed.
+ // If the cursor is far below topline and there is no folding,
+ // scrolling down is never needed.
+ if (wp->w_cursor.lnum < wp->w_topline) {
check_topline = true;
- else if (check_top_offset())
+ } else if (check_top_offset()) {
check_topline = true;
+ }
}
- /* Check if there are more filler lines than allowed. */
- if (!check_topline && curwin->w_topfill > diff_check_fill(curwin,
- curwin->w_topline))
+ // Check if there are more filler lines than allowed.
+ if (!check_topline && wp->w_topfill > diff_check_fill(wp, wp->w_topline)) {
check_topline = true;
+ }
if (check_topline) {
- int halfheight = curwin->w_height_inner / 2 - 1;
+ int halfheight = wp->w_height_inner / 2 - 1;
if (halfheight < 2) {
halfheight = 2;
}
long n;
- if (hasAnyFolding(curwin)) {
- /* Count the number of logical lines between the cursor and
- * topline + p_so (approximation of how much will be
- * scrolled). */
+ if (hasAnyFolding(wp)) {
+ // Count the number of logical lines between the cursor and
+ // topline + p_so (approximation of how much will be
+ // scrolled).
n = 0;
- for (linenr_T lnum = curwin->w_cursor.lnum;
- lnum < curwin->w_topline + *so_ptr; lnum++) {
+ for (linenr_T lnum = wp->w_cursor.lnum;
+ lnum < wp->w_topline + *so_ptr; lnum++) {
n++;
// stop at end of file or when we know we are far off
- if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) {
+ assert(wp->w_buffer != 0);
+ if (lnum >= wp->w_buffer->b_ml.ml_line_count || n >= halfheight) {
break;
}
- (void)hasFolding(lnum, NULL, &lnum);
+ (void)hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL);
}
} else {
- n = curwin->w_topline + *so_ptr - curwin->w_cursor.lnum;
+ n = wp->w_topline + *so_ptr - wp->w_cursor.lnum;
}
/* If we weren't very close to begin with, we scroll to put the
@@ -233,8 +234,8 @@ void update_topline(void)
check_botline = true;
}
} else {
- /* Make sure topline is the first line of a fold. */
- (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+ // Make sure topline is the first line of a fold.
+ (void)hasFoldingWin(wp, wp->w_topline, &wp->w_topline, NULL, true, NULL);
check_botline = true;
}
}
@@ -248,35 +249,36 @@ void update_topline(void)
* for every small change.
*/
if (check_botline) {
- if (!(curwin->w_valid & VALID_BOTLINE_AP))
- validate_botline();
-
- if (curwin->w_botline <= curbuf->b_ml.ml_line_count) {
- if (curwin->w_cursor.lnum < curwin->w_botline) {
- if (((long)curwin->w_cursor.lnum
- >= (long)curwin->w_botline - *so_ptr
- || hasAnyFolding(curwin)
- )) {
+ if (!(wp->w_valid & VALID_BOTLINE_AP)) {
+ validate_botline(wp);
+ }
+
+ assert(wp->w_buffer != 0);
+ if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count) {
+ if (wp->w_cursor.lnum < wp->w_botline) {
+ if (((long)wp->w_cursor.lnum
+ >= (long)wp->w_botline - *so_ptr
+ || hasAnyFolding(wp))) {
lineoff_T loff;
/* Cursor is (a few lines) above botline, check if there are
* 'scrolloff' window lines below the cursor. If not, need to
* scroll. */
- int n = curwin->w_empty_rows;
- loff.lnum = curwin->w_cursor.lnum;
- /* In a fold go to its last line. */
- (void)hasFolding(loff.lnum, NULL, &loff.lnum);
+ int n = wp->w_empty_rows;
+ loff.lnum = wp->w_cursor.lnum;
+ // In a fold go to its last line.
+ (void)hasFoldingWin(wp, loff.lnum, NULL, &loff.lnum, true, NULL);
loff.fill = 0;
- n += curwin->w_filler_rows;
+ n += wp->w_filler_rows;
loff.height = 0;
- while (loff.lnum < curwin->w_botline
- && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0)
+ while (loff.lnum < wp->w_botline
+ && (loff.lnum + 1 < wp->w_botline || loff.fill == 0)
) {
n += loff.height;
if (n >= *so_ptr) {
break;
}
- botline_forw(&loff);
+ botline_forw(wp, &loff);
}
if (n >= *so_ptr) {
// sufficient context, no need to scroll
@@ -289,23 +291,23 @@ void update_topline(void)
}
if (check_botline) {
long line_count = 0;
- if (hasAnyFolding(curwin)) {
- /* Count the number of logical lines between the cursor and
- * botline - p_so (approximation of how much will be
- * scrolled). */
- for (linenr_T lnum = curwin->w_cursor.lnum;
- lnum >= curwin->w_botline - *so_ptr; lnum--) {
+ if (hasAnyFolding(wp)) {
+ // Count the number of logical lines between the cursor and
+ // botline - p_so (approximation of how much will be
+ // scrolled).
+ for (linenr_T lnum = wp->w_cursor.lnum;
+ lnum >= wp->w_botline - *so_ptr; lnum--) {
line_count++;
// stop at end of file or when we know we are far off
- if (lnum <= 0 || line_count > curwin->w_height_inner + 1) {
+ if (lnum <= 0 || line_count > wp->w_height_inner + 1) {
break;
}
(void)hasFolding(lnum, &lnum, NULL);
}
- } else
- line_count = curwin->w_cursor.lnum - curwin->w_botline
- + 1 + *so_ptr;
- if (line_count <= curwin->w_height_inner + 1) {
+ } else {
+ line_count = wp->w_cursor.lnum - wp->w_botline + 1 + *so_ptr;
+ }
+ if (line_count <= wp->w_height_inner + 1) {
scroll_cursor_bot(scrolljump_value(), false);
} else {
scroll_cursor_halfway(false);
@@ -313,25 +315,25 @@ void update_topline(void)
}
}
}
- curwin->w_valid |= VALID_TOPLINE;
- curwin->w_viewport_invalid = true;
- win_check_anchored_floats(curwin);
+ wp->w_valid |= VALID_TOPLINE;
+ wp->w_viewport_invalid = true;
+ win_check_anchored_floats(wp);
/*
* Need to redraw when topline changed.
*/
- if (curwin->w_topline != old_topline
- || curwin->w_topfill != old_topfill
+ if (wp->w_topline != old_topline
+ || wp->w_topfill != old_topfill
) {
dollar_vcol = -1;
- if (curwin->w_skipcol != 0) {
- curwin->w_skipcol = 0;
- redraw_later(curwin, NOT_VALID);
+ if (wp->w_skipcol != 0) {
+ wp->w_skipcol = 0;
+ redraw_later(wp, NOT_VALID);
} else {
- redraw_later(curwin, VALID);
+ redraw_later(wp, VALID);
}
// May need to set w_skipcol when cursor in w_topline.
- if (curwin->w_cursor.lnum == curwin->w_topline) {
+ if (wp->w_cursor.lnum == wp->w_topline) {
validate_cursor();
}
}
@@ -346,7 +348,7 @@ void update_topline_win(win_T* win)
{
win_T *save_curwin;
switch_win(&save_curwin, NULL, win, NULL, true);
- update_topline();
+ update_topline(curwin);
restore_win(save_curwin, NULL, true);
}
@@ -368,7 +370,7 @@ static int scrolljump_value(void)
*/
static bool check_top_offset(void)
{
- long so = get_scrolloff_value();
+ long so = get_scrolloff_value(curwin);
if (curwin->w_cursor.lnum < curwin->w_topline + so
|| hasAnyFolding(curwin)
) {
@@ -378,7 +380,7 @@ static bool check_top_offset(void)
int n = curwin->w_topfill; // always have this context
// Count the visible screen lines above the cursor line.
while (n < so) {
- topline_back(&loff);
+ topline_back(curwin, &loff);
// Stop when included a line above the window.
if (loff.lnum < curwin->w_topline
|| (loff.lnum == curwin->w_topline && loff.fill > 0)
@@ -498,10 +500,11 @@ void changed_line_abv_curs_win(win_T *wp)
/*
* Make sure the value of curwin->w_botline is valid.
*/
-void validate_botline(void)
+void validate_botline(win_T *wp)
{
- if (!(curwin->w_valid & VALID_BOTLINE))
- comp_botline(curwin);
+ if (!(wp->w_valid & VALID_BOTLINE)) {
+ comp_botline(wp);
+ }
}
/*
@@ -539,8 +542,9 @@ int cursor_valid(void)
void validate_cursor(void)
{
check_cursor_moved(curwin);
- if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
- curs_columns(true);
+ if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) {
+ curs_columns(curwin, true);
+ }
}
/*
@@ -720,8 +724,10 @@ int curwin_col_off2(void)
// Compute curwin->w_wcol and curwin->w_virtcol.
// Also updates curwin->w_wrow and curwin->w_cline_row.
// Also updates curwin->w_leftcol.
+// @param may_scroll when true, may scroll horizontally
void curs_columns(
- int may_scroll /* when true, may scroll horizontally */
+ win_T *wp,
+ int may_scroll
)
{
int n;
@@ -729,136 +735,136 @@ void curs_columns(
colnr_T startcol;
colnr_T endcol;
colnr_T prev_skipcol;
- long so = get_scrolloff_value();
- long siso = get_sidescrolloff_value();
+ long so = get_scrolloff_value(wp);
+ long siso = get_sidescrolloff_value(wp);
/*
* First make sure that w_topline is valid (after moving the cursor).
*/
- update_topline();
+ update_topline(wp);
// Next make sure that w_cline_row is valid.
- if (!(curwin->w_valid & VALID_CROW)) {
- curs_rows(curwin);
+ if (!(wp->w_valid & VALID_CROW)) {
+ curs_rows(wp);
}
/*
* Compute the number of virtual columns.
*/
- if (curwin->w_cline_folded)
- /* In a folded line the cursor is always in the first column */
- startcol = curwin->w_virtcol = endcol = curwin->w_leftcol;
- else
- getvvcol(curwin, &curwin->w_cursor,
- &startcol, &(curwin->w_virtcol), &endcol);
+ if (wp->w_cline_folded) {
+ // In a folded line the cursor is always in the first column
+ startcol = wp->w_virtcol = endcol = wp->w_leftcol;
+ } else {
+ getvvcol(wp, &wp->w_cursor, &startcol, &(wp->w_virtcol), &endcol);
+ }
/* remove '$' from change command when cursor moves onto it */
if (startcol > dollar_vcol)
dollar_vcol = -1;
- int extra = curwin_col_off();
- curwin->w_wcol = curwin->w_virtcol + extra;
+ int extra = win_col_off(wp);
+ wp->w_wcol = wp->w_virtcol + extra;
endcol += extra;
- /*
- * Now compute w_wrow, counting screen lines from w_cline_row.
- */
- curwin->w_wrow = curwin->w_cline_row;
+ // Now compute w_wrow, counting screen lines from w_cline_row.
+ wp->w_wrow = wp->w_cline_row;
- int textwidth = curwin->w_width_inner - extra;
+ int textwidth = wp->w_width_inner - extra;
if (textwidth <= 0) {
// No room for text, put cursor in last char of window.
- curwin->w_wcol = curwin->w_width_inner - 1;
- curwin->w_wrow = curwin->w_height_inner - 1;
- } else if (curwin->w_p_wrap
- && curwin->w_width_inner != 0
+ wp->w_wcol = wp->w_width_inner - 1;
+ wp->w_wrow = wp->w_height_inner - 1;
+ } else if (wp->w_p_wrap
+ && wp->w_width_inner != 0
) {
- width = textwidth + curwin_col_off2();
+ width = textwidth + win_col_off2(wp);
- // long line wrapping, adjust curwin->w_wrow
- if (curwin->w_wcol >= curwin->w_width_inner) {
+ // long line wrapping, adjust wp->w_wrow
+ if (wp->w_wcol >= wp->w_width_inner) {
// this same formula is used in validate_cursor_col()
- n = (curwin->w_wcol - curwin->w_width_inner) / width + 1;
- curwin->w_wcol -= n * width;
- curwin->w_wrow += n;
+ n = (wp->w_wcol - wp->w_width_inner) / width + 1;
+ wp->w_wcol -= n * width;
+ wp->w_wrow += n;
/* When cursor wraps to first char of next line in Insert
* mode, the 'showbreak' string isn't shown, backup to first
* column */
if (*p_sbr && *get_cursor_pos_ptr() == NUL
- && curwin->w_wcol == (int)vim_strsize(p_sbr))
- curwin->w_wcol = 0;
+ && wp->w_wcol == (int)vim_strsize(p_sbr)) {
+ wp->w_wcol = 0;
+ }
}
- }
- /* No line wrapping: compute curwin->w_leftcol if scrolling is on and line
- * is not folded.
- * If scrolling is off, curwin->w_leftcol is assumed to be 0 */
- else if (may_scroll
- && !curwin->w_cline_folded
- ) {
- /*
- * If Cursor is left of the screen, scroll rightwards.
- * If Cursor is right of the screen, scroll leftwards
- * If we get closer to the edge than 'sidescrolloff', scroll a little
- * extra
- */
+ } else if (may_scroll
+ && !wp->w_cline_folded
+ ) {
+ // No line wrapping: compute wp->w_leftcol if scrolling is on and line
+ // is not folded.
+ // If scrolling is off, wp->w_leftcol is assumed to be 0
+
+ // If Cursor is left of the screen, scroll rightwards.
+ // If Cursor is right of the screen, scroll leftwards
+ // If we get closer to the edge than 'sidescrolloff', scroll a little
+ // extra
assert(siso <= INT_MAX);
- int off_left = startcol - curwin->w_leftcol - (int)siso;
+ int off_left = startcol - wp->w_leftcol - (int)siso;
int off_right =
- endcol - curwin->w_leftcol - curwin->w_width_inner + (int)siso + 1;
+ endcol - wp->w_leftcol - wp->w_width_inner + (int)siso + 1;
if (off_left < 0 || off_right > 0) {
int diff = (off_left < 0) ? -off_left: off_right;
/* When far off or not enough room on either side, put cursor in
* middle of window. */
int new_leftcol;
- if (p_ss == 0 || diff >= textwidth / 2 || off_right >= off_left)
- new_leftcol = curwin->w_wcol - extra - textwidth / 2;
- else {
+ if (p_ss == 0 || diff >= textwidth / 2 || off_right >= off_left) {
+ new_leftcol = wp->w_wcol - extra - textwidth / 2;
+ } else {
if (diff < p_ss) {
assert(p_ss <= INT_MAX);
diff = (int)p_ss;
}
- if (off_left < 0)
- new_leftcol = curwin->w_leftcol - diff;
- else
- new_leftcol = curwin->w_leftcol + diff;
+ if (off_left < 0) {
+ new_leftcol = wp->w_leftcol - diff;
+ } else {
+ new_leftcol = wp->w_leftcol + diff;
+ }
}
if (new_leftcol < 0)
new_leftcol = 0;
- if (new_leftcol != (int)curwin->w_leftcol) {
- curwin->w_leftcol = new_leftcol;
- win_check_anchored_floats(curwin);
- // screen has to be redrawn with new curwin->w_leftcol
- redraw_later(curwin, NOT_VALID);
+ if (new_leftcol != (int)wp->w_leftcol) {
+ wp->w_leftcol = new_leftcol;
+ win_check_anchored_floats(wp);
+ // screen has to be redrawn with new wp->w_leftcol
+ redraw_later(wp, NOT_VALID);
}
}
- curwin->w_wcol -= curwin->w_leftcol;
- } else if (curwin->w_wcol > (int)curwin->w_leftcol)
- curwin->w_wcol -= curwin->w_leftcol;
- else
- curwin->w_wcol = 0;
+ wp->w_wcol -= wp->w_leftcol;
+ } else if (wp->w_wcol > (int)wp->w_leftcol) {
+ wp->w_wcol -= wp->w_leftcol;
+ } else {
+ wp->w_wcol = 0;
+ }
/* Skip over filler lines. At the top use w_topfill, there
* may be some filler lines above the window. */
- if (curwin->w_cursor.lnum == curwin->w_topline)
- curwin->w_wrow += curwin->w_topfill;
- else
- curwin->w_wrow += diff_check_fill(curwin, curwin->w_cursor.lnum);
+ if (wp->w_cursor.lnum == wp->w_topline) {
+ wp->w_wrow += wp->w_topfill;
+ } else {
+ wp->w_wrow += diff_check_fill(wp, wp->w_cursor.lnum);
+ }
- prev_skipcol = curwin->w_skipcol;
+ prev_skipcol = wp->w_skipcol;
int plines = 0;
- if ((curwin->w_wrow >= curwin->w_height_inner
+ if ((wp->w_wrow >= wp->w_height_inner
|| ((prev_skipcol > 0
- || curwin->w_wrow + so >= curwin->w_height_inner)
+ || wp->w_wrow + so >= wp->w_height_inner)
&& (plines =
- plines_win_nofill(curwin, curwin->w_cursor.lnum, false)) - 1
- >= curwin->w_height_inner))
- && curwin->w_height_inner != 0
- && curwin->w_cursor.lnum == curwin->w_topline
+ plines_win_nofill(wp, wp->w_cursor.lnum, false)) - 1
+ >= wp->w_height_inner))
+ && wp->w_height_inner != 0
+ && wp->w_cursor.lnum == wp->w_topline
&& width > 0
- && curwin->w_width_inner != 0
+ && wp->w_width_inner != 0
) {
/* Cursor past end of screen. Happens with a single line that does
* not fit on screen. Find a skipcol to show the text around the
@@ -867,87 +873,88 @@ void curs_columns(
* 2: Less than "p_so" lines below
* 3: both of them */
extra = 0;
- if (curwin->w_skipcol + so * width > curwin->w_virtcol) {
+ if (wp->w_skipcol + so * width > wp->w_virtcol) {
extra = 1;
}
// Compute last display line of the buffer line that we want at the
// bottom of the window.
if (plines == 0) {
- plines = plines_win(curwin, curwin->w_cursor.lnum, false);
+ plines = plines_win(wp, wp->w_cursor.lnum, false);
}
plines--;
- if (plines > curwin->w_wrow + so) {
+ if (plines > wp->w_wrow + so) {
assert(so <= INT_MAX);
- n = curwin->w_wrow + (int)so;
+ n = wp->w_wrow + (int)so;
} else {
n = plines;
}
- if ((colnr_T)n >= curwin->w_height_inner + curwin->w_skipcol / width) {
+ if ((colnr_T)n >= wp->w_height_inner + wp->w_skipcol / width) {
extra += 2;
}
if (extra == 3 || plines < so * 2) {
// not enough room for 'scrolloff', put cursor in the middle
- n = curwin->w_virtcol / width;
- if (n > curwin->w_height_inner / 2) {
- n -= curwin->w_height_inner / 2;
+ n = wp->w_virtcol / width;
+ if (n > wp->w_height_inner / 2) {
+ n -= wp->w_height_inner / 2;
} else {
n = 0;
}
// don't skip more than necessary
- if (n > plines - curwin->w_height_inner + 1) {
- n = plines - curwin->w_height_inner + 1;
+ if (n > plines - wp->w_height_inner + 1) {
+ n = plines - wp->w_height_inner + 1;
}
- curwin->w_skipcol = n * width;
+ wp->w_skipcol = n * width;
} else if (extra == 1) {
// less then 'scrolloff' lines above, decrease skipcol
assert(so <= INT_MAX);
- extra = (curwin->w_skipcol + (int)so * width - curwin->w_virtcol
+ extra = (wp->w_skipcol + (int)so * width - wp->w_virtcol
+ width - 1) / width;
if (extra > 0) {
- if ((colnr_T)(extra * width) > curwin->w_skipcol)
- extra = curwin->w_skipcol / width;
- curwin->w_skipcol -= extra * width;
+ if ((colnr_T)(extra * width) > wp->w_skipcol) {
+ extra = wp->w_skipcol / width;
+ }
+ wp->w_skipcol -= extra * width;
}
} else if (extra == 2) {
// less then 'scrolloff' lines below, increase skipcol
- endcol = (n - curwin->w_height_inner + 1) * width;
- while (endcol > curwin->w_virtcol) {
+ endcol = (n - wp->w_height_inner + 1) * width;
+ while (endcol > wp->w_virtcol) {
endcol -= width;
}
- if (endcol > curwin->w_skipcol) {
- curwin->w_skipcol = endcol;
+ if (endcol > wp->w_skipcol) {
+ wp->w_skipcol = endcol;
}
}
- curwin->w_wrow -= curwin->w_skipcol / width;
- if (curwin->w_wrow >= curwin->w_height_inner) {
+ wp->w_wrow -= wp->w_skipcol / width;
+ if (wp->w_wrow >= wp->w_height_inner) {
// small window, make sure cursor is in it
- extra = curwin->w_wrow - curwin->w_height_inner + 1;
- curwin->w_skipcol += extra * width;
- curwin->w_wrow -= extra;
+ extra = wp->w_wrow - wp->w_height_inner + 1;
+ wp->w_skipcol += extra * width;
+ wp->w_wrow -= extra;
}
// extra could be either positive or negative
- extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width;
- win_scroll_lines(curwin, 0, extra);
+ extra = ((int)prev_skipcol - (int)wp->w_skipcol) / width;
+ win_scroll_lines(wp, 0, extra);
} else {
- curwin->w_skipcol = 0;
+ wp->w_skipcol = 0;
}
- if (prev_skipcol != curwin->w_skipcol) {
- redraw_later(curwin, NOT_VALID);
+ if (prev_skipcol != wp->w_skipcol) {
+ redraw_later(wp, NOT_VALID);
}
- /* Redraw when w_virtcol changes and 'cursorcolumn' is set */
- if (curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0
+ // Redraw when w_virtcol changes and 'cursorcolumn' is set
+ if (wp->w_p_cuc && (wp->w_valid & VALID_VIRTCOL) == 0
&& !pum_visible()) {
- redraw_later(curwin, SOME_VALID);
+ redraw_later(wp, SOME_VALID);
}
// now w_leftcol is valid, avoid check_cursor_moved() thinking otherwise
- curwin->w_valid_leftcol = curwin->w_leftcol;
+ wp->w_valid_leftcol = wp->w_leftcol;
- curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
+ wp->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
}
/// Compute the screen position of text character at "pos" in window "wp"
@@ -1231,7 +1238,7 @@ void scrolldown_clamp(void)
end_row += curwin->w_cline_height - 1 -
curwin->w_virtcol / curwin->w_width_inner;
}
- if (end_row < curwin->w_height_inner - get_scrolloff_value()) {
+ if (end_row < curwin->w_height_inner - get_scrolloff_value(curwin)) {
if (can_fill) {
++curwin->w_topfill;
check_topfill(curwin, true);
@@ -1271,7 +1278,7 @@ void scrollup_clamp(void)
validate_virtcol();
start_row -= curwin->w_virtcol / curwin->w_width_inner;
}
- if (start_row >= get_scrolloff_value()) {
+ if (start_row >= get_scrolloff_value(curwin)) {
if (curwin->w_topfill > 0) {
curwin->w_topfill--;
} else {
@@ -1289,22 +1296,22 @@ void scrollup_clamp(void)
* Returns the height of the added line in "lp->height".
* Lines above the first one are incredibly high: MAXCOL.
*/
-static void topline_back(lineoff_T *lp)
+static void topline_back(win_T *wp, lineoff_T *lp)
{
- if (lp->fill < diff_check_fill(curwin, lp->lnum)) {
- /* Add a filler line. */
- ++lp->fill;
+ if (lp->fill < diff_check_fill(wp, lp->lnum)) {
+ // Add a filler line
+ lp->fill++;
lp->height = 1;
} else {
--lp->lnum;
lp->fill = 0;
- if (lp->lnum < 1)
+ if (lp->lnum < 1) {
lp->height = MAXCOL;
- else if (hasFolding(lp->lnum, &lp->lnum, NULL))
- /* Add a closed fold */
+ } else if (hasFolding(lp->lnum, &lp->lnum, NULL)) {
+ // Add a closed fold
lp->height = 1;
- else {
- lp->height = plines_nofill(lp->lnum);
+ } else {
+ lp->height = plines_win_nofill(wp, lp->lnum, true);
}
}
}
@@ -1315,22 +1322,23 @@ static void topline_back(lineoff_T *lp)
* Returns the height of the added line in "lp->height".
* Lines below the last one are incredibly high.
*/
-static void botline_forw(lineoff_T *lp)
+static void botline_forw(win_T *wp, lineoff_T *lp)
{
- if (lp->fill < diff_check_fill(curwin, lp->lnum + 1)) {
- /* Add a filler line. */
- ++lp->fill;
+ if (lp->fill < diff_check_fill(wp, lp->lnum + 1)) {
+ // Add a filler line.
+ lp->fill++;
lp->height = 1;
} else {
++lp->lnum;
lp->fill = 0;
- if (lp->lnum > curbuf->b_ml.ml_line_count) {
+ assert(wp->w_buffer != 0);
+ if (lp->lnum > wp->w_buffer->b_ml.ml_line_count) {
lp->height = MAXCOL;
- } else if (hasFolding(lp->lnum, NULL, &lp->lnum)) {
+ } else if (hasFoldingWin(wp, lp->lnum, NULL, &lp->lnum, true, NULL)) {
// Add a closed fold
lp->height = 1;
} else {
- lp->height = plines_nofill(lp->lnum);
+ lp->height = plines_win_nofill(wp, lp->lnum, true);
}
}
}
@@ -1374,7 +1382,7 @@ void scroll_cursor_top(int min_scroll, int always)
linenr_T old_topline = curwin->w_topline;
linenr_T old_topfill = curwin->w_topfill;
linenr_T new_topline;
- int off = (int)get_scrolloff_value();
+ int off = (int)get_scrolloff_value(curwin);
if (mouse_dragging > 0)
off = mouse_dragging - 1;
@@ -1518,7 +1526,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
int old_valid = curwin->w_valid;
int old_empty_rows = curwin->w_empty_rows;
linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number
- long so = get_scrolloff_value();
+ long so = get_scrolloff_value(curwin);
if (set_topbot) {
used = 0;
@@ -1528,7 +1536,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
curwin->w_topline > 1;
curwin->w_topline = loff.lnum) {
loff.lnum = curwin->w_topline;
- topline_back(&loff);
+ topline_back(curwin, &loff);
if (loff.height == MAXCOL
|| used + loff.height > curwin->w_height_inner) {
break;
@@ -1542,8 +1550,9 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
|| curwin->w_topfill != old_topfill
)
curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
- } else
- validate_botline();
+ } else {
+ validate_botline(curwin);
+ }
/* The lines of the cursor line itself are always used. */
used = plines_nofill(cln);
@@ -1586,8 +1595,8 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
break;
}
- /* Add one line above */
- topline_back(&loff);
+ // Add one line above
+ topline_back(curwin, &loff);
if (loff.height == MAXCOL) {
used = MAXCOL;
} else {
@@ -1609,8 +1618,8 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
}
if (boff.lnum < curbuf->b_ml.ml_line_count) {
- /* Add one line below */
- botline_forw(&boff);
+ // Add one line below
+ botline_forw(curwin, &boff);
used += boff.height;
if (used > curwin->w_height_inner) {
break;
@@ -1647,7 +1656,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
boff.lnum = curwin->w_topline - 1;
int i;
for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; ) {
- botline_forw(&boff);
+ botline_forw(curwin, &boff);
i += boff.height;
++line_count;
}
@@ -1701,7 +1710,7 @@ void scroll_cursor_halfway(int atend)
while (topline > 1) {
if (below <= above) { /* add a line below the cursor first */
if (boff.lnum < curbuf->b_ml.ml_line_count) {
- botline_forw(&boff);
+ botline_forw(curwin, &boff);
used += boff.height;
if (used > curwin->w_height_inner) {
break;
@@ -1714,12 +1723,13 @@ void scroll_cursor_halfway(int atend)
}
}
- if (below > above) { /* add a line above the cursor */
- topline_back(&loff);
- if (loff.height == MAXCOL)
+ if (below > above) { // add a line above the cursor
+ topline_back(curwin, &loff);
+ if (loff.height == MAXCOL) {
used = MAXCOL;
- else
+ } else {
used += loff.height;
+ }
if (used > curwin->w_height_inner) {
break;
}
@@ -1751,8 +1761,8 @@ void cursor_correct(void)
* How many lines we would like to have above/below the cursor depends on
* whether the first/last line of the file is on screen.
*/
- int above_wanted = (int)get_scrolloff_value();
- int below_wanted = (int)get_scrolloff_value();
+ int above_wanted = (int)get_scrolloff_value(curwin);
+ int below_wanted = (int)get_scrolloff_value(curwin);
if (mouse_dragging > 0) {
above_wanted = mouse_dragging - 1;
below_wanted = mouse_dragging - 1;
@@ -1764,7 +1774,7 @@ void cursor_correct(void)
below_wanted = max_off;
}
}
- validate_botline();
+ validate_botline(curwin);
if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1
&& mouse_dragging == 0) {
below_wanted = 0;
@@ -1848,21 +1858,19 @@ int onepage(Direction dir, long count)
int retval = OK;
lineoff_T loff;
linenr_T old_topline = curwin->w_topline;
- long so = get_scrolloff_value();
+ long so = get_scrolloff_value(curwin);
if (curbuf->b_ml.ml_line_count == 1) { /* nothing to do */
beep_flush();
return FAIL;
}
- for (; count > 0; --count) {
- validate_botline();
- /*
- * It's an error to move a page up when the first line is already on
- * the screen. It's an error to move a page down when the last line
- * is on the screen and the topline is 'scrolloff' lines from the
- * last line.
- */
+ for (; count > 0; count--) {
+ validate_botline(curwin);
+ // It's an error to move a page up when the first line is already on
+ // the screen. It's an error to move a page down when the last line
+ // is on the screen and the topline is 'scrolloff' lines from the
+ // last line.
if (dir == FORWARD
? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so)
&& curwin->w_botline > curbuf->b_ml.ml_line_count)
@@ -1945,11 +1953,12 @@ int onepage(Direction dir, long count)
* at the bottom of the window. */
n = 0;
while (n <= curwin->w_height_inner && loff.lnum >= 1) {
- topline_back(&loff);
- if (loff.height == MAXCOL)
+ topline_back(curwin, &loff);
+ if (loff.height == MAXCOL) {
n = MAXCOL;
- else
+ } else {
n += loff.height;
+ }
}
if (loff.lnum < 1) { /* at begin of file */
curwin->w_topline = 1;
@@ -1958,11 +1967,11 @@ int onepage(Direction dir, long count)
} else {
/* Go two lines forward again. */
topline_botline(&loff);
- botline_forw(&loff);
- botline_forw(&loff);
+ botline_forw(curwin, &loff);
+ botline_forw(curwin, &loff);
botline_topline(&loff);
- /* We're at the wrong end of a fold now. */
- (void)hasFolding(loff.lnum, &loff.lnum, NULL);
+ // We're at the wrong end of a fold now.
+ (void)hasFoldingWin(curwin, loff.lnum, &loff.lnum, NULL, true, NULL);
/* Always scroll at least one line. Avoid getting stuck on
* very long lines. */
@@ -2046,10 +2055,11 @@ static void get_scroll_overlap(lineoff_T *lp, int dir)
return; /* no overlap */
lineoff_T loff0 = *lp;
- if (dir > 0)
- botline_forw(lp);
- else
- topline_back(lp);
+ if (dir > 0) {
+ botline_forw(curwin, lp);
+ } else {
+ topline_back(curwin, lp);
+ }
int h2 = lp->height;
if (h2 == MAXCOL || h2 + h1 > min_height) {
*lp = loff0; /* no overlap */
@@ -2057,10 +2067,11 @@ static void get_scroll_overlap(lineoff_T *lp, int dir)
}
lineoff_T loff1 = *lp;
- if (dir > 0)
- botline_forw(lp);
- else
- topline_back(lp);
+ if (dir > 0) {
+ botline_forw(curwin, lp);
+ } else {
+ topline_back(curwin, lp);
+ }
int h3 = lp->height;
if (h3 == MAXCOL || h3 + h2 > min_height) {
*lp = loff0; /* no overlap */
@@ -2068,10 +2079,11 @@ static void get_scroll_overlap(lineoff_T *lp, int dir)
}
lineoff_T loff2 = *lp;
- if (dir > 0)
- botline_forw(lp);
- else
- topline_back(lp);
+ if (dir > 0) {
+ botline_forw(curwin, lp);
+ } else {
+ topline_back(curwin, lp);
+ }
int h4 = lp->height;
if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
*lp = loff1; /* 1 line overlap */
@@ -2094,8 +2106,8 @@ void halfpage(bool flag, linenr_T Prenum)
int n = curwin->w_p_scr <= curwin->w_height_inner ? (int)curwin->w_p_scr
: curwin->w_height_inner;
- update_topline();
- validate_botline();
+ update_topline(curwin);
+ validate_botline(curwin);
int room = curwin->w_empty_rows + curwin->w_filler_rows;
if (flag) {
/*
@@ -2255,7 +2267,7 @@ void do_check_cursorbind(void)
// Only scroll when 'scrollbind' hasn't done this.
if (!curwin->w_p_scb) {
- update_topline();
+ update_topline(curwin);
}
curwin->w_redr_status = true;
}
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 68ef4cd41e..a0b439ac45 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -377,6 +377,10 @@ static void request_event(void **argv)
Channel *channel = e->channel;
MsgpackRpcRequestHandler handler = e->handler;
Error error = ERROR_INIT;
+ if (channel->rpc.closed) {
+ // channel was closed, abort any pending requests
+ goto free_ret;
+ }
Object result = handler.fn(channel->id, e->args, &error);
if (e->type == kMessageTypeRequest || ERROR_SET(&error)) {
// Send the response.
@@ -391,6 +395,8 @@ static void request_event(void **argv)
} else {
api_free_object(result);
}
+
+free_ret:
api_free_array(e->args);
channel_decref(channel);
xfree(e);
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 3ecac615b3..4e955667dc 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -168,7 +168,7 @@ static const struct nv_cmd {
{ NL, nv_down, 0, false },
{ Ctrl_K, nv_error, 0, 0 },
{ Ctrl_L, nv_clear, 0, 0 },
- { Ctrl_M, nv_down, 0, true },
+ { CAR, nv_down, 0, true },
{ Ctrl_N, nv_down, NV_STS, false },
{ Ctrl_O, nv_ctrlo, 0, 0 },
{ Ctrl_P, nv_up, NV_STS, false },
@@ -1261,7 +1261,7 @@ static void normal_redraw(NormalState *s)
{
// Before redrawing, make sure w_topline is correct, and w_leftcol
// if lines don't wrap, and w_skipcol if lines wrap.
- update_topline();
+ update_topline(curwin);
validate_cursor();
// If the cursor moves horizontally when 'concealcursor' is active, then the
@@ -1341,7 +1341,7 @@ static int normal_check(VimState *state)
} else if (do_redraw || stuff_empty()) {
// Need to make sure w_topline and w_leftcol are correct before
// normal_check_window_scrolled() is called.
- update_topline();
+ update_topline(curwin);
normal_check_cursor_moved(s);
normal_check_text_changed(s);
@@ -2629,7 +2629,7 @@ do_mouse (
/* Set global flag that we are extending the Visual area with mouse
* dragging; temporarily minimize 'scrolloff'. */
- if (VIsual_active && is_drag && get_scrolloff_value()) {
+ if (VIsual_active && is_drag && get_scrolloff_value(curwin)) {
// In the very first line, allow scrolling one line
if (mouse_row == 0) {
mouse_dragging = 2;
@@ -4135,7 +4135,7 @@ void scroll_redraw(int up, long count)
scrollup(count, true) :
scrolldown(count, true);
- if (get_scrolloff_value()) {
+ if (get_scrolloff_value(curwin)) {
// Adjust the cursor position for 'scrolloff'. Mark w_topline as
// valid, otherwise the screen jumps back at the end of the file.
cursor_correct();
@@ -4185,7 +4185,7 @@ static void nv_zet(cmdarg_T *cap)
int old_fen = curwin->w_p_fen;
bool undo = false;
- int l_p_siso = (int)get_sidescrolloff_value();
+ int l_p_siso = (int)get_sidescrolloff_value(curwin);
assert(l_p_siso <= INT_MAX);
if (ascii_isdigit(nchar)) {
@@ -4253,12 +4253,13 @@ dozet:
/* "z+", "z<CR>" and "zt": put cursor at top of screen */
case '+':
if (cap->count0 == 0) {
- /* No count given: put cursor at the line below screen */
- validate_botline(); /* make sure w_botline is valid */
- if (curwin->w_botline > curbuf->b_ml.ml_line_count)
+ // No count given: put cursor at the line below screen
+ validate_botline(curwin); // make sure w_botline is valid
+ if (curwin->w_botline > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- else
+ } else {
curwin->w_cursor.lnum = curwin->w_botline;
+ }
}
FALLTHROUGH;
case NL:
@@ -5053,7 +5054,7 @@ static void nv_scroll(cmdarg_T *cap)
setpcmark();
if (cap->cmdchar == 'L') {
- validate_botline(); /* make sure curwin->w_botline is valid */
+ validate_botline(curwin); // make sure curwin->w_botline is valid
curwin->w_cursor.lnum = curwin->w_botline - 1;
if (cap->count1 - 1 >= curwin->w_cursor.lnum)
curwin->w_cursor.lnum = 1;
@@ -5074,7 +5075,7 @@ static void nv_scroll(cmdarg_T *cap)
/* Don't count filler lines above the window. */
used -= diff_check_fill(curwin, curwin->w_topline)
- curwin->w_topfill;
- validate_botline(); // make sure w_empty_rows is valid
+ validate_botline(curwin); // make sure w_empty_rows is valid
half = (curwin->w_height_inner - curwin->w_empty_rows + 1) / 2;
for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; n++) {
// Count half he number of filler lines to be "below this
@@ -6653,16 +6654,15 @@ static void nv_g_cmd(cmdarg_T *cap)
VIsual = curwin->w_cursor;
curwin->w_cursor = tpos;
check_cursor();
- update_topline();
- /*
- * When called from normal "g" command: start Select mode when
- * 'selectmode' contains "cmd". When called for K_SELECT, always
- * start Select mode.
- */
- if (cap->arg)
+ update_topline(curwin);
+ // When called from normal "g" command: start Select mode when
+ // 'selectmode' contains "cmd". When called for K_SELECT, always
+ // start Select mode.
+ if (cap->arg) {
VIsual_select = true;
- else
+ } else {
may_start_select('c');
+ }
setmouse();
redraw_curbuf_later(INVERTED);
showmode();
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 8fddb1b561..052b07ed44 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -3554,15 +3554,21 @@ void ex_display(exarg_T *eap)
int name;
char_u *arg = eap->arg;
int clen;
+ char_u type[2];
if (arg != NULL && *arg == NUL)
arg = NULL;
int attr = HL_ATTR(HLF_8);
- /* Highlight title */
- MSG_PUTS_TITLE(_("\n--- Registers ---"));
+ // Highlight title
+ msg_puts_title(_("\nType Name Content"));
for (int i = -1; i < NUM_REGISTERS && !got_int; i++) {
name = get_register_name(i);
+ switch (get_reg_type(name, NULL)) {
+ case kMTLineWise: type[0] = 'l'; break;
+ case kMTCharWise: type[0] = 'c'; break;
+ default: type[0] = 'b'; break;
+ }
if (arg != NULL && vim_strchr(arg, name) == NULL) {
continue; /* did not ask for this register */
@@ -3587,11 +3593,14 @@ void ex_display(exarg_T *eap)
if (yb->y_array != NULL) {
msg_putchar('\n');
+ msg_puts(" ");
+ msg_putchar(type[0]);
+ msg_puts(" ");
msg_putchar('"');
msg_putchar(name);
MSG_PUTS(" ");
- int n = Columns - 6;
+ int n = Columns - 11;
for (size_t j = 0; j < yb->y_size && n > 1; j++) {
if (j) {
MSG_PUTS_ATTR("^J", attr);
@@ -3616,8 +3625,8 @@ void ex_display(exarg_T *eap)
*/
if ((p = get_last_insert()) != NULL
&& (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int) {
- MSG_PUTS("\n\". ");
- dis_msg(p, TRUE);
+ msg_puts("\n c \". ");
+ dis_msg(p, true);
}
/*
@@ -3625,8 +3634,8 @@ void ex_display(exarg_T *eap)
*/
if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
&& !got_int) {
- MSG_PUTS("\n\": ");
- dis_msg(last_cmdline, FALSE);
+ msg_puts("\n c \": ");
+ dis_msg(last_cmdline, false);
}
/*
@@ -3634,8 +3643,8 @@ void ex_display(exarg_T *eap)
*/
if (curbuf->b_fname != NULL
&& (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int) {
- MSG_PUTS("\n\"% ");
- dis_msg(curbuf->b_fname, FALSE);
+ msg_puts("\n c \"% ");
+ dis_msg(curbuf->b_fname, false);
}
/*
@@ -3646,8 +3655,8 @@ void ex_display(exarg_T *eap)
linenr_T dummy;
if (buflist_name_nr(0, &fname, &dummy) != FAIL) {
- MSG_PUTS("\n\"# ");
- dis_msg(fname, FALSE);
+ msg_puts("\n c \"# ");
+ dis_msg(fname, false);
}
}
@@ -3656,8 +3665,8 @@ void ex_display(exarg_T *eap)
*/
if (last_search_pat() != NULL
&& (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int) {
- MSG_PUTS("\n\"/ ");
- dis_msg(last_search_pat(), FALSE);
+ msg_puts("\n c \"/ ");
+ dis_msg(last_search_pat(), false);
}
/*
@@ -3665,8 +3674,8 @@ void ex_display(exarg_T *eap)
*/
if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
&& !got_int) {
- MSG_PUTS("\n\"= ");
- dis_msg(expr_line, FALSE);
+ msg_puts("\n c \"= ");
+ dis_msg(expr_line, false);
}
}
@@ -3676,9 +3685,10 @@ void ex_display(exarg_T *eap)
*/
static void
dis_msg(
- char_u *p,
- int skip_esc /* if TRUE, ignore trailing ESC */
+ const char_u *p,
+ bool skip_esc // if true, ignore trailing ESC
)
+ FUNC_ATTR_NONNULL_ALL
{
int n;
int l;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 7786feddf3..d43dd9ba15 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -4334,6 +4334,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
char buf_old[NUMBUFLEN];
char buf_new[NUMBUFLEN];
char buf_type[7];
+
vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%ld", old_value);
vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%ld", value);
vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
@@ -7151,20 +7152,20 @@ dict_T *get_winbuf_options(const int bufopt)
/// Return the effective 'scrolloff' value for the current window, using the
/// global value when appropriate.
-long get_scrolloff_value(void)
+long get_scrolloff_value(win_T *wp)
{
// Disallow scrolloff in terminal-mode. #11915
if (State & TERM_FOCUS) {
return 0;
}
- return curwin->w_p_so < 0 ? p_so : curwin->w_p_so;
+ return wp->w_p_so < 0 ? p_so : wp->w_p_so;
}
/// Return the effective 'sidescrolloff' value for the current window, using the
/// global value when appropriate.
-long get_sidescrolloff_value(void)
+long get_sidescrolloff_value(win_T *wp)
{
- return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso;
+ return wp->w_p_siso < 0 ? p_siso : wp->w_p_siso;
}
Dictionary get_vimoption(String name, Error *err)
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 64a09dc2b4..df2bfbce34 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2313,6 +2313,7 @@ return {
deny_duplicates=true,
vi_def=true,
secure=true,
+ expand=true,
varname='p_shadafile',
defaults={if_true={vi=""}}
},
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 551a650045..aef7ffa397 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -809,7 +809,7 @@ static int pum_set_selected(int n, int repeat)
no_u_sync++;
win_enter(curwin_save, true);
no_u_sync--;
- update_topline();
+ update_topline(curwin);
}
// Update the screen before drawing the popup menu.
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 9b8cc9ba31..aeac6e4905 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3696,7 +3696,7 @@ void ex_copen(exarg_T *eap)
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = 0;
check_cursor();
- update_topline(); // scroll to show the line
+ update_topline(curwin); // scroll to show the line
}
// Move the cursor in the quickfix window to "lnum".
@@ -3710,7 +3710,7 @@ static void qf_win_goto(win_T *win, linenr_T lnum)
curwin->w_cursor.col = 0;
curwin->w_cursor.coladd = 0;
curwin->w_curswant = 0;
- update_topline(); // scroll to show the line
+ update_topline(curwin); // scroll to show the line
redraw_later(curwin, VALID);
curwin->w_redr_status = true; // update ruler
curwin = old_curwin;
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index fb08cd2727..a2589ac431 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -3724,8 +3724,7 @@ static long regtry(bt_regprog_T *prog,
} else {
if (reg_startzp[i] != NULL && reg_endzp[i] != NULL)
re_extmatch_out->matches[i] =
- vim_strnsave(reg_startzp[i],
- (int)(reg_endzp[i] - reg_startzp[i]));
+ vim_strnsave(reg_startzp[i], reg_endzp[i] - reg_startzp[i]);
}
}
}
@@ -6565,7 +6564,7 @@ static int fill_submatch_list(int argc FUNC_ATTR_UNUSED, typval_T *argv,
if (s == NULL || rsm.sm_match->endp[i] == NULL) {
s = NULL;
} else {
- s = vim_strnsave(s, (int)(rsm.sm_match->endp[i] - s));
+ s = vim_strnsave(s, rsm.sm_match->endp[i] - s);
}
TV_LIST_ITEM_TV(li)->v_type = VAR_STRING;
TV_LIST_ITEM_TV(li)->vval.v_string = s;
@@ -7084,7 +7083,7 @@ char_u *reg_submatch(int no)
if (s == NULL || rsm.sm_match->endp[no] == NULL) {
retval = NULL;
} else {
- retval = vim_strnsave(s, (int)(rsm.sm_match->endp[no] - s));
+ retval = vim_strnsave(s, rsm.sm_match->endp[no] - s);
}
}
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index d38719f396..8b5ee59d40 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -6480,8 +6480,7 @@ static long nfa_regtry(nfa_regprog_T *prog,
if (lpos->start != NULL && lpos->end != NULL)
re_extmatch_out->matches[i] =
- vim_strnsave(lpos->start,
- (int)(lpos->end - lpos->start));
+ vim_strnsave(lpos->start, lpos->end - lpos->start);
}
}
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 2eeeebb88d..a7fd2bfcc6 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -683,7 +683,7 @@ void conceal_check_cursor_line(void)
redrawWinline(curwin, curwin->w_cursor.lnum);
// Need to recompute cursor column, e.g., when starting Visual mode
// without concealing. */
- curs_columns(true);
+ curs_columns(curwin, true);
}
}
@@ -1698,7 +1698,7 @@ static void win_update(win_T *wp, Providers *providers)
const int new_wcol = wp->w_wcol;
recursive = true;
curwin->w_valid &= ~VALID_TOPLINE;
- update_topline(); // may invalidate w_botline again
+ update_topline(curwin); // may invalidate w_botline again
if (old_wcol != new_wcol
&& (wp->w_valid & (VALID_WCOL|VALID_WROW))
@@ -2013,6 +2013,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// end-of-line
int lcs_eol_one = wp->w_p_lcs_chars.eol; // 'eol' until it's been used
int lcs_prec_todo = wp->w_p_lcs_chars.prec; // 'prec' until it's been used
+ bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
// saved "extra" items for when draw_state becomes WL_LINE (again)
int saved_n_extra = 0;
@@ -2196,7 +2197,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
if (wp->w_p_spell
- && foldinfo.fi_lines == 0
+ && !has_fold
&& *wp->w_s->b_p_spl != NUL
&& !GA_EMPTY(&wp->w_s->b_langp)
&& *(char **)(wp->w_s->b_langp.ga_data) != NULL) {
@@ -2299,6 +2300,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// handle 'incsearch' and ":s///c" highlighting
} else if (highlight_match
&& wp == curwin
+ && !has_fold
&& lnum >= curwin->w_cursor.lnum
&& lnum <= curwin->w_cursor.lnum + search_match_lines) {
if (lnum == curwin->w_cursor.lnum) {
@@ -2551,7 +2553,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
cur = wp->w_match_head;
shl_flag = false;
while ((cur != NULL || !shl_flag) && !number_only
- && foldinfo.fi_lines == 0
+ && !has_fold
) {
if (!shl_flag) {
shl = &search_hl;
@@ -3883,8 +3885,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
/* check if line ends before left margin */
if (vcol < v + col - win_col_off(wp))
vcol = v + col - win_col_off(wp);
- /* Get rid of the boguscols now, we want to draw until the right
- * edge for 'cursorcolumn'. */
+ // Get rid of the boguscols now, we want to draw until the right
+ // edge for 'cursorcolumn'.
col -= boguscols;
// boguscols = 0; // Disabled because value never read after this
@@ -7380,7 +7382,7 @@ void screen_resize(int width, int height)
cmdline_pum_display(false);
}
} else {
- update_topline();
+ update_topline(curwin);
if (pum_drawn()) {
// TODO(bfredl): ins_compl_show_pum wants to redraw the screen first.
// For now make sure the nested update_screen(0) won't redraw the
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index ffe51287c5..fc9f53c192 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -173,13 +173,15 @@ static void insert_sign(
const char_u *group, // sign group; NULL for global group
int prio, // sign priority
linenr_T lnum, // line number which gets the mark
- int typenr // typenr of sign we are adding
+ int typenr, // typenr of sign we are adding
+ bool has_text_or_icon // sign has text or icon
)
{
signlist_T *newsign = xmalloc(sizeof(signlist_T));
newsign->id = id;
newsign->lnum = lnum;
newsign->typenr = typenr;
+ newsign->has_text_or_icon = has_text_or_icon;
if (group != NULL) {
newsign->group = sign_group_ref(group);
} else {
@@ -210,13 +212,14 @@ static void insert_sign(
/// Insert a new sign sorted by line number and sign priority.
static void insert_sign_by_lnum_prio(
- buf_T *buf, // buffer to store sign in
- signlist_T *prev, // previous sign entry
- int id, // sign ID
- const char_u *group, // sign group; NULL for global group
- int prio, // sign priority
- linenr_T lnum, // line number which gets the mark
- int typenr // typenr of sign we are adding
+ buf_T *buf, // buffer to store sign in
+ signlist_T *prev, // previous sign entry
+ int id, // sign ID
+ const char_u *group, // sign group; NULL for global group
+ int prio, // sign priority
+ linenr_T lnum, // line number which gets the mark
+ int typenr, // typenr of sign we are adding
+ bool has_text_or_icon // sign has text or icon
)
{
signlist_T *sign;
@@ -234,7 +237,7 @@ static void insert_sign_by_lnum_prio(
sign = prev->next;
}
- insert_sign(buf, prev, sign, id, group, prio, lnum, typenr);
+ insert_sign(buf, prev, sign, id, group, prio, lnum, typenr, has_text_or_icon);
}
/// Get the name of a sign by its typenr.
@@ -342,12 +345,13 @@ static void sign_sort_by_prio_on_line(buf_T *buf, signlist_T *sign)
/// Add the sign into the signlist. Find the right spot to do it though.
void buf_addsign(
- buf_T *buf, // buffer to store sign in
- int id, // sign ID
+ buf_T *buf, // buffer to store sign in
+ int id, // sign ID
const char_u *groupname, // sign group
- int prio, // sign priority
- linenr_T lnum, // line number which gets the mark
- int typenr // typenr of sign we are adding
+ int prio, // sign priority
+ linenr_T lnum, // line number which gets the mark
+ int typenr, // typenr of sign we are adding
+ bool has_text_or_icon // sign has text or icon
)
{
signlist_T *sign; // a sign in the signlist
@@ -363,13 +367,29 @@ void buf_addsign(
sign_sort_by_prio_on_line(buf, sign);
return;
} else if (lnum < sign->lnum) {
- insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr);
+ insert_sign_by_lnum_prio(
+ buf,
+ prev,
+ id,
+ groupname,
+ prio,
+ lnum,
+ typenr,
+ has_text_or_icon);
return;
}
prev = sign;
}
- insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr);
+ insert_sign_by_lnum_prio(
+ buf,
+ prev,
+ id,
+ groupname,
+ prio,
+ lnum,
+ typenr,
+ has_text_or_icon);
}
// For an existing, placed sign "markId" change the type to "typenr".
@@ -786,11 +806,15 @@ static int sign_define_init_text(sign_T *sp, char_u *text)
}
cells += utf_ptr2cells(s);
}
- // Currently must be one or two display cells
- if (s != endp || cells < 1 || cells > 2) {
+ // Currently must be empty, one or two display cells
+ if (s != endp || cells > 2) {
EMSG2(_("E239: Invalid sign text: %s"), text);
return FAIL;
}
+ if (cells < 1) {
+ sp->sn_text = NULL;
+ return OK;
+ }
xfree(sp->sn_text);
// Allocate one byte more if we need to pad up
@@ -939,7 +963,15 @@ int sign_place(
if (lnum > 0) {
// ":sign place {id} line={lnum} name={name} file={fname}":
// place a sign
- buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr);
+ bool has_text_or_icon = sp->sn_text != NULL || sp->sn_icon != NULL;
+ buf_addsign(
+ buf,
+ *sign_id,
+ sign_group,
+ prio,
+ lnum,
+ sp->sn_typenr,
+ has_text_or_icon);
} else {
// ":sign place {id} file={fname}": change sign type
lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr);
diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h
index 687c15bbd6..c898dba890 100644
--- a/src/nvim/sign_defs.h
+++ b/src/nvim/sign_defs.h
@@ -1,6 +1,7 @@
#ifndef NVIM_SIGN_DEFS_H
#define NVIM_SIGN_DEFS_H
+#include <stdbool.h>
#include "nvim/pos.h"
#include "nvim/types.h"
@@ -22,13 +23,14 @@ typedef struct signlist signlist_T;
struct signlist
{
- int id; // unique identifier for each placed sign
- linenr_T lnum; // line number which has this sign
- int typenr; // typenr of sign
- signgroup_T *group; // sign group
- int priority; // priority for highlighting
- signlist_T *next; // next signlist entry
- signlist_T *prev; // previous entry -- for easy reordering
+ int id; // unique identifier for each placed sign
+ linenr_T lnum; // line number which has this sign
+ int typenr; // typenr of sign
+ bool has_text_or_icon; // has text or icon
+ signgroup_T *group; // sign group
+ int priority; // priority for highlighting
+ signlist_T *next; // next signlist entry
+ signlist_T *prev; // previous entry -- for easy reordering
};
// Default sign priority for highlighting
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index e91d560284..4d88df5a3a 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -4186,10 +4186,10 @@ get_syn_options(
arg = skiptowhite(arg);
if (gname_start == arg)
return NULL;
- gname = vim_strnsave(gname_start, (int)(arg - gname_start));
- if (STRCMP(gname, "NONE") == 0)
+ gname = vim_strnsave(gname_start, arg - gname_start);
+ if (STRCMP(gname, "NONE") == 0) {
*opt->sync_idx = NONE_IDX;
- else {
+ } else {
syn_id = syn_name2id(gname);
int i;
for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; )
@@ -4587,7 +4587,7 @@ syn_cmd_region(
while (*key_end && !ascii_iswhite(*key_end) && *key_end != '=')
++key_end;
xfree(key);
- key = vim_strnsave_up(rest, (int)(key_end - rest));
+ key = vim_strnsave_up(rest, key_end - rest);
if (STRCMP(key, "MATCHGROUP") == 0) {
item = ITEM_MATCHGROUP;
} else if (STRCMP(key, "START") == 0) {
@@ -5047,8 +5047,8 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
EMSG2(_("E401: Pattern delimiter not found: %s"), arg);
return NULL;
}
- /* store the pattern and compiled regexp program */
- ci->sp_pattern = vim_strnsave(arg + 1, (int)(end - arg - 1));
+ // store the pattern and compiled regexp program
+ ci->sp_pattern = vim_strnsave(arg + 1, end - arg - 1);
/* Make 'cpoptions' empty, to avoid the 'l' flag */
cpo_save = p_cpo;
@@ -5136,7 +5136,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
arg_end = skiptowhite(arg_start);
next_arg = skipwhite(arg_end);
xfree(key);
- key = vim_strnsave_up(arg_start, (int)(arg_end - arg_start));
+ key = vim_strnsave_up(arg_start, arg_end - arg_start);
if (STRCMP(key, "CCOMMENT") == 0) {
if (!eap->skip)
curwin->w_s->b_syn_sync_flags |= SF_CCOMMENT;
@@ -5195,7 +5195,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
if (!eap->skip) {
/* store the pattern and compiled regexp program */
curwin->w_s->b_syn_linecont_pat =
- vim_strnsave(next_arg + 1, (int)(arg_end - next_arg - 1));
+ vim_strnsave(next_arg + 1, arg_end - next_arg - 1);
curwin->w_s->b_syn_linecont_ic = curwin->w_s->b_syn_ic;
/* Make 'cpoptions' empty, to avoid the 'l' flag */
@@ -5555,18 +5555,17 @@ void ex_syntax(exarg_T *eap)
{
char_u *arg = eap->arg;
char_u *subcmd_end;
- char_u *subcmd_name;
- int i;
syn_cmdlinep = eap->cmdlinep;
- /* isolate subcommand name */
- for (subcmd_end = arg; ASCII_ISALPHA(*subcmd_end); ++subcmd_end)
- ;
- subcmd_name = vim_strnsave(arg, (int)(subcmd_end - arg));
- if (eap->skip) /* skip error messages for all subcommands */
- ++emsg_skip;
- for (i = 0;; ++i) {
+ // isolate subcommand name
+ for (subcmd_end = arg; ASCII_ISALPHA(*subcmd_end); subcmd_end++) {
+ }
+ char_u *const subcmd_name = vim_strnsave(arg, subcmd_end - arg);
+ if (eap->skip) { // skip error messages for all subcommands
+ emsg_skip++;
+ }
+ for (int i = 0;; i++) {
if (subcommands[i].name == NULL) {
EMSG2(_("E410: Invalid :syntax subcommand: %s"), subcmd_name);
break;
@@ -6719,7 +6718,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
}
xfree(key);
key = (char *)vim_strnsave_up((const char_u *)key_start,
- (int)(linep - key_start));
+ linep - key_start);
linep = (const char *)skipwhite((const char_u *)linep);
if (strcmp(key, "NONE") == 0) {
diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim
index 7f6b7dcfec..24d3959f83 100644
--- a/src/nvim/testdir/check.vim
+++ b/src/nvim/testdir/check.vim
@@ -12,6 +12,9 @@ endfunc
" Command to check for the presence of a working option.
command -nargs=1 CheckOption call CheckOption(<f-args>)
func CheckOption(name)
+ if !exists('&' .. a:name)
+ throw 'Checking for non-existent option ' .. a:name
+ endif
if !exists('+' .. a:name)
throw 'Skipped: ' .. a:name .. ' option not supported'
endif
@@ -74,6 +77,14 @@ func CheckCanRunGui()
endif
endfunc
+" Command to check that we are using the GUI
+command CheckGui call CheckGui()
+func CheckGui()
+ if !has('gui_running')
+ throw 'Skipped: only works in the GUI'
+ endif
+endfunc
+
" Command to check that not currently using the GUI
command CheckNotGui call CheckNotGui()
func CheckNotGui()
diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim
index 3377f86126..53704bd094 100644
--- a/src/nvim/testdir/test_clientserver.vim
+++ b/src/nvim/testdir/test_clientserver.vim
@@ -61,6 +61,15 @@ func Test_client_server()
call assert_fails('call remote_send("XXX", ":let testvar = ''yes''\<CR>")', 'E241')
+ call writefile(['one'], 'Xclientfile')
+ let cmd = GetVimProg() .. ' --servername ' .. name .. ' --remote Xclientfile'
+ call system(cmd)
+ call WaitForAssert({-> assert_equal('Xclientfile', remote_expr(name, "bufname()", "", 2))})
+ call WaitForAssert({-> assert_equal('one', remote_expr(name, "getline(1)", "", 2))})
+ call writefile(['one', 'two'], 'Xclientfile')
+ call system(cmd)
+ call WaitForAssert({-> assert_equal('two', remote_expr(name, "getline(2)", "", 2))})
+
" Expression evaluated locally.
if v:servername == ''
call remote_startserver('MYSELF')
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 81f653c393..39f865144a 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -51,6 +51,22 @@ func Test_complete_wildmenu()
call feedkeys(":e Xdir1/\<Tab>\<Down>\<Up>\<Right>\<CR>", 'tx')
call assert_equal('testfile1', getline(1))
+ " this fails in some Unix GUIs, not sure why
+ if !has('unix') || !has('gui_running')
+ " <C-J>/<C-K> mappings to go up/down directories when 'wildcharm' is
+ " different than 'wildchar'.
+ set wildcharm=<C-Z>
+ cnoremap <C-J> <Down><C-Z>
+ cnoremap <C-K> <Up><C-Z>
+ call feedkeys(":e Xdir1/\<Tab>\<C-J>\<CR>", 'tx')
+ call assert_equal('testfile3', getline(1))
+ call feedkeys(":e Xdir1/\<Tab>\<C-J>\<C-K>\<CR>", 'tx')
+ call assert_equal('testfile1', getline(1))
+ set wildcharm=0
+ cunmap <C-J>
+ cunmap <C-K>
+ endif
+
" cleanup
%bwipe
call delete('Xdir1/Xdir2/Xtestfile4')
@@ -62,6 +78,33 @@ func Test_complete_wildmenu()
set nowildmenu
endfunc
+func Test_wildmenu_screendump()
+ CheckScreendump
+
+ let lines =<< trim [SCRIPT]
+ set wildmenu hlsearch
+ [SCRIPT]
+ call writefile(lines, 'XTest_wildmenu')
+
+ let buf = RunVimInTerminal('-S XTest_wildmenu', {'rows': 8})
+ call term_sendkeys(buf, ":vim\<Tab>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_1', {})
+
+ call term_sendkeys(buf, "\<Tab>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_2', {})
+
+ call term_sendkeys(buf, "\<Tab>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_3', {})
+
+ call term_sendkeys(buf, "\<Tab>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_4', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XTest_wildmenu')
+endfunc
+
func Test_map_completion()
if !has('cmdline_compl')
return
@@ -548,6 +591,13 @@ func Test_cmdline_complete_user_names()
endif
endfunc
+func Test_cmdline_complete_bang()
+ if executable('whoami')
+ call feedkeys(":!whoam\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^".*\<whoami\>', @:)
+ endif
+endfunc
+
funct Test_cmdline_complete_languages()
let lang = substitute(execute('language messages'), '.*"\(.*\)"$', '\1', '')
@@ -570,6 +620,17 @@ funct Test_cmdline_complete_languages()
endif
endfunc
+func Test_cmdline_complete_expression()
+ let g:SomeVar = 'blah'
+ for cmd in ['exe', 'echo', 'echon', 'echomsg']
+ call feedkeys(":" .. cmd .. " SomeV\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match('"' .. cmd .. ' SomeVar', @:)
+ call feedkeys(":" .. cmd .. " foo SomeV\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match('"' .. cmd .. ' foo SomeVar', @:)
+ endfor
+ unlet g:SomeVar
+endfunc
+
func Test_cmdline_write_alternatefile()
new
call setline('.', ['one', 'two'])
@@ -819,6 +880,36 @@ func Test_cmdwin_cedit()
delfunc CmdWinType
endfunc
+func Test_cmdwin_restore()
+ CheckScreendump
+
+ let lines =<< trim [SCRIPT]
+ call setline(1, range(30))
+ 2split
+ [SCRIPT]
+ call writefile(lines, 'XTest_restore')
+
+ let buf = RunVimInTerminal('-S XTest_restore', {'rows': 12})
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, "q:")
+ call VerifyScreenDump(buf, 'Test_cmdwin_restore_1', {})
+
+ " normal restore
+ call term_sendkeys(buf, ":q\<CR>")
+ call VerifyScreenDump(buf, 'Test_cmdwin_restore_2', {})
+
+ " restore after setting 'lines' with one window
+ call term_sendkeys(buf, ":close\<CR>")
+ call term_sendkeys(buf, "q:")
+ call term_sendkeys(buf, ":set lines=18\<CR>")
+ call term_sendkeys(buf, ":q\<CR>")
+ call VerifyScreenDump(buf, 'Test_cmdwin_restore_3', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XTest_restore')
+endfunc
+
func Test_buffers_lastused()
" check that buffers are sorted by time when wildmode has lastused
edit bufc " oldest
@@ -894,5 +985,23 @@ func Test_zero_line_search()
q!
endfunc
+func Test_read_shellcmd()
+ CheckUnix
+ if executable('ls')
+ " There should be ls in the $PATH
+ call feedkeys(":r! l\<c-a>\<c-b>\"\<cr>", 'tx')
+ call assert_match('^"r! .*\<ls\>', @:)
+ endif
+
+ if executable('rm')
+ call feedkeys(":r! ++enc=utf-8 r\<c-a>\<c-b>\"\<cr>", 'tx')
+ call assert_notmatch('^"r!.*\<runtest.vim\>', @:)
+ call assert_match('^"r!.*\<rm\>', @:)
+
+ call feedkeys(":r ++enc=utf-8 !rm\<c-a>\<c-b>\"\<cr>", 'tx')
+ call assert_notmatch('^"r.*\<runtest.vim\>', @:)
+ call assert_match('^"r ++enc\S\+ !.*\<rm\>', @:)
+ endif
+endfunc
-" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim
index 9eea27740d..b6d9687560 100644
--- a/src/nvim/testdir/test_digraph.vim
+++ b/src/nvim/testdir/test_digraph.vim
@@ -1,8 +1,8 @@
" Tests for digraphs
-if !has("digraphs")
- finish
-endif
+source check.vim
+CheckFeature digraphs
+source term_util.vim
func Put_Dig(chars)
exe "norm! o\<c-k>".a:chars
@@ -487,4 +487,20 @@ func Test_show_digraph_cp1251()
bwipe!
endfunc
+" Test for the characters displayed on the screen when entering a digraph
+func Test_entering_digraph()
+ CheckRunVimInTerminal
+ let buf = RunVimInTerminal('', {'rows': 6})
+ call term_sendkeys(buf, "i\<C-K>")
+ call term_wait(buf)
+ call assert_equal('?', term_getline(buf, 1))
+ call term_sendkeys(buf, "1")
+ call term_wait(buf)
+ call assert_equal('1', term_getline(buf, 1))
+ call term_sendkeys(buf, "2")
+ call term_wait(buf)
+ call assert_equal('½', term_getline(buf, 1))
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 356a7ce135..2123780f11 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -181,6 +181,7 @@ let s:filename_checks = {
\ 'gdb': ['.gdbinit'],
\ 'gdmo': ['file.mo', 'file.gdmo'],
\ 'gedcom': ['file.ged', 'lltxxxxx.txt'],
+ \ 'gift': ['file.gift'],
\ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG'],
\ 'gitconfig': ['file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig'],
\ 'gitolite': ['gitolite.conf'],
diff --git a/src/nvim/testdir/test_global.vim b/src/nvim/testdir/test_global.vim
index bdeaf8e2cf..7ccf2812ff 100644
--- a/src/nvim/testdir/test_global.vim
+++ b/src/nvim/testdir/test_global.vim
@@ -1,3 +1,4 @@
+source check.vim
func Test_yank_put_clipboard()
new
@@ -10,6 +11,16 @@ func Test_yank_put_clipboard()
bwipe!
endfunc
+func Test_global_set_clipboard()
+ CheckFeature clipboard_working
+ new
+ set clipboard=unnamedplus
+ let @+='clipboard' | g/^/set cb= | let @" = 'unnamed' | put
+ call assert_equal(['','unnamed'], getline(1, '$'))
+ set clipboard&
+ bwipe!
+endfunc
+
func Test_nested_global()
new
call setline(1, ['nothing', 'found', 'found bad', 'bad'])
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 8ef8bbc23a..f71da92bf8 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -178,15 +178,20 @@ func Test_mksession_rtp()
set sessionoptions&
endfunc
-" Verify that arglist is stored correctly to the session file.
func Test_mksession_arglist()
%argdel
next file1 file2 file3 file4
+ new
+ next | next
mksession! Xtest_mks.out
source Xtest_mks.out
call assert_equal(['file1', 'file2', 'file3', 'file4'], argv())
+ call assert_equal(2, argidx())
+ wincmd w
+ call assert_equal(0, argidx())
call delete('Xtest_mks.out')
+ enew | only
argdel *
endfunc
@@ -220,6 +225,53 @@ func Test_mksession_one_buffer_two_windows()
call delete('Xtest_mks.out')
endfunc
+func Test_mksession_lcd_multiple_tabs()
+ tabnew
+ tabnew
+ lcd .
+ tabfirst
+ lcd .
+ mksession! Xtest_mks.out
+ tabonly
+ source Xtest_mks.out
+ call assert_true(haslocaldir(), 'Tab 1 localdir')
+ tabnext 2
+ call assert_true(!haslocaldir(), 'Tab 2 localdir')
+ tabnext 3
+ call assert_true(haslocaldir(), 'Tab 3 localdir')
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_blank_tabs()
+ tabnew
+ tabnew
+ tabnew
+ tabnext 3
+ mksession! Xtest_mks.out
+ tabnew
+ tabnew
+ tabnext 2
+ source Xtest_mks.out
+ call assert_equal(4, tabpagenr('$'), 'session restore should restore number of tabs')
+ call assert_equal(3, tabpagenr(), 'session restore should restore the active tab')
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_blank_windows()
+ split
+ split
+ split
+ 3 wincmd w
+ mksession! Xtest_mks.out
+ split
+ split
+ 2 wincmd w
+ source Xtest_mks.out
+ call assert_equal(4, winnr('$'), 'session restore should restore number of windows')
+ call assert_equal(3, winnr(), 'session restore should restore the active window')
+ call delete('Xtest_mks.out')
+endfunc
+
if has('extra_search')
func Test_mksession_hlsearch()
@@ -356,24 +408,28 @@ func Test_mksession_globals()
set sessionoptions+=globals
" create different global variables
- let g:Global_string = "Sun is shining"
+ let g:Global_string = "Sun is shining\r\n"
let g:Global_count = 100
let g:Global_pi = 3.14
+ let g:Global_neg_float = -2.68
mksession! Xtest_mks.out
unlet g:Global_string
unlet g:Global_count
unlet g:Global_pi
+ unlet g:Global_neg_float
source Xtest_mks.out
- call assert_equal("Sun is shining", g:Global_string)
+ call assert_equal("Sun is shining\r\n", g:Global_string)
call assert_equal(100, g:Global_count)
call assert_equal(3.14, g:Global_pi)
+ call assert_equal(-2.68, g:Global_neg_float)
unlet g:Global_string
unlet g:Global_count
unlet g:Global_pi
+ unlet g:Global_neg_float
call delete('Xtest_mks.out')
set sessionoptions&
endfunc
@@ -432,20 +488,123 @@ func Test_mksession_resize()
for line in lines
if line =~ '^set lines='
let found_resize = v:true
+ break
endif
endfor
- call assert_equal(v:false, found_resize)
+ call assert_false(found_resize)
let lines = readfile('Xtest_mks2.out')
let found_resize = v:false
for line in lines
if line =~ '^set lines='
let found_resize = v:true
+ break
+ endif
+ endfor
+ call assert_true(found_resize)
+
+ call delete('Xtest_mks1.out')
+ call delete('Xtest_mks2.out')
+ set sessionoptions&
+endfunc
+
+" Test for mksession with a named scratch buffer
+func Test_mksession_scratch()
+ set sessionoptions&vi
+ enew | only
+ file Xscratch
+ set buftype=nofile
+ mksession! Xtest_mks.out
+ %bwipe
+ source Xtest_mks.out
+ call assert_equal('Xscratch', bufname(''))
+ call assert_equal('nofile', &buftype)
+ %bwipe
+ call delete('Xtest_mks.out')
+ set sessionoptions&
+endfunc
+
+" Test for mksession with fold options
+func Test_mksession_foldopt()
+ set sessionoptions-=options
+ set sessionoptions+=folds
+ new
+ setlocal foldenable
+ setlocal foldmethod=expr
+ setlocal foldmarker=<<<,>>>
+ setlocal foldignore=%
+ setlocal foldlevel=2
+ setlocal foldminlines=10
+ setlocal foldnestmax=15
+ mksession! Xtest_mks.out
+ close
+ %bwipe
+
+ source Xtest_mks.out
+ call assert_true(&foldenable)
+ call assert_equal('expr', &foldmethod)
+ call assert_equal('<<<,>>>', &foldmarker)
+ call assert_equal('%', &foldignore)
+ call assert_equal(2, &foldlevel)
+ call assert_equal(10, &foldminlines)
+ call assert_equal(15, &foldnestmax)
+
+ close
+ %bwipe
+ set sessionoptions&
+endfunc
+
+" Test for mksession with window position
+func Test_mksession_winpos()
+ if !has('gui_running')
+ " Only applicable in GUI Vim
+ return
+ endif
+ set sessionoptions+=winpos
+ mksession! Xtest_mks.out
+ let found_winpos = v:false
+ let lines = readfile('Xtest_mks.out')
+ for line in lines
+ if line =~ '^winpos '
+ let found_winpos = v:true
+ break
+ endif
+ endfor
+ call assert_true(found_winpos)
+ call delete('Xtest_mks.out')
+ set sessionoptions&
+endfunc
+
+" Test for mksession with 'compatible' option
+func Test_mksession_compatible()
+ throw 'skipped: Nvim does not support "compatible" option'
+ mksession! Xtest_mks1.out
+ set compatible
+ mksession! Xtest_mks2.out
+ set nocp
+
+ let test_success = v:false
+ let lines = readfile('Xtest_mks1.out')
+ for line in lines
+ if line =~ '^if &cp | set nocp | endif'
+ let test_success = v:true
+ break
+ endif
+ endfor
+ call assert_true(test_success)
+
+ let test_success = v:false
+ let lines = readfile('Xtest_mks2.out')
+ for line in lines
+ if line =~ '^if !&cp | set cp | endif'
+ let test_success = v:true
+ break
endif
endfor
- call assert_equal(v:true, found_resize)
+ call assert_true(test_success)
call delete('Xtest_mks1.out')
call delete('Xtest_mks2.out')
+ set compatible&
set sessionoptions&
endfunc
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index 24e02cb385..8d2a768ba0 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -2,6 +2,9 @@
" Tests for register operations
"
+source check.vim
+source view_util.vim
+
" This test must be executed first to check for empty and unset registers.
func Test_aaa_empty_reg_test()
call assert_fails('normal @@', 'E748:')
@@ -52,31 +55,44 @@ func Test_display_registers()
let b = execute('registers')
call assert_equal(a, b)
- call assert_match('^\n--- Registers ---\n'
- \ . '"" a\n'
- \ . '"0 ba\n'
- \ . '"1 b\n'
- \ . '"a b\n'
+ call assert_match('^\nType Name Content\n'
+ \ . ' c "" a\n'
+ \ . ' c "0 ba\n'
+ \ . ' c "1 b\n'
+ \ . ' c "a b\n'
\ . '.*'
- \ . '"- a\n'
+ \ . ' c "- a\n'
\ . '.*'
- \ . '": ls\n'
- \ . '"% file2\n'
- \ . '"# file1\n'
- \ . '"/ bar\n'
- \ . '"= 2\*4', a)
+ \ . ' c ": ls\n'
+ \ . ' c "% file2\n'
+ \ . ' c "# file1\n'
+ \ . ' c "/ bar\n'
+ \ . ' c "= 2\*4', a)
let a = execute('registers a')
- call assert_match('^\n--- Registers ---\n'
- \ . '"a b', a)
+ call assert_match('^\nType Name Content\n'
+ \ . ' c "a b', a)
let a = execute('registers :')
- call assert_match('^\n--- Registers ---\n'
- \ . '": ls', a)
+ call assert_match('^\nType Name Content\n'
+ \ . ' c ": ls', a)
bwipe!
endfunc
+func Test_recording_status_in_ex_line()
+ norm qx
+ redraw!
+ call assert_equal('recording @x', Screenline(&lines))
+ set shortmess=q
+ redraw!
+ call assert_equal('recording', Screenline(&lines))
+ set shortmess&
+ norm q
+ redraw!
+ call assert_equal('', Screenline(&lines))
+endfunc
+
" Check that replaying a typed sequence does not use an Esc and following
" characters as an escape sequence.
func Test_recording_esc_sequence()
@@ -259,9 +275,9 @@ func Test_insert_small_delete()
call setline(1, ['foo foobar bar'])
call cursor(1,1)
exe ":norm! ciw'\<C-R>-'"
- call assert_equal(getline(1), "'foo' foobar bar")
+ call assert_equal("'foo' foobar bar", getline(1))
exe ":norm! w.w."
- call assert_equal(getline(1), "'foo' 'foobar' 'bar'")
+ call assert_equal("'foo' 'foobar' 'bar'", getline(1))
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index 1e6c311374..4bbd722fdb 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -122,9 +122,9 @@ func Test_sign()
call assert_fails("sign define Sign4 text=a\e linehl=Comment", 'E239:')
call assert_fails("sign define Sign4 text=\ea linehl=Comment", 'E239:')
- " Only 1 or 2 character text is allowed
+ " Only 0, 1 or 2 character text is allowed
call assert_fails("sign define Sign4 text=abc linehl=Comment", 'E239:')
- call assert_fails("sign define Sign4 text= linehl=Comment", 'E239:')
+ " call assert_fails("sign define Sign4 text= linehl=Comment", 'E239:')
call assert_fails("sign define Sign4 text=\\ ab linehl=Comment", 'E239:')
" define sign with whitespace
@@ -306,7 +306,7 @@ func Test_sign_invalid_commands()
call assert_fails('sign jump 1 name=', 'E474:')
call assert_fails('sign jump 1 name=Sign1', 'E474:')
call assert_fails('sign jump 1 line=100', '474:')
- call assert_fails('sign define Sign2 text=', 'E239:')
+ " call assert_fails('sign define Sign2 text=', 'E239:')
" Non-numeric identifier for :sign place
call assert_fails("sign place abc line=3 name=Sign1 buffer=" . bufnr(''),
\ 'E474:')
@@ -415,7 +415,7 @@ func Test_sign_funcs()
" Tests for invalid arguments to sign_define()
call assert_fails('call sign_define("sign4", {"text" : "===>"})', 'E239:')
- call assert_fails('call sign_define("sign5", {"text" : ""})', 'E239:')
+ " call assert_fails('call sign_define("sign5", {"text" : ""})', 'E239:')
call assert_fails('call sign_define([])', 'E730:')
call assert_fails('call sign_define("sign6", [])', 'E715:')
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index bc7c69d920..2b6a89647e 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -1,6 +1,7 @@
" Tests for tabpage
source screendump.vim
+source check.vim
function Test_tabpage()
bw!
@@ -222,6 +223,34 @@ function Test_tabpage_with_autocmd()
1tabonly!
endfunction
+" Test autocommands on tab drop
+function Test_tabpage_with_autocmd_tab_drop()
+ augroup TestTabpageGroup
+ au!
+ autocmd TabEnter * call add(s:li, 'TabEnter')
+ autocmd WinEnter * call add(s:li, 'WinEnter')
+ autocmd BufEnter * call add(s:li, 'BufEnter')
+ autocmd TabLeave * call add(s:li, 'TabLeave')
+ autocmd WinLeave * call add(s:li, 'WinLeave')
+ autocmd BufLeave * call add(s:li, 'BufLeave')
+ augroup END
+
+ let s:li = []
+ tab drop test1
+ call assert_equal(['BufLeave', 'BufEnter'], s:li)
+
+ let s:li = []
+ tab drop test2 test3
+ call assert_equal([
+ \ 'TabLeave', 'TabEnter', 'TabLeave', 'TabEnter',
+ \ 'TabLeave', 'WinEnter', 'TabEnter', 'BufEnter',
+ \ 'TabLeave', 'WinEnter', 'TabEnter', 'BufEnter'], s:li)
+
+ autocmd! TestTabpageGroup
+ augroup! TestTabpageGroup
+ 1tabonly!
+endfunction
+
function Test_tabpage_with_tab_modifier()
for n in range(4)
tabedit
@@ -579,4 +608,82 @@ func Test_tabpage_cmdheight()
call delete('XTest_tabpage_cmdheight')
endfunc
+" Return the terminal key code for selecting a tab page from the tabline. This
+" sequence contains the following codes: a CSI (0x9b), KS_TABLINE (0xf0),
+" KS_FILLER (0x58) and then the tab page number.
+func TabLineSelectPageCode(tabnr)
+ return "\x9b\xf0\x58" .. nr2char(a:tabnr)
+endfunc
+
+" Return the terminal key code for opening a new tabpage from the tabpage
+" menu. This sequence consists of the following codes: a CSI (0x9b),
+" KS_TABMENU (0xef), KS_FILLER (0x58), the tab page number and
+" TABLINE_MENU_NEW (2).
+func TabMenuNewItemCode(tabnr)
+ return "\x9b\xef\x58" .. nr2char(a:tabnr) .. nr2char(2)
+endfunc
+
+" Return the terminal key code for closing a tabpage from the tabpage menu.
+" This sequence consists of the following codes: a CSI (0x9b), KS_TABMENU
+" (0xef), KS_FILLER (0x58), the tab page number and TABLINE_MENU_CLOSE (1).
+func TabMenuCloseItemCode(tabnr)
+ return "\x9b\xef\x58" .. nr2char(a:tabnr) .. nr2char(1)
+endfunc
+
+" Test for using the tabpage menu from the insert and normal modes
+func Test_tabline_tabmenu()
+ " only works in GUI
+ CheckGui
+
+ %bw!
+ tabnew
+ tabnew
+ call assert_equal(3, tabpagenr())
+
+ " go to tab page 2 in normal mode
+ call feedkeys(TabLineSelectPageCode(2), "Lx!")
+ call assert_equal(2, tabpagenr())
+
+ " close tab page 3 in normal mode
+ call feedkeys(TabMenuCloseItemCode(3), "Lx!")
+ call assert_equal(2, tabpagenr('$'))
+ call assert_equal(2, tabpagenr())
+
+ " open new tab page before tab page 1 in normal mode
+ call feedkeys(TabMenuNewItemCode(1), "Lx!")
+ call assert_equal(1, tabpagenr())
+ call assert_equal(3, tabpagenr('$'))
+
+ " go to tab page 2 in operator-pending mode (should beep)
+ call assert_beeps('call feedkeys("f" .. TabLineSelectPageCode(2), "Lx!")')
+
+ " open new tab page before tab page 1 in operator-pending mode (should beep)
+ call assert_beeps('call feedkeys("f" .. TabMenuNewItemCode(1), "Lx!")')
+
+ " open new tab page after tab page 3 in normal mode
+ call feedkeys(TabMenuNewItemCode(4), "Lx!")
+ call assert_equal(4, tabpagenr())
+ call assert_equal(4, tabpagenr('$'))
+
+ " go to tab page 2 in insert mode
+ call feedkeys("i" .. TabLineSelectPageCode(2) .. "\<C-C>", "Lx!")
+ call assert_equal(2, tabpagenr())
+
+ " close tab page 2 in insert mode
+ call feedkeys("i" .. TabMenuCloseItemCode(2) .. "\<C-C>", "Lx!")
+ call assert_equal(3, tabpagenr('$'))
+
+ " open new tab page before tab page 3 in insert mode
+ call feedkeys("i" .. TabMenuNewItemCode(3) .. "\<C-C>", "Lx!")
+ call assert_equal(3, tabpagenr())
+ call assert_equal(4, tabpagenr('$'))
+
+ " open new tab page after tab page 4 in insert mode
+ call feedkeys("i" .. TabMenuNewItemCode(5) .. "\<C-C>", "Lx!")
+ call assert_equal(5, tabpagenr())
+ call assert_equal(5, tabpagenr('$'))
+
+ %bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index c630e678fd..bed39d0741 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -850,6 +850,14 @@ func Test_window_resize()
exe other_winnr .. 'resize +1'
call assert_equal(12, winheight(other_winnr))
call assert_equal(&lines - 10 - 3 -2, winheight(0))
+ close
+
+ vsplit
+ wincmd l
+ let other_winnr = winnr('h')
+ call assert_notequal(winnr(), other_winnr)
+ exe 'vert ' .. other_winnr .. 'resize -100'
+ call assert_equal(0, winwidth(other_winnr))
%bwipe!
endfunc
diff --git a/src/nvim/window.c b/src/nvim/window.c
index ad1e1f8f02..00f49724b6 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -4540,7 +4540,7 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
// Might need to scroll the old window before switching, e.g., when the
// cursor was moved.
- update_topline();
+ update_topline(curwin);
// may have to copy the buffer options when 'cpo' contains 'S'
if (wp->w_buffer != curbuf) {
@@ -5013,7 +5013,10 @@ void win_size_save(garray_T *gap)
{
ga_init(gap, (int)sizeof(int), 1);
- ga_grow(gap, win_count() * 2);
+ ga_grow(gap, win_count() * 2 + 1);
+ // first entry is value of 'lines'
+ ((int *)gap->ga_data)[gap->ga_len++] = Rows;
+
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
((int *)gap->ga_data)[gap->ga_len++] =
wp->w_width + wp->w_vsep_width;
@@ -5021,18 +5024,18 @@ void win_size_save(garray_T *gap)
}
}
-/*
- * Restore window sizes, but only if the number of windows is still the same.
- * Does not free the growarray.
- */
+// Restore window sizes, but only if the number of windows is still the same
+// and 'lines' didn't change.
+// Does not free the growarray.
void win_size_restore(garray_T *gap)
+ FUNC_ATTR_NONNULL_ALL
{
- if (win_count() * 2 == gap->ga_len) {
- /* The order matters, because frames contain other frames, but it's
- * difficult to get right. The easy way out is to do it twice. */
- for (int j = 0; j < 2; ++j)
- {
- int i = 0;
+ if (win_count() * 2 + 1 == gap->ga_len
+ && ((int *)gap->ga_data)[0] == Rows) {
+ // The order matters, because frames contain other frames, but it's
+ // difficult to get right. The easy way out is to do it twice.
+ for (int j = 0; j < 2; j++) {
+ int i = 1;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
int width = ((int *)gap->ga_data)[i++];
int height = ((int *)gap->ga_data)[i++];
@@ -5346,6 +5349,8 @@ void win_setwidth_win(int width, win_T *wp)
width = p_wmw;
if (width == 0)
width = 1;
+ } else if (width < 0) {
+ width = 0;
}
if (wp->w_floating) {
wp->w_float_config.width = width;
@@ -5873,10 +5878,10 @@ void scroll_to_fraction(win_T *wp, int prev_height)
}
if (wp == curwin) {
- if (get_scrolloff_value()) {
- update_topline();
+ if (get_scrolloff_value(wp)) {
+ update_topline(wp);
}
- curs_columns(false); // validate w_wrow
+ curs_columns(wp, false); // validate w_wrow
}
if (prev_height > 0) {
wp->w_prev_fraction_row = wp->w_wrow;
@@ -5932,8 +5937,8 @@ void win_set_inner_size(win_T *wp)
changed_line_abv_curs_win(wp);
invalidate_botline_win(wp);
if (wp == curwin) {
- update_topline();
- curs_columns(true); // validate w_wrow
+ update_topline(wp);
+ curs_columns(wp, true); // validate w_wrow
}
redraw_later(wp, NOT_VALID);
}
diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua
index 29cd38ef0d..9ee2570798 100644
--- a/test/functional/api/server_notifications_spec.lua
+++ b/test/functional/api/server_notifications_spec.lua
@@ -3,6 +3,8 @@ local eq, clear, eval, command, nvim, next_msg =
helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim,
helpers.next_msg
local meths = helpers.meths
+local exec_lua = helpers.exec_lua
+local retry = helpers.retry
describe('notify', function()
local channel
@@ -72,4 +74,18 @@ describe('notify', function()
nvim('unsubscribe', 'event1')
eq(2, eval('1+1')) -- Still alive?
end)
+
+ it('cancels stale events on channel close', function()
+ if helpers.pending_win32(pending) then return end
+ local catchan = eval("jobstart(['cat'], {'rpc': v:true})")
+ eq({id=catchan, stream='job', mode='rpc', client = {}}, exec_lua ([[
+ vim.rpcnotify(..., "nvim_call_function", 'chanclose', {..., 'rpc'})
+ vim.rpcnotify(..., "nvim_subscribe", "daily_rant")
+ return vim.api.nvim_get_chan_info(...)
+ ]], catchan))
+ eq(2, eval('1+1')) -- Still alive?
+ eq({false, 'Invalid channel: '..catchan},
+ exec_lua ([[ return {pcall(vim.rpcrequest, ..., 'nvim_eval', '1+1')}]], catchan))
+ retry(nil, 3000, function() eq({}, meths.get_chan_info(catchan)) end) -- cat be dead :(
+ end)
end)
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 1431054494..2c681eb9d8 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -605,10 +605,10 @@ describe('clipboard (with fake clipboard.vim)', function()
{0:~ }|
{4: }|
:registers |
- {1:--- Registers ---} |
- "* some{2:^J}star data{2:^J} |
- "+ such{2:^J}plus{2:^J}stuff |
- ": let g:test_clip['+'] = ['such', 'plus', 'stuff'] |
+ {1:Type Name Content} |
+ l "* some{2:^J}star data{2:^J} |
+ c "+ such{2:^J}plus{2:^J}stuff |
+ c ": let g:test_clip['+'] = ['such', 'plus', 'stuff'] |
{3:Press ENTER or type command to continue}^ |
]], {
[0] = {bold = true, foreground = Screen.colors.Blue},
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 222275eb4d..656f613c6a 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -20,6 +20,7 @@ describe('search highlighting', function()
[2] = {background = colors.Yellow}, -- Search
[3] = {reverse = true},
[4] = {foreground = colors.Red}, -- Message
+ [6] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey}, -- Folded
})
end)
@@ -38,6 +39,21 @@ describe('search highlighting', function()
]])
end)
+ it('is disabled in folded text', function()
+ insert("some text\nmore text")
+ feed_command('1,2fold')
+ feed("gg/text")
+ screen:expect([[
+ {6:+-- 2 lines: some text·················}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ /text^ |
+ ]])
+ end)
+
it('works', function()
insert([[
some text
@@ -455,6 +471,19 @@ describe('search highlighting', function()
{4:search hit BOTTOM, continuing at TOP} |
]])
+ -- check hilights work also in folds
+ feed("zf4j")
+ command("%foldopen")
+ screen:expect([[
+ very {5:spec^ial}{2: te}{6:xt} |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {4:search hit BOTTOM, continuing at TOP} |
+ ]])
+
feed_command("call clearmatches()")
screen:expect([[
very spec{2:^ial te}xt |
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 0ed62b21b2..d1b8de5e4e 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -76,6 +76,28 @@ describe('Signs', function()
]])
end)
+ it('allows signs with no text', function()
+ feed('ia<cr>b<cr><esc>')
+ command('sign define piet1 text= texthl=Search')
+ command('sign place 1 line=1 name=piet1 buffer=1')
+ screen:expect([[
+ a |
+ b |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
it('can be called right after :split', function()
feed('ia<cr>b<cr>c<cr><esc>gg')
-- This used to cause a crash due to :sign using a special redraw
@@ -244,6 +266,50 @@ describe('Signs', function()
]]}
end)
+ it('ignores signs with no icon and text when calculting the signcolumn width', function()
+ feed('ia<cr>b<cr>c<cr><esc>')
+ command('set number')
+ command('set signcolumn=auto:2')
+ command('sign define pietSearch text=>> texthl=Search')
+ command('sign define pietError text= texthl=Error')
+ command('sign place 2 line=1 name=pietError buffer=1')
+ -- no signcolumn with only empty sign
+ screen:expect([[
+ {6: 1 }a |
+ {6: 2 }b |
+ {6: 3 }c |
+ {6: 4 }^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ -- single column with 1 sign with text and one sign without
+ command('sign place 1 line=1 name=pietSearch buffer=1')
+ screen:expect([[
+ {1:>>}{6: 1 }a |
+ {2: }{6: 2 }b |
+ {2: }{6: 3 }c |
+ {2: }{6: ^4 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
it('can have 32bit sign IDs', function()
command('sign define piet text=>> texthl=Search')
command('sign place 100000 line=1 name=piet buffer=1')