aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/api-docs.yml2
-rw-r--r--.github/workflows/backport.yml2
-rw-r--r--.github/workflows/ci.yml43
-rw-r--r--.github/workflows/commitlint.yml4
-rw-r--r--.github/workflows/coverity-scan.yml4
-rwxr-xr-x.github/workflows/env.sh2
-rw-r--r--.github/workflows/labeler.yml4
-rw-r--r--.github/workflows/release.yml26
-rw-r--r--.github/workflows/remove-reviewers-on-draft.yml2
-rw-r--r--.github/workflows/reviews.yml2
-rw-r--r--.github/workflows/vim-patches.yml4
-rw-r--r--.mailmap2
-rw-r--r--runtime/colors/README.txt33
-rw-r--r--runtime/doc/api.txt21
-rw-r--r--runtime/doc/builtin.txt24
-rw-r--r--runtime/doc/cmdline.txt3
-rw-r--r--runtime/doc/deprecated.txt4
-rw-r--r--runtime/doc/dev_style.txt67
-rw-r--r--runtime/doc/eval.txt2
-rw-r--r--runtime/doc/gui.txt3
-rw-r--r--runtime/doc/index.txt20
-rw-r--r--runtime/doc/insert.txt9
-rw-r--r--runtime/doc/intro.txt10
-rw-r--r--runtime/doc/lsp.txt83
-rw-r--r--runtime/doc/map.txt5
-rw-r--r--runtime/doc/options.txt119
-rw-r--r--runtime/doc/quickref.txt3
-rw-r--r--runtime/doc/starting.txt1
-rw-r--r--runtime/doc/syntax.txt6
-rw-r--r--runtime/doc/treesitter.txt2
-rw-r--r--runtime/doc/various.txt10
-rw-r--r--runtime/doc/vim_diff.txt9
-rw-r--r--runtime/ftplugin/spec.vim5
-rw-r--r--runtime/indent/fortran.vim7
-rw-r--r--runtime/indent/postscr.vim4
-rw-r--r--runtime/lua/vim/_editor.lua1
-rw-r--r--runtime/lua/vim/filetype.lua377
-rw-r--r--runtime/lua/vim/filetype/detect.lua843
-rw-r--r--runtime/lua/vim/lsp.lua81
-rw-r--r--runtime/lua/vim/lsp/buf.lua37
-rw-r--r--runtime/lua/vim/lsp/handlers.lua8
-rw-r--r--runtime/lua/vim/lsp/health.lua3
-rw-r--r--runtime/lua/vim/lsp/rpc.lua4
-rw-r--r--runtime/lua/vim/lsp/util.lua33
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua8
-rw-r--r--runtime/optwin.vim3
-rwxr-xr-xsrc/clint.py313
-rw-r--r--src/coverity-model.c69
-rw-r--r--src/nvim/api/autocmd.c12
-rw-r--r--src/nvim/api/extmark.c35
-rw-r--r--src/nvim/api/keysets.lua2
-rw-r--r--src/nvim/api/private/helpers.c11
-rw-r--r--src/nvim/api/ui.c6
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/api/vim.c39
-rw-r--r--src/nvim/api/vimscript.c27
-rw-r--r--src/nvim/assert.h4
-rw-r--r--src/nvim/auevents.lua4
-rw-r--r--src/nvim/autocmd.c85
-rw-r--r--src/nvim/autocmd.h1
-rw-r--r--src/nvim/buffer_defs.h26
-rw-r--r--src/nvim/change.c18
-rw-r--r--src/nvim/change.h11
-rw-r--r--src/nvim/edit.c70
-rw-r--r--src/nvim/eval.c9
-rw-r--r--src/nvim/eval/funcs.c33
-rw-r--r--src/nvim/eval/userfunc.c1
-rw-r--r--src/nvim/event/loop.c2
-rw-r--r--src/nvim/ex_cmds.c15
-rw-r--r--src/nvim/ex_docmd.c45
-rw-r--r--src/nvim/ex_docmd.h1
-rw-r--r--src/nvim/ex_getln.c17
-rw-r--r--src/nvim/ex_session.c13
-rw-r--r--src/nvim/fold.c26
-rw-r--r--src/nvim/fold.h1
-rw-r--r--src/nvim/getchar.c12
-rw-r--r--src/nvim/globals.h9
-rw-r--r--src/nvim/grid.c137
-rw-r--r--src/nvim/grid_defs.h22
-rw-r--r--src/nvim/highlight_defs.h6
-rw-r--r--src/nvim/highlight_group.c2
-rw-r--r--src/nvim/main.c5
-rw-r--r--src/nvim/math.c2
-rw-r--r--src/nvim/mbyte.c22
-rw-r--r--src/nvim/message.c31
-rw-r--r--src/nvim/mouse.c35
-rw-r--r--src/nvim/move.c4
-rw-r--r--src/nvim/normal.c196
-rw-r--r--src/nvim/ops.c12
-rw-r--r--src/nvim/option.c65
-rw-r--r--src/nvim/option_defs.h11
-rw-r--r--src/nvim/options.lua22
-rw-r--r--src/nvim/os/fs.h10
-rw-r--r--src/nvim/os/input.c9
-rw-r--r--src/nvim/os/users.c2
-rw-r--r--src/nvim/po/check.vim6
-rw-r--r--src/nvim/popupmnu.c4
-rw-r--r--src/nvim/quickfix.c4
-rw-r--r--src/nvim/screen.c475
-rw-r--r--src/nvim/screen.h30
-rw-r--r--src/nvim/search.c38
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/strings.c30
-rw-r--r--src/nvim/strings.h2
-rw-r--r--src/nvim/testdir/test_bufline.vim35
-rw-r--r--src/nvim/testdir/test_cmdline.vim12
-rw-r--r--src/nvim/testdir/test_cursor_func.vim5
-rw-r--r--src/nvim/testdir/test_edit.vim39
-rw-r--r--src/nvim/testdir/test_filetype.vim63
-rw-r--r--src/nvim/testdir/test_fold.vim88
-rw-r--r--src/nvim/testdir/test_mksession.vim24
-rw-r--r--src/nvim/testdir/test_normal.vim9
-rw-r--r--src/nvim/testdir/test_tagjump.vim9
-rw-r--r--src/nvim/testdir/test_textformat.vim19
-rw-r--r--src/nvim/ui.c4
-rw-r--r--src/nvim/ui_compositor.c62
-rw-r--r--src/nvim/viml/parser/expressions.c4
-rw-r--r--src/nvim/window.c234
-rw-r--r--test/functional/api/autocmd_spec.lua80
-rw-r--r--test/functional/api/buffer_updates_spec.lua1
-rw-r--r--test/functional/api/vim_spec.lua21
-rw-r--r--test/functional/core/startup_spec.lua4
-rw-r--r--test/functional/editor/mode_insert_spec.lua24
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua88
-rw-r--r--test/functional/legacy/edit_spec.lua25
-rw-r--r--test/functional/legacy/prompt_buffer_spec.lua19
-rw-r--r--test/functional/plugin/lsp_spec.lua108
-rw-r--r--test/functional/terminal/cursor_spec.lua4
-rw-r--r--test/functional/terminal/highlight_spec.lua1
-rw-r--r--test/functional/terminal/scrollback_spec.lua5
-rw-r--r--test/functional/ui/bufhl_spec.lua10
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/float_spec.lua329
-rw-r--r--test/functional/ui/fold_spec.lua61
-rw-r--r--test/functional/ui/global_statusline_spec.lua260
-rw-r--r--test/functional/ui/inccommand_spec.lua24
-rw-r--r--test/functional/ui/messages_spec.lua43
-rw-r--r--test/functional/ui/multigrid_spec.lua222
-rw-r--r--test/functional/ui/output_spec.lua1
-rw-r--r--test/functional/ui/screen.lua8
-rw-r--r--test/functional/ui/searchhl_spec.lua44
-rw-r--r--test/functional/ui/statusline_spec.lua317
-rw-r--r--test/functional/ui/winbar_spec.lua422
-rw-r--r--test/functional/vimscript/execute_spec.lua4
-rw-r--r--test/unit/fixtures/rbuffer.c2
-rw-r--r--test/unit/helpers.lua4
-rw-r--r--test/unit/search_spec.lua24
-rw-r--r--test/unit/strings_spec.lua35
-rw-r--r--third-party/CMakeLists.txt8
149 files changed, 4501 insertions, 2356 deletions
diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml
index ce8ed7996a..167d799c27 100644
--- a/.github/workflows/api-docs.yml
+++ b/.github/workflows/api-docs.yml
@@ -28,7 +28,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 75ee81d368..b5fd22d036 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -15,7 +15,7 @@ jobs:
)
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# required to find all branches
fetch-depth: 0
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9a98c6097c..4657053167 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,7 +29,7 @@ jobs:
env:
CC: gcc
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup common environment variables
run: ./.github/workflows/env.sh lint
@@ -66,8 +66,34 @@ jobs:
ninja-build \
pkg-config
+
+ - name: Cache uncrustify
+ id: cache-uncrustify
+ uses: actions/cache@v3
+ with:
+ path: ${{ env.CACHE_UNCRUSTIFY }}
+ key: ${{ env.UNCRUSTIFY_VERSION }}
+
+ - name: Clone uncrustify
+ if: steps.cache-uncrustify.outputs.cache-hit != 'true'
+ uses: actions/checkout@v3
+ with:
+ repository: uncrustify/uncrustify
+ ref: ${{ env.UNCRUSTIFY_VERSION }}
+ path: uncrustify
+
+ - name: Install uncrustify
+ if: steps.cache-uncrustify.outputs.cache-hit != 'true'
+ run: |
+ source_dir=uncrustify
+ build_dir=uncrustify/build
+ cmake -S $source_dir -B $build_dir -G Ninja -DCMAKE_BUILD_TYPE=Release
+ cmake --build $build_dir
+ mkdir -p $HOME/.cache
+ cp $build_dir/uncrustify ${{ env.CACHE_UNCRUSTIFY }}
+
- name: Cache artifacts
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
${{ env.CACHE_NVIM_DEPS_DIR }}
@@ -92,6 +118,11 @@ jobs:
args: --check runtime/
- if: "!cancelled()"
+ name: uncrustify
+ run: |
+ ${{ env.CACHE_UNCRUSTIFY }} -c ./src/uncrustify.cfg -q --check $(find ./src/nvim -name "*.[ch]") >/dev/null
+
+ - if: "!cancelled()"
name: lualint
run: ./ci/run_lint.sh lualint
@@ -151,7 +182,7 @@ jobs:
CC: ${{ matrix.cc }}
CI_OS_NAME: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup common environment variables
run: ./.github/workflows/env.sh ${{ matrix.flavor }}
@@ -198,7 +229,7 @@ jobs:
run: ./ci/install.sh
- name: Cache dependencies
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
${{ env.CACHE_NVIM_DEPS_DIR }}
@@ -238,9 +269,9 @@ jobs:
DEPS_PREFIX: ${{ format('{0}/nvim-deps/usr', github.workspace) }}
name: windows (MSVC_64)
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
with:
path: ${{ env.DEPS_BUILD_DIR }}
key: ${{ hashFiles('third-party\**') }}
diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml
index f190981322..68be5436f6 100644
--- a/.github/workflows/commitlint.yml
+++ b/.github/workflows/commitlint.yml
@@ -4,12 +4,14 @@ on:
# to merge a PR, it can't be skipped, so use pull_request_target
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review]
+ branches:
+ - 'master'
jobs:
lint-commits:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml
index a6eef47645..064da54456 100644
--- a/.github/workflows/coverity-scan.yml
+++ b/.github/workflows/coverity-scan.yml
@@ -1,14 +1,14 @@
name: Coverity
on:
schedule:
- - cron: '10 0 * * 1' # Run every Monday at 00:10
+ - cron: '10 0 * * *' # Run every day at 00:10
workflow_dispatch:
jobs:
scan:
runs-on: ubuntu-18.04
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Install dependencies
run: |
diff --git a/.github/workflows/env.sh b/.github/workflows/env.sh
index fe7543510e..c3959ac104 100755
--- a/.github/workflows/env.sh
+++ b/.github/workflows/env.sh
@@ -19,6 +19,8 @@ NVIM_LOG_FILE=$GITHUB_WORKSPACE/build/.nvimlog
VALGRIND_LOG=$GITHUB_WORKSPACE/build/log/valgrind-%p.log
CACHE_NVIM_DEPS_DIR=$HOME/.cache/nvim-deps
CACHE_MARKER=$HOME/.cache/nvim-deps/.ci_cache_marker
+CACHE_UNCRUSTIFY=$HOME/.cache/uncrustify
+UNCRUSTIFY_VERSION=uncrustify-0.75.0
CCACHE_BASEDIR=$GITHUB_WORKSPACE
CCACHE_COMPRESS=1
CCACHE_SLOPPINESS=time_macros,file_macro
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index 7845ae92a3..f85f9d0cda 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -10,7 +10,7 @@ jobs:
contents: read
pull-requests: write
steps:
- - uses: actions/labeler@main
+ - uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
sync-labels: ""
@@ -40,7 +40,7 @@ jobs:
permissions:
pull-requests: write
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: 'Request reviewers'
uses: actions/github-script@v6
with:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index a95b57a657..518a30158b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,7 +21,7 @@ jobs:
version: ${{ steps.build.outputs.version }}
release: ${{ steps.build.outputs.release }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install dependencies
@@ -41,12 +41,12 @@ jobs:
make DESTDIR="$GITHUB_WORKSPACE/build/release/nvim-linux64" install
cd "$GITHUB_WORKSPACE/build/"
cpack -C $NVIM_BUILD_TYPE
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: nvim-linux64
path: build/nvim-linux64.tar.gz
retention-days: 1
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: nvim-linux64
path: build/nvim-linux64.deb
@@ -55,7 +55,7 @@ jobs:
appimage:
runs-on: ubuntu-18.04
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install dependencies
@@ -66,12 +66,12 @@ jobs:
run: CC=gcc-11 make appimage-latest
- if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name == 'nightly')
run: CC=gcc-11 make appimage-nightly
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: appimage
path: build/bin/nvim.appimage
retention-days: 1
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: appimage
path: build/bin/nvim.appimage.zsync
@@ -80,7 +80,7 @@ jobs:
macOS:
runs-on: macos-10.15
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install brew packages
@@ -112,7 +112,7 @@ jobs:
fi
done
tar cfz nvim-macos.tar.gz nvim-osx64
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: nvim-macos
path: build/release/nvim-macos.tar.gz
@@ -130,18 +130,18 @@ jobs:
archive: nvim-win64
name: windows (${{ matrix.config }})
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
- run: powershell ci\build.ps1 -NoTests
env:
CONFIGURATION: ${{ matrix.config }}
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: ${{ matrix.archive }}
path: build/${{ matrix.archive }}.zip
retention-days: 1
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: ${{ matrix.archive }}
path: build/${{ matrix.archive }}.msi
@@ -157,9 +157,9 @@ jobs:
steps:
# Must perform checkout first, since it deletes the target directory
# before running, and would therefore delete the downloaded artifacts
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- - uses: actions/download-artifact@v2
+ - uses: actions/download-artifact@v3
- name: Install dependencies
run: |
diff --git a/.github/workflows/remove-reviewers-on-draft.yml b/.github/workflows/remove-reviewers-on-draft.yml
index 64474618b8..f707f79737 100644
--- a/.github/workflows/remove-reviewers-on-draft.yml
+++ b/.github/workflows/remove-reviewers-on-draft.yml
@@ -8,7 +8,7 @@ jobs:
permissions:
pull-requests: write
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: 'Remove reviewers'
uses: actions/github-script@v6
with:
diff --git a/.github/workflows/reviews.yml b/.github/workflows/reviews.yml
index 964f57b871..34ce19d830 100644
--- a/.github/workflows/reviews.yml
+++ b/.github/workflows/reviews.yml
@@ -9,7 +9,7 @@ jobs:
permissions:
pull-requests: write
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: 'Request reviewers'
uses: actions/github-script@v6
with:
diff --git a/.github/workflows/vim-patches.yml b/.github/workflows/vim-patches.yml
index 453d293b0e..45e6b81aed 100644
--- a/.github/workflows/vim-patches.yml
+++ b/.github/workflows/vim-patches.yml
@@ -14,11 +14,11 @@ jobs:
VERSION_BRANCH: marvim/ci-version-update
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
repository: vim/vim
path: ${{ env.VIM_SOURCE_DIR }}
diff --git a/.mailmap b/.mailmap
index 1aa9aa36d8..7e154b4644 100644
--- a/.mailmap
+++ b/.mailmap
@@ -8,7 +8,7 @@ Anmol Sethi <hi@nhooyr.io> <nhooyr@users.noreply.github.com>
BK1603 <chouhan.shreyansh2702@gmail.com> Shreyansh Chouhan
Billy Su <g4691821@gmail.com> Billy SU
Billy Vong <billyvg@gmail.com> <billyvg@users.noreply.github.com>
-Björn Linse <bjorn.linse@gmail.com> bfredl
+bfredl <bjorn.linse@gmail.com>
Carlos Hernandez <carlos@techbyte.ca> <hurricanehrndz@users.noreply.github.com>
Chris Kipp <ckipp@pm.me> ckipp01
Christian Clason <c.clason@uni-graz.at> <christian.clason@uni-due.de>
diff --git a/runtime/colors/README.txt b/runtime/colors/README.txt
index bda0300678..4ea8e5e640 100644
--- a/runtime/colors/README.txt
+++ b/runtime/colors/README.txt
@@ -1,14 +1,18 @@
README.txt for color scheme files
-These files are used for the ":colorscheme" command. They appear in the
+These files are used for the `:colorscheme` command. They appear in the
"Edit/Color Scheme" menu in the GUI.
+The colorschemes were updated for the Vim 9 release. If you don't like the
+changes you can find the old ones here:
+https://github.com/vim/colorschemes/tree/master/legacy_colors
+
Hints for writing a color scheme file:
There are two basic ways to define a color scheme:
-1. Define a new Normal color and set the 'background' option accordingly.
+1. Define a new Normal color and set the 'background' option accordingly. >
set background={light or dark}
highlight clear
@@ -16,7 +20,7 @@ There are two basic ways to define a color scheme:
...
2. Use the default Normal color and automatically adjust to the value of
- 'background'.
+ 'background'. >
highlight clear Normal
set background&
@@ -29,17 +33,17 @@ There are two basic ways to define a color scheme:
...
endif
-You can use ":highlight clear" to reset everything to the defaults, and then
+You can use `:highlight clear` to reset everything to the defaults, and then
change the groups that you want differently. This will also work for groups
that are added in later versions of Vim.
-Note that ":highlight clear" uses the value of 'background', thus set it
+Note that `:highlight clear` uses the value of 'background', thus set it
before this command.
Some attributes (e.g., bold) might be set in the defaults that you want
removed in your color scheme. Use something like "gui=NONE" to remove the
attributes.
In case you want to set 'background' depending on the colorscheme selected,
-this autocmd might be useful:
+this autocmd might be useful: >
autocmd SourcePre */colors/blue_sky.vim set background=dark
@@ -49,7 +53,7 @@ In case you want to tweak a colorscheme after it was loaded, check out the
ColorScheme autocommand event.
To clean up just before loading another colorscheme, use the ColorSchemePre
-autocommand event. For example:
+autocommand event. For example: >
let g:term_ansi_colors = ...
augroup MyColorscheme
@@ -59,20 +63,20 @@ autocommand event. For example:
augroup END
To customize a colorscheme use another name, e.g. "~/.vim/colors/mine.vim",
-and use ":runtime" to load the original colorscheme:
+and use ":runtime" to load the original colorscheme: >
" load the "evening" colorscheme
runtime colors/evening.vim
" change the color of statements
hi Statement ctermfg=Blue guifg=Blue
-To see which highlight group is used where, see ":help highlight-groups" and
-":help group-name".
+To see which highlight group is used where, see `:help highlight-groups` and
+`:help group-name` .
You can use ":highlight" to find out the current colors. Exception: the
ctermfg and ctermbg values are numbers, which are only valid for the current
terminal. Use the color names instead for better portability. See
-":help cterm-colors".
+`:help cterm-colors` .
The default color settings can be found in the source file
"src/nvim/highlight_group.c". Search for "highlight_init".
@@ -86,7 +90,7 @@ please check the following items:
- Does it work in a color terminal as well as in the GUI? Is it consistent?
- Is "g:colors_name" set to a meaningful value? In case of doubt you can do
- it this way:
+ it this way: >
let g:colors_name = expand('<sfile>:t:r')
@@ -121,7 +125,7 @@ please check the following items:
- Try to keep your color scheme simple by avoiding unnecessary logic and
refraining from adding options. The best color scheme is one that only
- requires:
+ requires: >
colorscheme foobar
@@ -136,3 +140,6 @@ that:
- it was made with colortemplate,
and join us at vim/colorschemes: (https://github.com/vim/colorschemes).
+
+
+vim: set ft=help :
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 34c2c31824..58ec9756a2 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -844,8 +844,11 @@ nvim_eval_statusline({str}, {*opts}) *nvim_eval_statusline()*
Treated as single-width even if it isn't.
• highlights: (boolean) Return highlight
information.
+ • use_winbar: (boolean) Evaluate winbar instead of
+ statusline.
• use_tabline: (boolean) Evaluate tabline instead
of statusline. When |TRUE|, {winid} is ignored.
+ Mutually exclusive with {use_winbar}.
Return: ~
Dictionary containing statusline information, with these
@@ -2653,13 +2656,12 @@ nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts})
Creates or updates an extmark.
- To create a new extmark, pass id=0. The extmark id will be
- returned. To move an existing mark, pass its id.
-
- It is also allowed to create a new mark by passing in a
- previously unused id, but the caller must then keep track of
- existing and unused ids itself. (Useful over RPC, to avoid
- waiting for the return value.)
+ By default a new extmark is created when no id is passed in,
+ but it is also possible to create a new mark by passing in a
+ previously unused id or move an existing mark by passing in
+ its id. The caller must then keep track of existing and unused
+ ids itself. (Useful over RPC, to avoid waiting for the return
+ value.)
Using the optional arguments, it is possible to use this to
highlight a range of text, and also to associate virtual text
@@ -3466,6 +3468,8 @@ nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()*
• buf: (number) the expanded value of |<abuf>|
• file: (string) the expanded value of
|<afile>|
+ • data: (any) arbitrary data passed to
+ |nvim_exec_autocmds()|
• command (string) optional: Vim command to
execute on event. Cannot be used with
@@ -3541,6 +3545,9 @@ nvim_exec_autocmds({event}, {*opts}) *nvim_exec_autocmds()*
• modeline (bool) optional: defaults to true.
Process the modeline after the autocommands
|<nomodeline>|.
+ • data (any): arbitrary data to send to the
+ autocommand callback. See
+ |nvim_create_autocmd()| for details.
See also: ~
|:doautocmd|
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index d197a2c62c..cb0b3d3aa6 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -1026,7 +1026,7 @@ chansend({id}, {data}) *chansend()*
char2nr({string} [, {utf8}]) *char2nr()*
- Return number value of the first char in {string}.
+ Return Number value of the first char in {string}.
Examples: >
char2nr(" ") returns 32
char2nr("ABC") returns 65
@@ -1313,13 +1313,13 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
An example: >
let choice = confirm("What do you want?",
- \ "&Apples\n&Oranges\n&Bananas", 2)
+ \ "&Apples\n&Oranges\n&Bananas", 2)
if choice == 0
- echo "make up your mind!"
+ echo "make up your mind!"
elseif choice == 3
- echo "tasteful"
+ echo "tasteful"
else
- echo "I prefer bananas myself."
+ echo "I prefer bananas myself."
endif
< In a GUI dialog, buttons are used. The layout of the buttons
depends on the 'v' flag in 'guioptions'. If it is included,
@@ -1894,8 +1894,8 @@ exists({expr}) The result is a Number, which is |TRUE| if {expr} is
< There must be no space between the symbol (&/$/*/#) and the
name.
There must be no extra characters after the name, although in
- a few cases this is ignored. That may become more strict in
- the future, thus don't count on it!
+ a few cases this is ignored. That may become stricter in the
+ future, thus don't count on it!
Working example: >
exists(":make")
< NOT working example: >
@@ -2680,7 +2680,7 @@ getchar([expr]) *getchar()*
Without [expr] and when [expr] is 0 a whole character or
special key is returned. If it is a single character, the
- result is a number. Use nr2char() to convert it to a String.
+ result is a Number. Use |nr2char()| to convert it to a String.
Otherwise a String is returned with the encoded character.
For a special key it's a String with a sequence of bytes
starting with 0x80 (decimal: 128). This is the same value as
@@ -7612,9 +7612,11 @@ strftime({format} [, {time}]) *strftime()*
GetFormat()->strftime()
strgetchar({str}, {index}) *strgetchar()*
- Get character {index} from {str}. This uses a character
- index, not a byte index. Composing characters are considered
- separate characters here.
+ Get a Number corresponding to the character at {index} in
+ {str}. This uses a zero-based character index, not a byte
+ index. Composing characters are considered separate
+ characters here. Use |nr2char()| to convert the Number to a
+ String.
Also see |strcharpart()| and |strchars()|.
Can also be used as a |method|: >
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index 6228c9238f..23a87505ad 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -1065,8 +1065,7 @@ line contains the command as typed so far. The left column will show a
character that indicates the type of command-line being edited, see
|cmdwin-char|.
-Vim will be in Normal mode when the editor is opened, except when 'insertmode'
-is set.
+Vim will be in Normal mode when the editor is opened.
The height of the window is specified with 'cmdwinheight' (or smaller if there
is no room). The window is always full width and is positioned just above the
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index 13644cf208..e328bd28b5 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -106,11 +106,13 @@ internally and are no longer exposed as part of the API. Instead, use
*vim.lsp.diagnostic.set_underline()*
*vim.lsp.diagnostic.set_virtual_text()*
-LSP Utility Functions ~
+LSP Functions ~
*vim.lsp.util.diagnostics_to_items()* Use |vim.diagnostic.toqflist()| instead.
*vim.lsp.util.set_qflist()* Use |setqflist()| instead.
*vim.lsp.util.set_loclist()* Use |setloclist()| instead.
+*vim.lsp.buf_get_clients()* Use |vim.lsp.get_active_clients()| with
+ {buffer = bufnr} instead.
Lua ~
*vim.register_keystroke_callback()* Use |vim.on_key()| instead.
diff --git a/runtime/doc/dev_style.txt b/runtime/doc/dev_style.txt
index 6f0b862d3f..a2ea1204b5 100644
--- a/runtime/doc/dev_style.txt
+++ b/runtime/doc/dev_style.txt
@@ -913,19 +913,9 @@ Don't use spaces inside parentheses. Always use curly braces. >
...
}
-You must have a space between the `if` and the open parenthesis. You must also
-have a space between the close parenthesis and the curly brace, if you're
-using one. >
-
- if(condition) { // BAD: space missing after IF.
- if (condition){ // BAD: space missing before {.
- if (condition) { // GOOD: proper space after IF and before {.
-
-
Loops and Switch Statements ~
-Annotate non-trivial fall-through between cases. Empty loop bodies should use
-`{}` or `continue`.
+Annotate non-trivial fall-through between cases.
If not conditional on an enumerated value, switch statements should always
have a `default` case (in the case of an enumerated value, the compiler will
@@ -943,16 +933,6 @@ execute, simply `assert`: >
assert(false);
}
-Empty loop bodies should use `{}` or `continue`, but not a single semicolon. >
-
- while (condition) {
- // Repeat test until it returns false.
- }
- for (int i = 0; i < kSomeNumber; i++) {} // GOOD: empty body.
- while (condition) continue; // GOOD: continue indicates no logic.
-
- while (condition); // BAD: looks like part of do/while loop.
-
Pointer Expressions ~
No spaces around period or arrow. Pointer operators do not have trailing
@@ -1009,37 +989,6 @@ expr;`. >
return(result); // return is not a function!
-Preprocessor Directives ~
-
-The hash mark that starts a preprocessor directive should always be at the
-beginning of the line.
-
-Even when preprocessor directives are within the body of indented code, the
-directives should start at the beginning of the line.
-
-Nested directives should add one spaces after the hash mark for each level of
-indentation.
-
- // GOOD: directives at beginning of line >
- if (lopsided_score) {
- #if DISASTER_PENDING // Correct -- Starts at beginning of line
- drop_everything();
- # if NOTIFY // One space after #
- notify_client();
- # endif
- #endif
- BackToNormal();
- }
-
-< // BAD: indented directives >
- if (lopsided_score) {
- #if DISASTER_PENDING // Wrong! The "#if" should be at beginning of line
- drop_everything();
- #endif // Wrong! Do not indent "#endif"
- back_to_normal();
- }
-
-
Horizontal Whitespace ~
Use of horizontal whitespace depends on location. Never put trailing
@@ -1070,14 +1019,6 @@ whitespace at the end of a line.
};
<
- Macros ~
->
- #define FI(x) \ // Don't align \'s in macro definitions.
- foo(); \
- bar(); \
- ...
-<
-
Loops and Conditionals ~
>
if (b) { // Space after the keyword in condition.
@@ -1111,12 +1052,6 @@ Vertical Whitespace ~
Minimize use of vertical whitespace.
-This is more a principle than a rule: don't use blank lines when you don't
-have to. In particular, don't put more than one or two blank lines between
-functions, resist starting functions with a blank line, don't end functions
-with a blank line, and be discriminating with your use of blank lines inside
-functions.
-
The basic principle is: The more code that fits on one screen, the easier it
is to follow and understand the control flow of the program. Of course,
readability can suffer from code being too dense as well as too spread out, so
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index d1686741b4..71f5ad4536 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1366,7 +1366,7 @@ option *expr-option* *E112* *E113*
Examples: >
echo "tabstop is " .. &tabstop
- if &insertmode
+ if &expandtab
Any option name can be used here. See |options|. When using the local value
and there is no buffer-local or window-local value, the global value is used
diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt
index 812259741f..e296141c39 100644
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -224,9 +224,6 @@ some modes:
Cmdline <C-C> <C-\><C-G>
Op-pending <C-C> <C-\><C-G>
-Appending CTRL-\ CTRL-G is for going back to insert mode when 'insertmode' is
-set. |CTRL-\_CTRL-G|
-
Example: >
:amenu File.Next :next^M
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 5c36eaf8e5..ee8a820e53 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -26,7 +26,7 @@ tag char action in Insert mode ~
insert
|i_CTRL-A| CTRL-A insert previously inserted text
|i_CTRL-C| CTRL-C quit insert mode, without checking for
- abbreviation, unless 'insertmode' set.
+ abbreviation
|i_CTRL-D| CTRL-D delete one shiftwidth of indent in the current
line
|i_CTRL-E| CTRL-E insert the character which is below the cursor
@@ -50,7 +50,6 @@ tag char action in Insert mode ~
|i_CTRL-J| CTRL-J same as <CR>
|i_CTRL-K| CTRL-K {char1} {char2}
enter digraph
-|i_CTRL-L| CTRL-L when 'insertmode' set: Leave Insert mode
|i_<CR>| <CR> begin new line
|i_CTRL-M| CTRL-M same as <CR>
|i_CTRL-N| CTRL-N find next match for keyword in front of the
@@ -86,11 +85,10 @@ tag char action in Insert mode ~
|i_CTRL-W| CTRL-W delete word before the cursor
|i_CTRL-X| CTRL-X {mode} enter CTRL-X sub mode, see |i_CTRL-X_index|
|i_CTRL-Y| CTRL-Y insert the character which is above the cursor
-|i_CTRL-Z| CTRL-Z when 'insertmode' set: suspend Vim
-|i_<Esc>| <Esc> end insert mode (unless 'insertmode' set)
+|i_<Esc>| <Esc> end insert mode
|i_CTRL-[| CTRL-[ same as <Esc>
|i_CTRL-\_CTRL-N| CTRL-\ CTRL-N go to Normal mode
-|i_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to mode specified with 'insertmode'
+|i_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to Normal mode
CTRL-\ a - z reserved for extensions
CTRL-\ others not used
|i_CTRL-]| CTRL-] trigger abbreviation
@@ -221,7 +219,7 @@ tag char note action in Normal mode ~
|CTRL-Z| CTRL-Z suspend program (or start new shell)
CTRL-[ <Esc> not used
|CTRL-\_CTRL-N| CTRL-\ CTRL-N go to Normal mode (no-op)
-|CTRL-\_CTRL-G| CTRL-\ CTRL-G go to mode specified with 'insertmode'
+|CTRL-\_CTRL-G| CTRL-\ CTRL-G go to Normal mode (no-op)
CTRL-\ a - z reserved for extensions
CTRL-\ others not used
|CTRL-]| CTRL-] :ta to ident under cursor
@@ -892,7 +890,7 @@ here are those that are different.
tag command note action in Visual mode ~
------------------------------------------------------------------------------
|v_CTRL-\_CTRL-N| CTRL-\ CTRL-N stop Visual mode
-|v_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to mode specified with 'insertmode'
+|v_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to Normal mode
|v_CTRL-A| CTRL-A 2 add N to number in highlighted text
|v_CTRL-C| CTRL-C stop Visual mode
|v_CTRL-G| CTRL-G toggle between Visual mode and Select mode
@@ -1068,8 +1066,7 @@ tag command action in Command-line editing mode ~
|c_<Esc>| <Esc> abandon command-line without executing it
|c_CTRL-[| CTRL-[ same as <Esc>
|c_CTRL-\_CTRL-N| CTRL-\ CTRL-N go to Normal mode, abandon command-line
-|c_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to mode specified with 'insertmode',
- abandon command-line
+|c_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to Normal mode, abandon command-line
CTRL-\ a - d reserved for extensions
|c_CTRL-\_e| CTRL-\ e {expr} replace the command line with the result of
{expr}
@@ -1501,8 +1498,9 @@ tag command action ~
|:recover| :rec[over] recover a file from a swap file
|:redo| :red[o] redo one undone change
|:redir| :redi[r] redirect messages to a file or register
-|:redraw| :redr[aw] force a redraw of the display
-|:redrawstatus| :redraws[tatus] force a redraw of the status line(s)
+|:redraw| :redr[aw] force a redraw of the display
+|:redrawstatus| :redraws[tatus] force a redraw of the status line(s) and
+ window bar(s)
|:redrawtabline| :redrawt[abline] force a redraw of the tabline
|:registers| :reg[isters] display the contents of registers
|:resize| :res[ize] change current window height
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index 7f6662089d..3c5d246a49 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -32,9 +32,6 @@ If you are working in a special language mode when inserting text, see the
'langmap' option, |'langmap'|, on how to avoid switching this mode on and off
all the time.
-If you have 'insertmode' set, <Esc> and a few other keys get another meaning.
-See |'insertmode'|.
-
char action ~
-----------------------------------------------------------------------
*i_CTRL-[* *i_<Esc>*
@@ -335,9 +332,8 @@ that key is interpreted as in Insert mode.
The following keys are special. They stop the current insert, do something,
and then restart insertion. This means you can do something without getting
out of Insert mode. This is very handy if you prefer to use the Insert mode
-all the time, just like editors that don't have a separate Normal mode. You
-may also want to set the 'insertmode' option. You can use CTRL-O if you want
-to map a function key to a command.
+all the time, just like editors that don't have a separate Normal mode. You
+can use CTRL-O if you want to map a function key to a command.
The changes (inserted or deleted characters) before and after these keys can
be undone separately. Only the last change can be redone and always behaves
@@ -378,7 +374,6 @@ CTRL-G CTRL-J cursor one line down, insert start column *i_CTRL-G_CTRL-J*
<S-ScrollWheelRight> move window one page right *i_<S-ScrollWheelRight>*
CTRL-O execute one command, return to Insert mode *i_CTRL-O*
CTRL-\ CTRL-O like CTRL-O but don't move the cursor *i_CTRL-\_CTRL-O*
-CTRL-L when 'insertmode' is set: go to Normal mode *i_CTRL-L*
CTRL-G u break undo sequence, start new change *i_CTRL-G_u*
CTRL-G U don't break undo with next left/right cursor *i_CTRL-G_U*
movement, if the cursor stays within the
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index 4e3dcf850c..0074dc0733 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -424,8 +424,7 @@ Vim has seven BASIC modes:
*Normal* *Normal-mode* *command-mode*
Normal mode In Normal mode you can enter all the normal editor
commands. If you start the editor you are in this
- mode (unless you have set the 'insertmode' option,
- see below). This is also known as command mode.
+ mode. This is also known as command mode.
Visual mode This is like Normal mode, but the movement commands
extend a highlighted area. When a non-movement
@@ -551,8 +550,6 @@ Ex :vi -- -- -- -- --
*6 Go from Select mode to Insert mode by typing a printable character. The
selection is deleted and the character is inserted.
-If the 'insertmode' option is on, editing a file will start in Insert mode.
-
*CTRL-\_CTRL-N* *i_CTRL-\_CTRL-N* *c_CTRL-\_CTRL-N* *v_CTRL-\_CTRL-N*
Additionally the command CTRL-\ CTRL-N or <C-\><C-N> can be used to go to
Normal mode from any other mode. This can be used to make sure Vim is in
@@ -561,10 +558,7 @@ work in Ex mode. When used after a command that takes an argument, such as
|f| or |m|, the timeout set with 'ttimeoutlen' applies.
*CTRL-\_CTRL-G* *i_CTRL-\_CTRL-G* *c_CTRL-\_CTRL-G* *v_CTRL-\_CTRL-G*
-The command CTRL-\ CTRL-G or <C-\><C-G> can be used to go to Insert mode when
-'insertmode' is set. Otherwise it goes to Normal mode. This can be used to
-make sure Vim is in the mode indicated by 'insertmode', without knowing in
-what mode Vim currently is.
+CTRL-\ CTRL-G works the same as |CTRL-\_CTRL-N| for backward compatibility.
*gQ* *mode-Ex* *Ex-mode* *Ex* *EX* *E501*
gQ Switch to Ex mode. This is like typing ":" commands
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 569c570624..af3189a393 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -461,6 +461,39 @@ LspSignatureActiveParameter
==============================================================================
EVENTS *lsp-events*
+ *LspAttach*
+After an LSP client attaches to a buffer. The |autocmd-pattern| is the
+name of the buffer. When used from Lua, the client ID is passed to the
+callback in the "data" table. Example: >
+
+ vim.api.nvim_create_autocmd("LspAttach", {
+ callback = function(args)
+ local bufnr = args.buf
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+ if client.server_capabilities.completionProvider then
+ vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc"
+ end
+ if client.server_capabilities.definitionProvider then
+ vim.bo[bufnr].tagfunc = "v:lua.vim.lsp.tagfunc"
+ end
+ end,
+ })
+<
+ *LspDetach*
+Just before an LSP client detaches from a buffer. The |autocmd-pattern| is the
+name of the buffer. When used from Lua, the client ID is passed to the
+callback in the "data" table. Example: >
+
+ vim.api.nvim_create_autocmd("LspDetach", {
+ callback = function(args)
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+ -- Do something with the client
+ vim.cmd("setlocal tagfunc< omnifunc<")
+ end,
+ })
+<
+In addition, the following |User| |autocommands| are provided:
+
LspProgressUpdate *LspProgressUpdate*
Upon receipt of a progress notification from the server. See
|vim.lsp.util.get_progress_messages()|.
@@ -498,14 +531,6 @@ buf_detach_client({bufnr}, {client_id}) *vim.lsp.buf_detach_client()*
{bufnr} (number) Buffer handle, or 0 for current
{client_id} (number) Client id
-buf_get_clients({bufnr}) *vim.lsp.buf_get_clients()*
- Gets a map of client_id:client pairs for the given buffer,
- where each value is a |vim.lsp.client| object.
-
- Parameters: ~
- {bufnr} (optional, number): Buffer handle, or 0 for
- current
-
buf_is_attached({bufnr}, {client_id}) *vim.lsp.buf_is_attached()*
Checks if a buffer is attached for a particular client.
@@ -696,11 +721,22 @@ formatexpr({opts}) *vim.lsp.formatexpr()*
• timeout_ms (default 500ms). The timeout period
for the formatting request.
-get_active_clients() *vim.lsp.get_active_clients()*
- Gets all active clients.
+get_active_clients({filter}) *vim.lsp.get_active_clients()*
+ Get active clients.
+
+ Parameters: ~
+ {filter} (table|nil) A table with key-value pairs used to
+ filter the returned clients. The available keys
+ are:
+ • id (number): Only return clients with the
+ given id
+ • bufnr (number): Only return clients attached
+ to this buffer
+ • name (string): Only return clients with the
+ given name
Return: ~
- Table of |vim.lsp.client| objects
+ (table) List of |vim.lsp.client| objects
*vim.lsp.get_buffers_by_client_id()*
get_buffers_by_client_id({client_id})
@@ -1015,15 +1051,25 @@ completion({context}) *vim.lsp.buf.completion()*
See also: ~
|vim.lsp.protocol.constants.CompletionTriggerKind|
-declaration() *vim.lsp.buf.declaration()*
+declaration({options}) *vim.lsp.buf.declaration()*
Jumps to the declaration of the symbol under the cursor.
Note:
Many servers do not implement this method. Generally, see
|vim.lsp.buf.definition()| instead.
-definition() *vim.lsp.buf.definition()*
+ Parameters: ~
+ {options} (table|nil) additional options
+ • reuse_win: (boolean) Jump to existing window
+ if buffer is already open.
+
+definition({options}) *vim.lsp.buf.definition()*
Jumps to the definition of the symbol under the cursor.
+ Parameters: ~
+ {options} (table|nil) additional options
+ • reuse_win: (boolean) Jump to existing window
+ if buffer is already open.
+
document_highlight() *vim.lsp.buf.document_highlight()*
Send request to the server to resolve document highlights for
the current text document position. This request can be
@@ -1250,10 +1296,15 @@ signature_help() *vim.lsp.buf.signature_help()*
Displays signature information about the symbol under the
cursor in a floating window.
-type_definition() *vim.lsp.buf.type_definition()*
+type_definition({options}) *vim.lsp.buf.type_definition()*
Jumps to the definition of the type of the symbol under the
cursor.
+ Parameters: ~
+ {options} (table|nil) additional options
+ • reuse_win: (boolean) Jump to existing window
+ if buffer is already open.
+
workspace_symbol({query}) *vim.lsp.buf.workspace_symbol()*
Lists all symbols in the current workspace in the quickfix
window.
@@ -1539,12 +1590,14 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
|shiftwidth|
*vim.lsp.util.jump_to_location()*
-jump_to_location({location}, {offset_encoding})
+jump_to_location({location}, {offset_encoding}, {reuse_win})
Jumps to a location.
Parameters: ~
{location} (table) (`Location`|`LocationLink`)
{offset_encoding} (string) utf-8|utf-16|utf-32 (required)
+ {reuse_win} (boolean) Jump to existing window if
+ buffer is already opened.
Return: ~
`true` if the jump succeeded
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 056e6c3b56..98da68b76a 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -796,9 +796,8 @@ command. For example: >
:noremap j k
This will exchange the cursor up and down commands.
-With the normal :map command, when the 'remap' option is on, mapping takes
-place until the text is found not to be a part of a {lhs}. For example, if
-you use: >
+With the normal :map command mapping takes place until the text is found not
+to be a part of a {lhs}. For example, if you use: >
:map x y
:map y x
Vim will replace x with y, and then y with x, etc. When this has happened
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 4d6f589714..77aa294027 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -776,7 +776,7 @@ A jump table for the options with a short description can be found at |Q_op|.
oldest version of a file.
*'backupcopy'* *'bkc'*
-'backupcopy' 'bkc' string (Vi default for Unix: "yes", otherwise: "auto")
+'backupcopy' 'bkc' string (default: "auto")
global or local to buffer |global-local|
When writing a file and a backup is made, this option tells how it's
done. This is a comma-separated list of words.
@@ -959,7 +959,6 @@ A jump table for the options with a short description can be found at |Q_op|.
(mostly used in |Normal-mode| or |Cmdline-mode|).
esc hitting <Esc> in |Normal-mode|.
hangul Ignored.
- insertmode Pressing <Esc> in 'insertmode'.
lang Calling the beep module for Lua/Mzscheme/TCL.
mess No output available for |g<|.
showmatch Error occurred for 'showmatch' function.
@@ -1192,7 +1191,7 @@ A jump table for the options with a short description can be found at |Q_op|.
(parts of 'cdpath' can be passed to the shell to expand file names).
*'cedit'*
-'cedit' string (Vim default: CTRL-F, Vi default: "")
+'cedit' string (default: CTRL-F)
global
The key used in Command-line Mode to open the command-line window.
Only non-printable keys are allowed.
@@ -1291,8 +1290,6 @@ A jump table for the options with a short description can be found at |Q_op|.
*'cinscopedecls'* *'cinsd'*
'cinscopedecls' 'cinsd' string (default "public,protected,private")
local to buffer
- {not available when compiled without the |+cindent|
- feature}
Keywords that are interpreted as a C++ scope declaration by |cino-g|.
Useful e.g. for working with the Qt framework that defines additional
scope declarations "signals", "public slots" and "private slots": >
@@ -1545,8 +1542,7 @@ A jump table for the options with a short description can be found at |Q_op|.
See 'preserveindent'.
*'cpoptions'* *'cpo'* *cpo*
-'cpoptions' 'cpo' string (Vim default: "aABceFs_",
- Vi default: all flags)
+'cpoptions' 'cpo' string (default: "aABceFs_")
global
A sequence of single character flags. When a character is present
this indicates Vi-compatible behavior. This is used for things where
@@ -2115,7 +2111,7 @@ A jump table for the options with a short description can be found at |Q_op|.
security reasons.
*'display'* *'dy'*
-'display' 'dy' string (default "lastline,msgsep", Vi default: "")
+'display' 'dy' string (default "lastline,msgsep")
global
Change the way text is displayed. This is comma-separated list of
flags:
@@ -2361,9 +2357,8 @@ A jump table for the options with a short description can be found at |Q_op|.
*'fileformats'* *'ffs'*
'fileformats' 'ffs' string (default:
- Vim+Vi Win32: "dos,unix",
- Vim Unix: "unix,dos",
- Vi others: "")
+ Win32: "dos,unix",
+ Unix: "unix,dos")
global
This gives the end-of-line (<EOL>) formats that will be tried when
starting to edit a new buffer and when reading a file into an existing
@@ -2452,6 +2447,7 @@ A jump table for the options with a short description can be found at |Q_op|.
item default Used for ~
stl:c ' ' or '^' statusline of the current window
stlnc:c ' ' or '=' statusline of the non-current windows
+ wbr:c ' ' window bar
horiz:c '─' or '-' horizontal separators |:split|
horizup:c '┴' or '-' upwards facing horizontal separator
horizdown:c '┬' or '-' downwards facing horizontal separator
@@ -2492,6 +2488,7 @@ A jump table for the options with a short description can be found at |Q_op|.
item highlight group ~
stl:c StatusLine |hl-StatusLine|
stlnc:c StatusLineNC |hl-StatusLineNC|
+ wbr:c WinBar |hl-WinBar| or |hl-WinBarNC|
horiz:c WinSeparator |hl-WinSeparator|
horizup:c WinSeparator |hl-WinSeparator|
horizdown:c WinSeparator |hl-WinSeparator|
@@ -2719,7 +2716,7 @@ A jump table for the options with a short description can be found at |Q_op|.
character and white space.
*'formatoptions'* *'fo'*
-'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt")
+'formatoptions' 'fo' string (default: "tcqj")
local to buffer
This is a sequence of letters which describes how automatic
formatting is to be done. See |fo-table|. When the 'paste' option is
@@ -3151,7 +3148,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'hidden' is set for one command with ":hide {command}" |:hide|.
*'history'* *'hi'*
-'history' 'hi' number (Vim default: 10000, Vi default: 0)
+'history' 'hi' number (default: 10000)
global
A history of ":" commands, and a history of previous search patterns
is remembered. This option decides how many entries may be stored in
@@ -3414,31 +3411,6 @@ A jump table for the options with a short description can be found at |Q_op|.
and there is a letter before it, the completed part is made uppercase.
With 'noinfercase' the match is used as-is.
- *'insertmode'* *'im'* *'noinsertmode'* *'noim'*
-'insertmode' 'im' boolean (default off)
- global
- Makes Vim work in a way that Insert mode is the default mode. Useful
- if you want to use Vim as a modeless editor.
- These Insert mode commands will be useful:
- - Use the cursor keys to move around.
- - Use CTRL-O to execute one Normal mode command |i_CTRL-O|. When
- this is a mapping, it is executed as if 'insertmode' was off.
- Normal mode remains active until the mapping is finished.
- - Use CTRL-L to execute a number of Normal mode commands, then use
- <Esc> to get back to Insert mode. Note that CTRL-L moves the cursor
- left, like <Esc> does when 'insertmode' isn't set. |i_CTRL-L|
-
- These items change when 'insertmode' is set:
- - when starting to edit of a file, Vim goes to Insert mode.
- - <Esc> in Insert mode is a no-op and beeps.
- - <Esc> in Normal mode makes Vim go to Insert mode.
- - CTRL-L in Insert mode is a command, it is not inserted.
- - CTRL-Z in Insert mode suspends Vim, see |CTRL-Z|. *i_CTRL-Z*
- However, when <Esc> is used inside a mapping, it behaves like
- 'insertmode' was not set. This was done to be able to use the same
- mappings with 'insertmode' set or not set.
- When executing commands with |:normal| 'insertmode' is not used.
-
*'isfname'* *'isf'*
'isfname' 'isf' string (default for Windows:
"@,48-57,/,\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,="
@@ -3506,8 +3478,7 @@ A jump table for the options with a short description can be found at |Q_op|.
change 'iskeyword' instead.
*'iskeyword'* *'isk'*
-'iskeyword' 'isk' string (default: @,48-57,_,192-255
- Vi default: @,48-57,_)
+'iskeyword' 'isk' string (default: @,48-57,_,192-255)
local to buffer
Keywords are used in searching and recognizing with many commands:
"w", "*", "[i", etc. It is also used for "\k" in a |pattern|. See
@@ -3777,8 +3748,7 @@ A jump table for the options with a short description can be found at |Q_op|.
changing the way tabs are displayed.
*'listchars'* *'lcs'*
-'listchars' 'lcs' string (default: "tab:> ,trail:-,nbsp:+"
- Vi default: "eol:$")
+'listchars' 'lcs' string (default: "tab:> ,trail:-,nbsp:+")
global or local to window |global-local|
Strings to use in 'list' mode and for the |:list| command. It is a
comma-separated list of string settings.
@@ -4046,8 +4016,7 @@ A jump table for the options with a short description can be found at |Q_op|.
This option cannot be set from a |modeline| or in the |sandbox|.
*'modeline'* *'ml'* *'nomodeline'* *'noml'*
-'modeline' 'ml' boolean (Vim default: on (off for root),
- Vi default: off)
+'modeline' 'ml' boolean (default: on (off for root))
local to buffer
If 'modeline' is on 'modelines' gives the number of lines that is
checked for set commands. If 'modeline' is off or 'modelines' is zero
@@ -4102,7 +4071,7 @@ A jump table for the options with a short description can be found at |Q_op|.
when using "rA" on an "A".
*'more'* *'nomore'*
-'more' boolean (Vim default: on, Vi default: off)
+'more' boolean (default: on)
global
When on, listings pause when the whole screen is filled. You will get
the |more-prompt|. When this option is off there are no pauses, the
@@ -4357,7 +4326,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|there | 4 there | 1 there | 1 there
*'numberwidth'* *'nuw'*
-'numberwidth' 'nuw' number (Vim default: 4 Vi default: 8)
+'numberwidth' 'nuw' number (default: 4)
local to window
Minimal number of columns to use for the line number. Only relevant
when the 'number' or 'relativenumber' option is set or printing lines
@@ -4798,15 +4767,6 @@ A jump table for the options with a short description can be found at |Q_op|.
'number', see |number_relativenumber| for all combinations of the two
options.
- *'remap'* *'noremap'*
-'remap' boolean (default on)
- global
- Allows for mappings to work recursively. If you do not want this for
- a single entry, use the :noremap[!] command.
- NOTE: To avoid portability problems with Vim scripts, always keep
- this option at the default "on". Only switch it off when working with
- old Vi scripts.
-
*'report'*
'report' number (default 2)
global
@@ -5122,9 +5082,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'sessionoptions'* *'ssop'*
'sessionoptions' 'ssop' string (default: "blank,buffers,curdir,folds,
- help,tabpages,winsize"
- Vi default: "blank,buffers,curdir,folds,
- help,options,tabpages,winsize")
+ help,tabpages,winsize")
global
Changes the effect of the |:mksession| command. It is a comma-
separated list of words. Each word enables saving and restoring
@@ -5164,10 +5122,9 @@ A jump table for the options with a short description can be found at |Q_op|.
If you leave out "options" many things won't work well after restoring
the session.
*'shada'* *'sd'* *E526* *E527* *E528*
-'shada' 'sd' string (Vim default for
+'shada' 'sd' string (default for
Win32: !,'100,<50,s10,h,rA:,rB:
- others: !,'100,<50,s10,h
- Vi default: "")
+ others: !,'100,<50,s10,h)
global
When non-empty, the shada file is read upon startup and written
when exiting Vim (see |shada-file|). The string should be a comma-
@@ -5445,7 +5402,7 @@ A jump table for the options with a short description can be found at |Q_op|.
< Also see 'completeslash'.
*'shelltemp'* *'stmp'* *'noshelltemp'* *'nostmp'*
-'shelltemp' 'stmp' boolean (Vim default on, Vi default off)
+'shelltemp' 'stmp' boolean (default on)
global
When on, use temp files for shell commands. When off use a pipe.
When using a pipe is not possible temp files are used anyway.
@@ -5494,7 +5451,7 @@ A jump table for the options with a short description can be found at |Q_op|.
function to get the effective shiftwidth value.
*'shortmess'* *'shm'*
-'shortmess' 'shm' string (Vim default "filnxtToOF", Vi default: "S")
+'shortmess' 'shm' string (default "filnxtToOF")
global
This option helps to avoid all the |hit-enter| prompts caused by file
messages, for example with CTRL-G, and to avoid some other messages.
@@ -5568,7 +5525,7 @@ A jump table for the options with a short description can be found at |Q_op|.
:setlocal showbreak=NONE
<
*'showcmd'* *'sc'* *'noshowcmd'* *'nosc'*
-'showcmd' 'sc' boolean (Vim default: on, Vi default: off)
+'showcmd' 'sc' boolean (default: on)
global
Show (partial) command in the last line of the screen. Set this
option off if your terminal is slow.
@@ -5614,7 +5571,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Note: Use of the short form is rated PG.
*'showmode'* *'smd'* *'noshowmode'* *'nosmd'*
-'showmode' 'smd' boolean (Vim default: on, Vi default: off)
+'showmode' 'smd' boolean (default: on)
global
If in Insert, Replace or Visual mode put a message on the last line.
The |hl-ModeMsg| highlight group determines the highlighting.
@@ -6052,7 +6009,7 @@ A jump table for the options with a short description can be found at |Q_op|.
the label, e.g.: %3Xclose%X. Use %999X for a "close current
tab" label. Clicking this label with left mouse button closes
specified tab page.
- @ N For 'tabline': start of execute function label. Use %X or %T to
+ @ N Start of execute function label. Use %X or %T to
end the label, e.g.: %10@SwitchBuffer@foo.c%X. Clicking this
label runs specified function: in the example when clicking once
using left mouse button on "foo.c" "SwitchBuffer(10, 1, 'l',
@@ -6076,8 +6033,6 @@ A jump table for the options with a short description can be found at |Q_op|.
is a bug that denotes that new mouse button recognition was
added without modifying code that reacts on mouse clicks on
this label.
- Note: to test whether your version of Neovim contains this
- feature use `has('tablineat')`.
< - Where to truncate line if too long. Default is at the start.
No width fields allowed.
= - Separation point between alignment sections. Each section will
@@ -6398,7 +6353,7 @@ A jump table for the options with a short description can be found at |Q_op|.
If non-zero, tags are significant up to this number of characters.
*'tagrelative'* *'tr'* *'notagrelative'* *'notr'*
-'tagrelative' 'tr' boolean (Vim default: on, Vi default: off)
+'tagrelative' 'tr' boolean (default: on)
global
If on and using a tags file in another directory, file names in that
tags file are relative to the directory where the tags file is.
@@ -6478,13 +6433,6 @@ A jump table for the options with a short description can be found at |Q_op|.
C1 Control characters 0x80...0x9F
- *'terse'* *'noterse'*
-'terse' boolean (default off)
- global
- When set: Add 's' flag to 'shortmess' option (this makes the message
- for a search that hits the start or end of the file not being
- displayed). When reset: Remove 's' flag from 'shortmess' option.
-
*'textwidth'* *'tw'*
'textwidth' 'tw' number (default 0)
local to buffer
@@ -6853,7 +6801,7 @@ A jump table for the options with a short description can be found at |Q_op|.
has been changed.
*'whichwrap'* *'ww'*
-'whichwrap' 'ww' string (Vim default: "b,s", Vi default: "")
+'whichwrap' 'ww' string (default: "b,s")
global
Allow specified keys that move the cursor left/right to move to the
previous/next line when the cursor is on the first/last character in
@@ -6883,7 +6831,7 @@ A jump table for the options with a short description can be found at |Q_op|.
makes "dl", "cl", "yl" etc. work normally.
*'wildchar'* *'wc'*
-'wildchar' 'wc' number (Vim default: <Tab>, Vi default: CTRL-E)
+'wildchar' 'wc' number (default: <Tab>)
global
Character you have to type to start wildcard expansion in the
command-line, as specified with 'wildmode'.
@@ -7045,6 +6993,19 @@ A jump table for the options with a short description can be found at |Q_op|.
key is never used for the menu.
This option is not used for <F10>; on Win32.
+ *'winbar'* *'wbr'*
+'winbar' 'wbr' string (default empty)
+ global or local to window |global-local|
+ When non-empty, this option enables the window bar and determines its
+ contents. The window bar is a bar that's shown at the top of every
+ window with it enabled. The value of 'winbar' is evaluated like with
+ 'statusline'.
+
+ When changing something that is used in 'winbar' that does not trigger
+ it to be updated, use |:redrawstatus|.
+
+ This option cannot be set in a modeline when 'modelineexpr' is off.
+
*'winblend'* *'winbl'*
'winblend' 'winbl' number (default 0)
local to window
@@ -7186,7 +7147,7 @@ A jump table for the options with a short description can be found at |Q_op|.
starts. When typing text beyond this limit, an <EOL> will be inserted
and inserting continues on the next line.
Options that add a margin, such as 'number' and 'foldcolumn', cause
- the text width to be further reduced. This is Vi compatible.
+ the text width to be further reduced.
When 'textwidth' is non-zero, this option is not used.
See also 'formatoptions' and |ins-textwidth|.
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index 961d734bfe..1716ea025d 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -741,7 +741,6 @@ Short explanation of each option: *option-list*
'indentexpr' 'inde' expression used to obtain the indent of a line
'indentkeys' 'indk' keys that trigger indenting with 'indentexpr'
'infercase' 'inf' adjust case of match for keyword completion
-'insertmode' 'im' start the edit of a file in Insert mode
'isfname' 'isf' characters included in file names and pathnames
'isident' 'isi' characters included in identifiers
'iskeyword' 'isk' characters included in keywords
@@ -824,7 +823,6 @@ Short explanation of each option: *option-list*
'redrawtime' 'rdt' timeout for 'hlsearch' and |:match| highlighting
'regexpengine' 're' default regexp engine to use
'relativenumber' 'rnu' show relative line number in front of each line
-'remap' allow mappings to work recursively
'report' threshold for reporting nr. of lines changed
'revins' 'ri' inserting characters will work backwards
'rightleft' 'rl' window is right-to-left oriented
@@ -896,7 +894,6 @@ Short explanation of each option: *option-list*
'tagstack' 'tgst' push tags onto the tag stack
'term' name of the terminal
'termbidi' 'tbidi' terminal takes care of bi-directionality
-'terse' shorten some messages
'textwidth' 'tw' maximum width of text that is being inserted
'thesaurus' 'tsr' list of thesaurus files for keyword completion
'thesaurusfunc' 'tsrfu' function to be used for thesaurus completion
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index f542f33451..8b88fa9363 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -527,7 +527,6 @@ accordingly, proceeding as follows:
16. Execute startup commands
If a |-t| flag was given, the tag is jumped to.
Commands given with |-c| and |+cmd| are executed.
- If the 'insertmode' option is set, Insert mode is entered.
The starting flag is reset, has("vim_starting") will now return zero.
The |v:vim_did_enter| variable is set to 1.
The |VimEnter| autocommands are executed.
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 0aceb30ce0..4122f4ad9c 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -1476,7 +1476,7 @@ modes Conditional, Number, Statement, Comment, PreProc, Type, and String,
following the language specifications in 'Symbolic Manipulation with FORM' by
J.A.M. Vermaseren, CAN, Netherlands, 1991.
-If you want include your own changes to the default colors, you have to
+If you want to include your own changes to the default colors, you have to
redefine the following syntax groups:
- formConditional
@@ -5244,6 +5244,10 @@ Whitespace "nbsp", "space", "tab", "multispace", "lead" and "trail"
in 'listchars'.
*hl-WildMenu*
WildMenu Current match in 'wildmenu' completion.
+ *hl-WinBar*
+WinBar Window bar of current window.
+ *hl-WinBarNC*
+WinBarNC Window bar of not-current windows.
*hl-User1* *hl-User1..9* *hl-User9*
The 'statusline' syntax allows the use of 9 different highlights in the
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index bc264bd971..339ae0c2ed 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -616,8 +616,6 @@ LanguageTree:children({self}) *LanguageTree:children()*
LanguageTree:contains({self}, {range}) *LanguageTree:contains()*
Determines whether {range} is contained in this language tree
- This goes down the tree to recursively check children.
-
Parameters: ~
{range} A range, that is a `{ start_line, start_col,
end_line, end_col }` table.
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index 75ee0fdfdf..562faeaa2c 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -30,10 +30,10 @@ CTRL-L Clears and redraws the screen. The redraw may happen
function (or a mapping if 'lazyredraw' set).
*:redraws* *:redrawstatus*
-:redraws[tatus][!] Redraws the status line of the current window, or all
- status lines if "!" is included.
- Useful if 'statusline' includes an item that doesn't
- cause automatic updating.
+:redraws[tatus][!] Redraws the status line and window bar of the current
+ window, or all status lines and window bars if "!" is
+ included. Useful if 'statusline' or 'winbar' includes
+ an item that doesn't cause automatic updating.
*:redrawt* *:redrawtabline*
:redrawt[abline] Redraw the tabline. Useful to update the tabline when
@@ -208,8 +208,6 @@ g8 Print the hex values of the bytes used in the
{commands} cannot start with a space. Put a count of
1 (one) before it, "1 " is one space.
- The 'insertmode' option is ignored for {commands}.
-
This command cannot be followed by another command,
since any '|' is considered part of the command.
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index fc98331697..85b44e3b51 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -543,16 +543,25 @@ Options:
*'imactivatefunc'* *'imaf'*
*'imactivatekey'* *'imak'*
*'imstatusfunc'* *'imsf'*
+ *'insertmode'* *'im'* Use the following script to emulate 'insertmode':
+>
+ autocmd VimEnter,CmdlineLeave,WinEnter,WinScrolled,BufEnter * silent! if &modifiable | startinsert | endif
+ inoremap <Esc> <Nop>
+ inoremap <C-L> <Esc>
+ nnoremap <Esc> i
+<
*'macatsui'*
'maxmem' Nvim delegates memory-management to the OS.
'maxmemtot' Nvim delegates memory-management to the OS.
'maxcombine' (6 is always used)
*'prompt'* *'noprompt'*
+ *'remap'* *'noremap'*
*'restorescreen'* *'rs'* *'norestorescreen'* *'nors'*
'shelltype'
*'shortname'* *'sn'* *'noshortname'* *'nosn'*
*'swapsync'* *'sws'*
*'termencoding'* *'tenc'* (Vim 7.4.852 also removed this for Windows)
+ *'terse'* *'noterse'* (Add "s" to 'shortmess' instead)
'textauto'
'textmode'
*'toolbar'* *'tb'*
diff --git a/runtime/ftplugin/spec.vim b/runtime/ftplugin/spec.vim
index ce00021a69..9040e19ce1 100644
--- a/runtime/ftplugin/spec.vim
+++ b/runtime/ftplugin/spec.vim
@@ -3,6 +3,7 @@
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
" Former Maintainer: Gustavo Niemeyer <niemeyer@conectiva.com> (until March 2014)
" Last Change: Mon Jun 01 21:15 MSK 2015 Igor Gnatenko
+" Update by Zdenek Dohnal, 2022 May 17
if exists("b:did_ftplugin")
finish
@@ -41,8 +42,8 @@ else:
headers = spec.sourceHeader
version = headers["Version"]
release = headers["Release"]
- vim.command("let ver = " + version)
- vim.command("let rel = " + release)
+ vim.command("let ver = '" + version + "'")
+ vim.command("let rel = '" + release + "'")
PYEND
endif
endfunction
diff --git a/runtime/indent/fortran.vim b/runtime/indent/fortran.vim
index 26ed33a54d..9623014818 100644
--- a/runtime/indent/fortran.vim
+++ b/runtime/indent/fortran.vim
@@ -1,13 +1,13 @@
" Vim indent file
" Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77)
-" Version: (v48) 2020 October 07
-" Maintainer: Ajit J. Thakkar <ajit@unb.ca>; <http://www2.unb.ca/~ajit/>
+" Version: (v49) 2022 May 14
+" Maintainer: Ajit J. Thakkar <thakkar.ajit@gmail.com>; <http://www2.unb.ca/~ajit/>
" Usage: For instructions, do :help fortran-indent from Vim
" Credits:
" Version 0.1 was created in September 2000 by Ajit Thakkar.
" Since then, useful suggestions and contributions have been made, in order, by:
" Albert Oliver Serra, Takuya Fujiwara, Philipp Edelmann, Eisuke Kawashima,
-" and Louis Cochen.
+" Louis Cochen, and Doug Kearns.
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
@@ -17,6 +17,7 @@ let b:did_indent = 1
let s:cposet=&cpoptions
set cpoptions&vim
+let b:undo_indent = "setl inde< indk<"
setlocal indentkeys+==~end,=~case,=~if,=~else,=~do,=~where,=~elsewhere,=~select
setlocal indentkeys+==~endif,=~enddo,=~endwhere,=~endselect,=~elseif
diff --git a/runtime/indent/postscr.vim b/runtime/indent/postscr.vim
index 66094e3ed0..8430ccf8b8 100644
--- a/runtime/indent/postscr.vim
+++ b/runtime/indent/postscr.vim
@@ -1,10 +1,8 @@
" PostScript indent file
" Language: PostScript
-" Maintainer: Mike Williams <mrw@netcomuk.co.uk> (Invalid email address)
-" Doug Kearns <dougkearns@gmail.com>
+" Maintainer: Mike Williams <mrw@eandem.co.uk>
" Last Change: 2022 Apr 06
-
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
finish
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index dc25d68f61..e6ab48f30d 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -406,7 +406,6 @@ function vim.defer_fn(fn, timeout)
timeout,
0,
vim.schedule_wrap(function()
- timer:stop()
timer:close()
fn()
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index fed0231ae9..c9e81b53d7 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -786,8 +786,8 @@ local extension = {
zut = 'zimbutempl',
zsh = 'zsh',
vala = 'vala',
- E = function()
- vim.fn['dist#ft#FTe']()
+ E = function(path, bufnr)
+ return require('vim.filetype.detect').e(bufnr)
end,
EU = function(path, bufnr)
return require('vim.filetype.detect').euphoria(bufnr)
@@ -804,68 +804,68 @@ local extension = {
EXW = function(path, bufnr)
return require('vim.filetype.detect').euphoria(bufnr)
end,
- PL = function()
- vim.fn['dist#ft#FTpl']()
+ PL = function(path, bufnr)
+ return require('vim.filetype.detect').pl(bufnr)
end,
R = function(path, bufnr)
- require('vim.filetype.detect').r(bufnr)
+ return require('vim.filetype.detect').r(bufnr)
end,
- asm = function()
- vim.fn['dist#ft#FTasm']()
+ asm = function(path, bufnr)
+ return require('vim.filetype.detect').asm(bufnr)
end,
- bas = function()
- vim.fn['dist#ft#FTbas']()
+ bas = function(path, bufnr)
+ return require('vim.filetype.detect').bas(bufnr)
end,
- bi = function()
- vim.fn['dist#ft#FTbas']()
+ bi = function(path, bufnr)
+ return require('vim.filetype.detect').bas(bufnr)
end,
- bm = function()
- vim.fn['dist#ft#FTbas']()
+ bm = function(path, bufnr)
+ return require('vim.filetype.detect').bas(bufnr)
end,
- bash = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ bash = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
btm = function(path, bufnr)
return require('vim.filetype.detect').btm(bufnr)
end,
- c = function()
- vim.fn['dist#ft#FTlpc']()
+ c = function(path, bufnr)
+ return require('vim.filetype.detect').lpc(bufnr)
end,
- ch = function()
- vim.fn['dist#ft#FTchange']()
+ ch = function(path, bufnr)
+ return require('vim.filetype.detect').change(bufnr)
end,
- com = function()
- vim.fn['dist#ft#BindzoneCheck']('dcl')
+ com = function(path, bufnr)
+ return require('vim.filetype.detect').bindzone(bufnr, 'dcl')
end,
- cpt = function()
- vim.fn['dist#ft#FThtml']()
+ cpt = function(path, bufnr)
+ return require('vim.filetype.detect').html(bufnr)
end,
- csh = function()
- vim.fn['dist#ft#CSH']()
+ csh = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
- d = function()
- vim.fn['dist#ft#DtraceCheck']()
+ d = function(path, bufnr)
+ return require('vim.filetype.detect').dtrace(bufnr)
end,
- db = function()
- vim.fn['dist#ft#BindzoneCheck']('')
+ db = function(path, bufnr)
+ return require('vim.filetype.detect').bindzone(bufnr, '')
end,
- dtml = function()
- vim.fn['dist#ft#FThtml']()
+ dtml = function(path, bufnr)
+ return require('vim.filetype.detect').html(bufnr)
end,
- e = function()
- vim.fn['dist#ft#FTe']()
+ e = function(path, bufnr)
+ return require('vim.filetype.detect').e(bufnr)
end,
- ebuild = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ ebuild = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
- eclass = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ eclass = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
ent = function(path, bufnr)
return require('vim.filetype.detect').ent(bufnr)
end,
- env = function()
- vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1))
+ env = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1))
end,
eu = function(path, bufnr)
return require('vim.filetype.detect').euphoria(bufnr)
@@ -883,55 +883,55 @@ local extension = {
return require('vim.filetype.detect').euphoria(bufnr)
end,
frm = function(path, bufnr)
- require('vim.filetype.detect').frm(bufnr)
+ return require('vim.filetype.detect').frm(bufnr)
end,
- fs = function()
- vim.fn['dist#ft#FTfs']()
+ fs = function(path, bufnr)
+ return require('vim.filetype.detect').fs(bufnr)
end,
h = function(path, bufnr)
- require('vim.filetype.detect').header(bufnr)
+ return require('vim.filetype.detect').header(bufnr)
end,
- htm = function()
- vim.fn['dist#ft#FThtml']()
+ htm = function(path, bufnr)
+ return require('vim.filetype.detect').html(bufnr)
end,
- html = function()
- vim.fn['dist#ft#FThtml']()
+ html = function(path, bufnr)
+ return require('vim.filetype.detect').html(bufnr)
end,
- i = function()
- vim.fn['dist#ft#FTprogress_asm']()
+ i = function(path, bufnr)
+ return require('vim.filetype.detect').progress_asm(bufnr)
end,
idl = function(path, bufnr)
- require('vim.filetype.detect').idl(bufnr)
+ return require('vim.filetype.detect').idl(bufnr)
end,
- inc = function()
- vim.fn['dist#ft#FTinc']()
+ inc = function(path, bufnr)
+ return require('vim.filetype.detect').inc(bufnr)
end,
inp = function(path, bufnr)
- require('vim.filetype.detect').inp(bufnr)
+ return require('vim.filetype.detect').inp(bufnr)
end,
- ksh = function()
- vim.fn['dist#ft#SetFileTypeSH']('ksh')
+ ksh = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
end,
- lst = function()
- vim.fn['dist#ft#FTasm']()
+ lst = function(path, bufnr)
+ return require('vim.filetype.detect').asm(bufnr)
end,
- m = function()
- vim.fn['dist#ft#FTm']()
+ m = function(path, bufnr)
+ return require('vim.filetype.detect').m(bufnr)
end,
- mac = function()
- vim.fn['dist#ft#FTasm']()
+ mac = function(path, bufnr)
+ return require('vim.filetype.detect').asm(bufnr)
end,
mc = function(path, bufnr)
- require('vim.filetype.detect').mc(bufnr)
+ return require('vim.filetype.detect').mc(bufnr)
end,
- mm = function()
- vim.fn['dist#ft#FTmm']()
+ mm = function(path, bufnr)
+ return require('vim.filetype.detect').mm(bufnr)
end,
mms = function(path, bufnr)
- require('vim.filetype.detect').mms(bufnr)
+ return require('vim.filetype.detect').mms(bufnr)
end,
- p = function()
- vim.fn['dist#ft#FTprogress_pascal']()
+ p = function(path, bufnr)
+ return require('vim.filetype.detect').progress_pascal(bufnr)
end,
patch = function(path, bufnr)
local firstline = getline(bufnr, 1)
@@ -941,65 +941,65 @@ local extension = {
return 'diff'
end
end,
- pl = function()
- vim.fn['dist#ft#FTpl']()
+ pl = function(path, bufnr)
+ return require('vim.filetype.detect').pl(bufnr)
end,
- pp = function()
- vim.fn['dist#ft#FTpp']()
+ pp = function(path, bufnr)
+ return require('vim.filetype.detect').pp(bufnr)
end,
- pro = function()
- vim.fn['dist#ft#ProtoCheck']('idlang')
+ pro = function(path, bufnr)
+ return require('vim.filetype.detect').proto(bufnr, 'idlang')
end,
- pt = function()
- vim.fn['dist#ft#FThtml']()
+ pt = function(path, bufnr)
+ return require('vim.filetype.detect').html('idlang')
end,
r = function(path, bufnr)
- require('vim.filetype.detect').r(bufnr)
+ return require('vim.filetype.detect').r(bufnr)
end,
rdf = function(path, bufnr)
- require('vim.filetype.detect').redif(bufnr)
+ return require('vim.filetype.detect').redif(bufnr)
end,
- rules = function()
- vim.fn['dist#ft#FTRules']()
+ rules = function(path, bufnr)
+ return require('vim.filetype.detect').rules(path, bufnr)
end,
sc = function(path, bufnr)
- require('vim.filetype.detect').sc(bufnr)
+ return require('vim.filetype.detect').sc(bufnr)
end,
scd = function(path, bufnr)
- require('vim.filetype.detect').scd(bufnr)
+ return require('vim.filetype.detect').scd(bufnr)
end,
- sh = function()
- vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1))
+ sh = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1))
end,
- shtml = function()
- vim.fn['dist#ft#FThtml']()
+ shtml = function(path, bufnr)
+ return require('vim.filetype.detect').html(bufnr)
end,
sql = function(path, bufnr)
- require('vim.filetype.detect').sql(bufnr)
+ return require('vim.filetype.detect').sql(bufnr)
end,
- stm = function()
- vim.fn['dist#ft#FThtml']()
+ stm = function(path, bufnr)
+ return require('vim.filetype.detect').html(bufnr)
end,
- tcsh = function()
- vim.fn['dist#ft#SetFileTypeShell']('tcsh')
+ tcsh = function(path, bufnr)
+ return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
end,
- tex = function()
- vim.fn['dist#ft#FTtex']()
+ tex = function(path, bufnr)
+ return require('vim.filetype.detect').tex(path, bufnr)
end,
tf = function(path, bufnr)
- require('vim.filetype.detect').tf(bufnr)
+ return require('vim.filetype.detect').tf(bufnr)
end,
w = function(path, bufnr)
- require('vim.filetype.detect').progress_cweb(bufnr)
+ return require('vim.filetype.detect').progress_cweb(bufnr)
end,
xml = function(path, bufnr)
- require('vim.filetype.detect').xml(bufnr)
+ return require('vim.filetype.detect').xml(bufnr)
end,
y = function(path, bufnr)
- require('vim.filetype.detect').y(bufnr)
+ return require('vim.filetype.detect').y(bufnr)
end,
zsql = function(path, bufnr)
- require('vim.filetype.detect').sql(bufnr)
+ return require('vim.filetype.detect').sql(bufnr)
end,
txt = function(path, bufnr)
--helpfiles match *.txt, but should have a modeline as last line
@@ -1075,16 +1075,16 @@ local filename = {
exports = 'exports',
['.fetchmailrc'] = 'fetchmail',
fvSchemes = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
fvSolution = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
fvConstraints = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
fvModels = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
fstab = 'fstab',
mtab = 'fstab',
@@ -1300,63 +1300,63 @@ local filename = {
['.zcompdump'] = 'zsh',
['.zshenv'] = 'zsh',
['.zfbfmarks'] = 'zsh',
- ['.alias'] = function()
- vim.fn['dist#ft#CSH']()
+ ['.alias'] = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
- ['.bashrc'] = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ ['.bashrc'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
- ['.cshrc'] = function()
- vim.fn['dist#ft#CSH']()
+ ['.cshrc'] = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
- ['.env'] = function()
- vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1))
+ ['.env'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1))
end,
- ['.kshrc'] = function()
- vim.fn['dist#ft#SetFileTypeSH']('ksh')
+ ['.kshrc'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
end,
- ['.login'] = function()
- vim.fn['dist#ft#CSH']()
+ ['.login'] = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
- ['.profile'] = function()
- vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1))
+ ['.profile'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1))
end,
- ['.tcshrc'] = function()
- vim.fn['dist#ft#SetFileTypeShell']('tcsh')
+ ['.tcshrc'] = function(path, bufnr)
+ return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
end,
- ['/etc/profile'] = function()
- vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1))
+ ['/etc/profile'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1))
end,
- APKBUILD = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ APKBUILD = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
- PKGBUILD = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ PKGBUILD = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
- ['bash.bashrc'] = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ ['bash.bashrc'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
- bashrc = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ bashrc = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
crontab = starsetf('crontab'),
- ['csh.cshrc'] = function()
- vim.fn['dist#ft#CSH']()
+ ['csh.cshrc'] = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
- ['csh.login'] = function()
- vim.fn['dist#ft#CSH']()
+ ['csh.login'] = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
- ['csh.logout'] = function()
- vim.fn['dist#ft#CSH']()
+ ['csh.logout'] = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
- ['indent.pro'] = function()
- vim.fn['dist#ft#ProtoCheck']('indent')
+ ['indent.pro'] = function(path, bufnr)
+ return require('vim.filetype.detect').proto(bufnr, 'indent')
end,
- ['tcsh.login'] = function()
- vim.fn['dist#ft#SetFileTypeShell']('tcsh')
+ ['tcsh.login'] = function(path, bufnr)
+ return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
end,
- ['tcsh.tcshrc'] = function()
- vim.fn['dist#ft#SetFileTypeShell']('tcsh')
+ ['tcsh.tcshrc'] = function(path, bufnr)
+ return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
end,
-- END FILENAME
}
@@ -1528,32 +1528,32 @@ local pattern = {
['.*/etc/xdg/menus/.*%.menu'] = 'xml',
['.*Xmodmap'] = 'xmodmap',
['.*/etc/zprofile'] = 'zsh',
- ['%.bash[_-]aliases'] = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ ['%.bash[_-]aliases'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
- ['%.bash[_-]logout'] = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ ['%.bash[_-]logout'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
- ['%.bash[_-]profile'] = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ ['%.bash[_-]profile'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
- ['%.cshrc.*'] = function()
- vim.fn['dist#ft#CSH']()
+ ['%.cshrc.*'] = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
['%.gtkrc.*'] = starsetf('gtkrc'),
- ['%.kshrc.*'] = function()
- vim.fn['dist#ft#SetFileTypeSH']('ksh')
+ ['%.kshrc.*'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
end,
- ['%.login.*'] = function()
- vim.fn['dist#ft#CSH']()
+ ['%.login.*'] = function(path, bufnr)
+ return require('vim.filetype.detect').csh(path, bufnr)
end,
['%.neomuttrc.*'] = starsetf('neomuttrc'),
- ['%.profile.*'] = function()
- vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1))
+ ['%.profile.*'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1))
end,
['%.reminders.*'] = starsetf('remind'),
- ['%.tcshrc.*'] = function()
- vim.fn['dist#ft#SetFileTypeShell']('tcsh')
+ ['%.tcshrc.*'] = function(path, bufnr)
+ return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
end,
['%.zcompdump.*'] = starsetf('zsh'),
['%.zlog.*'] = starsetf('zsh'),
@@ -1561,11 +1561,11 @@ local pattern = {
['.*%.[1-9]'] = function(path, bufnr)
return require('vim.filetype.detect').nroff(bufnr)
end,
- ['.*%.[aA]'] = function()
- vim.fn['dist#ft#FTasm']()
+ ['.*%.[aA]'] = function(path, bufnr)
+ return require('vim.filetype.detect').asm(bufnr)
end,
- ['.*%.[sS]'] = function()
- vim.fn['dist#ft#FTasm']()
+ ['.*%.[sS]'] = function(path, bufnr)
+ return require('vim.filetype.detect').asm(bufnr)
end,
['.*%.properties_.._.._.*'] = starsetf('jproperties'),
['.*%.vhdl_[0-9].*'] = starsetf('vhdl'),
@@ -1575,8 +1575,8 @@ local pattern = {
['.*/Xresources/.*'] = starsetf('xdefaults'),
['.*/app%-defaults/.*'] = starsetf('xdefaults'),
['.*/bind/db%..*'] = starsetf('bindzone'),
- ['.*/debian/patches/.*'] = function()
- vim.fn['dist#ft#Dep3patch']()
+ ['.*/debian/patches/.*'] = function(path, bufnr)
+ return require('vim.filetype.detect').dep3patch(path, bufnr)
end,
['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'),
['.*/etc/apache2/.*%.conf.*'] = starsetf('apache'),
@@ -1592,8 +1592,8 @@ local pattern = {
['.*/etc/logcheck/.*%.d.*/.*'] = starsetf('logcheck'),
['.*/etc/modprobe%..*'] = starsetf('modconf'),
['.*/etc/pam%.d/.*'] = starsetf('pamconf'),
- ['.*/etc/profile'] = function()
- vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1))
+ ['.*/etc/profile'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1))
end,
['.*/etc/proftpd/.*%.conf.*'] = starsetf('apachestyle'),
['.*/etc/proftpd/conf%..*/.*'] = starsetf('apachestyle'),
@@ -1621,8 +1621,8 @@ local pattern = {
['access%.conf.*'] = starsetf('apache'),
['apache%.conf.*'] = starsetf('apache'),
['apache2%.conf.*'] = starsetf('apache'),
- ['bash%-fc[-%.]'] = function()
- vim.fn['dist#ft#SetFileTypeSH']('bash')
+ ['bash%-fc[-%.]'] = function(path, bufnr)
+ return require('vim.filetype.detect').sh(path, bufnr, 'bash')
end,
['cabal%.project%..*'] = starsetf('cabalproject'),
['crontab%..*'] = starsetf('crontab'),
@@ -1650,28 +1650,28 @@ local pattern = {
['neomutt' .. string.rep('[%w_-]', 6)] = 'mail',
['/tmp/SLRN[0-9A-Z.]+'] = 'mail',
['[a-zA-Z0-9].*Dict'] = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
['[a-zA-Z0-9].*Dict%..*'] = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
['[a-zA-Z].*Properties'] = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
['[a-zA-Z].*Properties%..*'] = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
['.*Transport%..*'] = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
['.*/constant/g'] = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
['.*/0/.*'] = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
['.*/0%.orig/.*'] = function(path, bufnr)
- require('vim.filetype.detect').foam(bufnr)
+ return require('vim.filetype.detect').foam(bufnr)
end,
['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'),
['.*%.git/.*'] = function(path, bufnr)
@@ -1680,24 +1680,29 @@ local pattern = {
return 'git'
end
end,
- ['.*%.[Cc][Ff][Gg]'] = function()
- vim.fn['dist#ft#FTcfg']()
- end,
- ['.*%.[Dd][Aa][Tt]'] = function()
- vim.fn['dist#ft#FTdat']()
+ ['.*%.[Cc][Ff][Gg]'] = {
+ function(path, bufnr)
+ return require('vim.filetype.detect').cfg(bufnr)
+ end,
+ -- Decrease the priority to avoid conflicts with more specific patterns
+ -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc.
+ { priority = -1 },
+ },
+ ['.*%.[Dd][Aa][Tt]'] = function(path, bufnr)
+ return require('vim.filetype.detect').dat(bufnr)
end,
- ['.*%.[Mm][Oo][Dd]'] = function()
- vim.fn['dist#ft#FTmod']()
+ ['.*%.[Mm][Oo][Dd]'] = function(path, bufnr)
+ return require('vim.filetype.detect').mod(path, bufnr)
end,
- ['.*%.[Ss][Rr][Cc]'] = function()
- vim.fn['dist#ft#FTsrc']()
+ ['.*%.[Ss][Rr][Cc]'] = function(path, bufnr)
+ return require('vim.filetype.detect').src(bufnr)
end,
['.*%.[Ss][Uu][Bb]'] = 'krl',
- ['.*%.[Pp][Rr][Gg]'] = function()
- vim.fn['dist#ft#FTprg']()
+ ['.*%.[Pp][Rr][Gg]'] = function(path, bufnr)
+ return require('vim.filetype.detect').prg(bufnr)
end,
- ['.*%.[Ss][Yy][Ss]'] = function()
- vim.fn['dist#ft#FTsys']()
+ ['.*%.[Ss][Yy][Ss]'] = function(path, bufnr)
+ return require('vim.filetype.detect').sys(bufnr)
end,
-- Neovim only
['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 4c363e7403..f195693dcf 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -1,19 +1,35 @@
+-- Contains filetype detection functions converted to Lua from Vim's autoload/runtime/dist/ft.vim file.
+
+-- Here are a few guidelines to follow when porting a new function:
+-- * Sort the function alphabetically and omit 'ft' or 'check' from the new function name.
+-- * Use ':find' instead of ':match' / ':sub' if possible.
+-- * When '=~' is used to match a pattern, there are two possibilities:
+-- - If the pattern only contains lowercase characters, treat the comparison as case-insensitive.
+-- - Otherwise, treat it as case-sensitive.
+-- (Basically, we apply 'smartcase': if upper case characters are used in the original pattern, then
+-- it's likely that case does matter).
+-- * When '\k', '\<' or '\>' is used in a pattern, use the 'matchregex' function.
+-- Note that vim.regex is case-sensitive by default, so add the '\c' flag if only lowercase letters
+-- are present in the pattern:
+-- Example:
+-- `if line =~ '^\s*unwind_protect\>'` => `if matchregex(line, [[\c^\s*unwind_protect\>]])`
+
local M = {}
---@private
-local function getlines(bufnr, start_lnum, end_lnum, opts)
+local function getlines(bufnr, start_lnum, end_lnum)
if not end_lnum then
-- Return a single line as a string
return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1]
end
-
- local lines = vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false)
- opts = opts or {}
- return opts.concat and (table.concat(lines) or '') or lines
+ return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false)
end
---@private
local function findany(s, patterns)
+ if s == nil then
+ return false
+ end
for _, v in ipairs(patterns) do
if s:find(v) then
return true
@@ -22,22 +38,117 @@ local function findany(s, patterns)
return false
end
+---@private
+local function nextnonblank(bufnr, start_lnum)
+ for _, line in ipairs(getlines(bufnr, start_lnum, -1)) do
+ if not line:find('^%s*$') then
+ return line
+ end
+ end
+ return nil
+end
+
+---@private
+local matchregex = (function()
+ local cache = {}
+ return function(line, pattern)
+ if line == nil then
+ return nil
+ end
+ if not cache[pattern] then
+ cache[pattern] = vim.regex(pattern)
+ end
+ return cache[pattern]:match_str(line)
+ end
+end)()
+
+---@private
+local did_filetype = function()
+ return vim.fn.did_filetype() ~= 0
+end
+
-- luacheck: push no unused args
-- luacheck: push ignore 122
-function M.asm(path, bufnr) end
+-- This function checks for the kind of assembly that is wanted by the user, or
+-- can be detected from the first five lines of the file.
+function M.asm(bufnr)
+ -- Make sure b:asmsyntax exists
+ if not vim.b[bufnr].asmsyntax then
+ vim.b[bufnr].asmsyntax = ''
+ end
+
+ if vim.b[bufnr].asmsyntax == '' then
+ M.asm_syntax(bufnr)
+ end
+
+ -- If b:asmsyntax still isn't set, default to asmsyntax or GNU
+ if vim.b[bufnr].asmsyntax == '' then
+ if vim.g.asmsyntax and vim.g.asmsyntax ~= 0 then
+ vim.b[bufnr].asmsyntax = vim.g.asmsyntax
+ else
+ vim.b[bufnr].asmsyntax = 'asm'
+ end
+ end
+ return vim.fn.fnameescape(vim.b[bufnr].asmsyntax)
+end
+
+-- Checks the first 5 lines for a asmsyntax=foo override.
+-- Only whitespace characters can be present immediately before or after this statement.
+function M.asm_syntax(bufnr)
+ local lines = table.concat(getlines(bufnr, 1, 5), ' '):lower()
+ local match = lines:match('%sasmsyntax=([a-zA-Z0-9]+)%s')
+ if match then
+ vim.b['asmsyntax'] = match
+ elseif findany(lines, { '%.title', '%.ident', '%.macro', '%.subtitle', '%.library' }) then
+ vim.b['asmsyntax'] = 'vmasm'
+ end
+end
-function M.asm_syntax(path, bufnr) end
+local visual_basic_content = { 'vb_name', 'begin vb%.form', 'begin vb%.mdiform', 'begin vb%.usercontrol' }
+
+-- See frm() for Visual Basic form file detection
+function M.bas(bufnr)
+ if vim.g.filetype_bas then
+ return vim.g.filetype_bas
+ end
-function M.bas(path, bufnr) end
+ -- Most frequent FreeBASIC-specific keywords in distro files
+ local fb_keywords =
+ [[\c^\s*\%(extern\|var\|enum\|private\|scope\|union\|byref\|operator\|constructor\|delete\|namespace\|public\|property\|with\|destructor\|using\)\>\%(\s*[:=(]\)\@!]]
+ local fb_preproc =
+ [[\c^\s*\%(#\a\+\|option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\)]]
-function M.bindzone(path, bufnr) end
+ local fb_comment = "^%s*/'"
+ -- OPTION EXPLICIT, without the leading underscore, is common to many dialects
+ local qb64_preproc = [[\c^\s*\%($\a\+\|option\s\+\%(_explicit\|_\=explicitarray\)\>\)]]
+
+ for _, line in ipairs(getlines(bufnr, 1, 100)) do
+ if line:find(fb_comment) or matchregex(line, fb_preproc) or matchregex(line, fb_keywords) then
+ return 'freebasic'
+ elseif matchregex(line, qb64_preproc) then
+ return 'qb64'
+ elseif findany(line:lower(), visual_basic_content) then
+ return 'vb'
+ end
+ end
+ return 'basic'
+end
+
+function M.bindzone(bufnr, default)
+ local lines = table.concat(getlines(bufnr, 1, 4))
+ if findany(lines, { '^; <<>> DiG [0-9%.]+.* <<>>', '%$ORIGIN', '%$TTL', 'IN%s+SOA' }) then
+ return 'bindzone'
+ else
+ return default
+ end
+end
function M.btm(bufnr)
if vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0 then
- vim.bo[bufnr].filetype = 'dosbatch'
+ return 'dosbatch'
else
- vim.bo[bufnr].filetype = 'btm'
+ return 'btm'
end
end
@@ -47,38 +158,131 @@ local function is_rapid(bufnr, extension)
local line = getlines(bufnr, 1):lower()
return findany(line, { 'eio:cfg', 'mmc:cfg', 'moc:cfg', 'proc:cfg', 'sio:cfg', 'sys:cfg' })
end
- local first = '^%s*module%s+%S+%s*'
- -- Called from mod, prg or sys functions
- for _, line in ipairs(getlines(bufnr, 1, -1)) do
- if not line:find('^%s*$') then
- return findany(line:lower(), { '^%s*%%%%%%', first .. '(', first .. '$' })
- end
+ local line = nextnonblank(bufnr, 1)
+ if line then
+ -- Called from mod, prg or sys functions
+ return matchregex(line:lower(), [[\c\v^\s*%(\%{3}|module\s+\k+\s*%(\(|$))]])
end
- -- Only found blank lines
return false
end
function M.cfg(bufnr)
if vim.g.filetype_cfg then
- vim.bo[bufnr].filetype = vim.g.filetype_cfg
+ return vim.g.filetype_cfg
elseif is_rapid(bufnr, 'cfg') then
- vim.bo[bufnr].filetype = 'rapid'
+ return 'rapid'
else
- vim.bo[bufnr].filetype = 'cfg'
+ return 'cfg'
end
end
-function M.change(path, bufnr) end
+-- This function checks if one of the first ten lines start with a '@'. In
+-- that case it is probably a change file.
+-- If the first line starts with # or ! it's probably a ch file.
+-- If a line has "main", "include", "//" or "/*" it's probably ch.
+-- Otherwise CHILL is assumed.
+function M.change(bufnr)
+ local first_line = getlines(bufnr, 1)
+ if findany(first_line, { '^#', '^!' }) then
+ return 'ch'
+ end
+ for _, line in ipairs(getlines(bufnr, 1, 10)) do
+ if line:find('^@') then
+ return 'change'
+ end
+ if line:find('MODULE') then
+ return 'chill'
+ elseif findany(line:lower(), { 'main%s*%(', '#%s*include', '//' }) then
+ return 'ch'
+ end
+ end
+ return 'chill'
+end
+
+function M.csh(path, bufnr)
+ if did_filetype() then
+ -- Filetype was already detected
+ return
+ end
+ if vim.g.filetype_csh then
+ return M.shell(path, bufnr, vim.g.filetype_csh)
+ elseif string.find(vim.o.shell, 'tcsh') then
+ return M.shell(path, bufnr, 'tcsh')
+ else
+ return M.shell(path, bufnr, 'csh')
+ end
+end
-function M.csh(path, bufnr) end
+-- Determine if a *.dat file is Kuka Robot Language
+function M.dat(bufnr)
+ if vim.g.filetype_dat then
+ return vim.g.filetype_dat
+ end
+ local line = nextnonblank(bufnr, 1)
+ if matchregex(line, [[\c\v^\s*%(\&\w+|defdat>)]]) then
+ return 'krl'
+ end
+end
-function M.dat(path, bufnr) end
+-- This function is called for all files under */debian/patches/*, make sure not
+-- to non-dep3patch files, such as README and other text files.
+function M.dep3patch(path, bufnr)
+ local file_name = vim.fn.fnamemodify(path, ':t')
+ if file_name == 'series' then
+ return
+ end
-function M.dep3patch(path, bufnr) end
+ for _, line in ipairs(getlines(bufnr, 1, 100)) do
+ if
+ findany(line, {
+ '^Description:',
+ '^Subject:',
+ '^Origin:',
+ '^Bug:',
+ '^Forwarded:',
+ '^Author:',
+ '^From:',
+ '^Reviewed%-by:',
+ '^Acked%-by:',
+ '^Last%-Updated:',
+ '^Applied%-Upstream:',
+ })
+ then
+ return 'dep3patch'
+ elseif line:find('^%-%-%-') then
+ -- End of headers found. stop processing
+ return
+ end
+ end
+end
-function M.dtrace(path, bufnr) end
+function M.dtrace(bufnr)
+ if did_filetype() then
+ -- Filetype was already detected
+ return
+ end
+ for _, line in ipairs(getlines(bufnr, 1, 100)) do
+ if matchregex(line, [[\c^module\>\|^import\>]]) then
+ -- D files often start with a module and/or import statement.
+ return 'd'
+ elseif findany(line, { '^#!%S+dtrace', '#pragma%s+D%s+option', ':%S-:%S-:' }) then
+ return 'dtrace'
+ end
+ end
+ return 'd'
+end
-function M.e(path, bufnr) end
+function M.e(bufnr)
+ if vim.g.filetype_euphoria then
+ return vim.g.filetype_euphoria
+ end
+ for _, line in ipairs(getlines(bufnr, 1, 100)) do
+ if findany(line, { "^%s*<'%s*$", "^%s*'>%s*$" }) then
+ return 'specman'
+ end
+ end
+ return 'eiffel'
+end
-- This function checks for valid cl syntax in the first five lines.
-- Look for either an opening comment, '#', or a block start, '{'.
@@ -86,37 +290,34 @@ function M.e(path, bufnr) end
function M.ent(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 5)) do
if line:find('^%s*[#{]') then
- vim.bo[bufnr].filetype = 'cl'
- return
+ return 'cl'
elseif not line:find('^%s*$') then
-- Not a blank line, not a comment, and not a block start,
-- so doesn't look like valid cl code.
break
end
end
- vim.bo[bufnr].filetype = 'dtd'
+ return 'dtd'
end
function M.euphoria(bufnr)
if vim.g.filetype_euphoria then
- vim.bo[bufnr].filetype = vim.g.filetype_euphoria
+ return vim.g.filetype_euphoria
else
- vim.bo[bufnr].filetype = 'euphoria3'
+ return 'euphoria3'
end
end
function M.ex(bufnr)
if vim.g.filetype_euphoria then
- vim.bo[bufnr].filetype = vim.g.filetype_euphoria
+ return vim.g.filetype_euphoria
else
for _, line in ipairs(getlines(bufnr, 1, 100)) do
- -- TODO: in the Vim regex, \> is used to match the end of the word, can this be omitted?
- if findany(line, { '^%-%-', '^ifdef', '^include' }) then
- vim.bo[bufnr].filetype = 'euphoria3'
- return
+ if matchregex(line, [[\c^--\|^ifdef\>\|^include\>]]) then
+ return 'euphoria3'
end
end
- vim.bo[bufnr].filetype = 'elixir'
+ return 'elixir'
end
end
@@ -129,80 +330,185 @@ function M.foam(bufnr)
if line:find('^FoamFile') then
foam_file = true
elseif foam_file and line:find('^%s*object') then
- vim.bo[bufnr].filetype = 'foam'
- return
+ return 'foam'
end
end
end
function M.frm(bufnr)
if vim.g.filetype_frm then
- vim.bo[bufnr].filetype = vim.g.filetype_frm
+ return vim.g.filetype_frm
+ end
+ local lines = table.concat(getlines(bufnr, 1, 5)):lower()
+ if findany(lines, visual_basic_content) then
+ return 'vb'
else
- -- Always ignore case
- local lines = getlines(bufnr, 1, 5, { concat = true }):lower()
- if findany(lines, { 'vb_name', 'begin vb%.form', 'begin vb%.mdiform' }) then
- vim.bo[bufnr].filetype = 'vb'
- else
- vim.bo[bufnr].filetype = 'form'
- end
+ return 'form'
end
end
-function M.fs(path, bufnr) end
+-- Distinguish between Forth and F#.
+function M.fs(bufnr)
+ if vim.g.filetype_fs then
+ return vim.g.filetype_fs
+ end
+ local line = nextnonblank(bufnr, 1)
+ if findany(line, { '^%s*%.?%( ', '^%s*\\G? ', '^\\$', '^%s*: %S' }) then
+ return 'forth'
+ else
+ return 'fsharp'
+ end
+end
function M.header(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 200)) do
- if findany(line, { '^@interface', '^@end', '^@class' }) then
+ if findany(line:lower(), { '^@interface', '^@end', '^@class' }) then
if vim.g.c_syntax_for_h then
- vim.bo[bufnr].filetype = 'objc'
+ return 'objc'
else
- vim.bo[bufnr].filetype = 'objcpp'
+ return 'objcpp'
end
- return
end
end
if vim.g.c_syntax_for_h then
- vim.bo[bufnr].filetype = 'c'
+ return 'c'
elseif vim.g.ch_syntax_for_h then
- vim.bo[bufnr].filetype = 'ch'
+ return 'ch'
else
- vim.bo[bufnr].filetype = 'cpp'
+ return 'cpp'
+ end
+end
+
+function M.html(bufnr)
+ for _, line in ipairs(getlines(bufnr, 1, 10)) do
+ if matchregex(line, [[\<DTD\s\+XHTML\s]]) then
+ return 'xhtml'
+ elseif matchregex(line, [[\c{%\s*\(extends\|block\|load\)\>\|{#\s\+]]) then
+ return 'htmldjango'
+ end
end
+ return 'html'
end
function M.idl(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 50)) do
- -- Always ignore case
- line = line:lower()
- if findany(line, { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then
- vim.bo[bufnr].filetype = 'msidl'
- return
+ if findany(line:lower(), { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then
+ return 'msidl'
end
end
- vim.bo[bufnr].filetype = 'idl'
+ return 'idl'
end
-function M.inc(path, bufnr) end
+local pascal_comments = { '^%s*{', '^%s*%(%*', '^%s*//' }
+local pascal_keywords = [[\c^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>]]
+
+function M.inc(bufnr)
+ if vim.g.filetype_inc then
+ return vim.g.filetype_inc
+ end
+ local lines = table.concat(getlines(bufnr, 1, 3))
+ if lines:lower():find('perlscript') then
+ return 'aspperl'
+ elseif lines:find('<%%') then
+ return 'aspvbs'
+ elseif lines:find('<%?') then
+ return 'php'
+ -- Pascal supports // comments but they're vary rarely used for file
+ -- headers so assume POV-Ray
+ elseif findany(lines, { '^%s{', '^%s%(%*' }) or matchregex(lines, pascal_keywords) then
+ return 'pascal'
+ else
+ M.asm_syntax(bufnr)
+ if vim.b[bufnr].asm_syntax then
+ return vim.fn.fnameescape(vim.b[bufnr].asm_syntax)
+ else
+ return 'pov'
+ end
+ end
+end
function M.inp(bufnr)
if getlines(bufnr, 1):find('^%*') then
- vim.bo[bufnr].filetype = 'abaqus'
+ return 'abaqus'
else
for _, line in ipairs(getlines(bufnr, 1, 500)) do
if line:lower():find('^header surface data') then
- vim.bo[bufnr].filetype = 'trasys'
- return
+ return 'trasys'
+ end
+ end
+ end
+end
+
+function M.lpc(bufnr)
+ if vim.g.lpc_syntax_for_c then
+ for _, line in ipairs(getlines(bufnr, 1, 12)) do
+ if
+ findany(line, {
+ '^//',
+ '^inherit',
+ '^private',
+ '^protected',
+ '^nosave',
+ '^string',
+ '^object',
+ '^mapping',
+ '^mixed',
+ })
+ then
+ return 'lpc'
end
end
end
+ return 'c'
end
-function M.lpc(path, bufnr) end
+function M.m(bufnr)
+ if vim.g.filetype_m then
+ return vim.g.filetype_m
+ end
-function M.lprolog(path, bufnr) end
+ -- Excluding end(for|function|if|switch|while) common to Murphi
+ local octave_block_terminators =
+ [[\<end\%(_try_catch\|classdef\|enumeration\|events\|methods\|parfor\|properties\)\>]]
+ local objc_preprocessor = [[\c^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>]]
-function M.m(path, bufnr) end
+ -- Whether we've seen a multiline comment leader
+ local saw_comment = false
+ for _, line in ipairs(getlines(bufnr, 1, 100)) do
+ if line:find('^%s*/%*') then
+ -- /* ... */ is a comment in Objective C and Murphi, so we can't conclude
+ -- it's either of them yet, but track this as a hint in case we don't see
+ -- anything more definitive.
+ saw_comment = true
+ end
+ if line:find('^%s*//') or matchregex(line, [[\c^\s*@import\>]]) or matchregex(line, objc_preprocessor) then
+ return 'objc'
+ end
+ if
+ findany(line, { '^%s*#', '^%s*%%!' })
+ or matchregex(line, [[\c^\s*unwind_protect\>]])
+ or matchregex(line, [[\c\%(^\|;\)\s*]] .. octave_block_terminators)
+ then
+ return 'octave'
+ elseif line:find('^%s*%%') then
+ return 'matlab'
+ elseif line:find('^%s*%(%*') then
+ return 'mma'
+ elseif matchregex(line, [[\c^\s*\(\(type\|var\)\>\|--\)]]) then
+ return 'murphi'
+ end
+ end
+
+ if saw_comment then
+ -- We didn't see anything definitive, but this looks like either Objective C
+ -- or Murphi based on the comment leader. Assume the former as it is more
+ -- common.
+ return 'objc'
+ else
+ -- Default is Matlab
+ return 'matlab'
+ end
+end
-- Rely on the file to start with a comment.
-- MS message text files use ';', Sendmail files use '#' or 'dnl'
@@ -210,112 +516,273 @@ function M.mc(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 20)) do
if findany(line:lower(), { '^%s*#', '^%s*dnl' }) then
-- Sendmail .mc file
- vim.bo[bufnr].filetype = 'm4'
- return
+ return 'm4'
elseif line:find('^%s*;') then
- vim.bo[bufnr].filetype = 'msmessages'
- return
+ return 'msmessages'
end
end
-- Default: Sendmail .mc file
- vim.bo[bufnr].filetype = 'm4'
+ return 'm4'
end
-function M.mm(path, bufnr) end
+function M.mm(bufnr)
+ for _, line in ipairs(getlines(bufnr, 1, 20)) do
+ if matchregex(line, [[\c^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)]]) then
+ return 'objcpp'
+ end
+ end
+ return 'nroff'
+end
function M.mms(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 20)) do
if findany(line, { '^%s*%%', '^%s*//', '^%*' }) then
- vim.bo[bufnr].filetype = 'mmix'
- return
+ return 'mmix'
elseif line:find('^%s*#') then
- vim.bo[bufnr].filetype = 'make'
- return
+ return 'make'
+ end
+ end
+ return 'mmix'
+end
+
+-- Returns true if file content looks like LambdaProlog
+local function is_lprolog(bufnr)
+ -- Skip apparent comments and blank lines, what looks like
+ -- LambdaProlog comment may be RAPID header
+ for _, line in ipairs(getlines(bufnr, 1, -1)) do
+ -- The second pattern matches a LambdaProlog comment
+ if not findany(line, { '^%s*$', '^%s*%%' }) then
+ -- The pattern must not catch a go.mod file
+ return matchregex(line, [[\c\<module\s\+\w\+\s*\.\s*\(%\|$\)]]) ~= nil
end
end
- vim.bo[bufnr].filetype = 'mmix'
end
-function M.mod(path, bufnr) end
+-- Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
+function M.mod(path, bufnr)
+ if vim.g.filetype_mod then
+ return vim.g.filetype_mod
+ elseif is_lprolog(bufnr) then
+ return 'lprolog'
+ elseif matchregex(nextnonblank(bufnr, 1), [[\%(\<MODULE\s\+\w\+\s*;\|^\s*(\*\)]]) then
+ return 'modula2'
+ elseif is_rapid(bufnr) then
+ return 'rapid'
+ elseif matchregex(path, [[\c\<go\.mod$]]) then
+ return 'gomod'
+ else
+ -- Nothing recognized, assume modsim3
+ return 'modsim3'
+ end
+end
-- This function checks if one of the first five lines start with a dot. In
--- that case it is probably an nroff file: 'filetype' is set and 1 is returned.
+-- that case it is probably an nroff file: 'filetype' is set and true is returned.
function M.nroff(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 5)) do
if line:find('^%.') then
- vim.bo[bufnr].filetype = 'nroff'
- return 1
+ return true
+ end
+ end
+ return false
+end
+
+-- If the file has an extension of 't' and is in a directory 't' or 'xt' then
+-- it is almost certainly a Perl test file.
+-- If the first line starts with '#' and contains 'perl' it's probably a Perl file.
+-- (Slow test) If a file contains a 'use' statement then it is almost certainly a Perl file.
+function M.perl(path, bufnr)
+ local dirname = vim.fn.expand(path, '%:p:h:t')
+ if vim.fn.expand(dirname, '%:e') == 't' and (dirname == 't' or dirname == 'xt') then
+ return true
+ end
+ local first_line = getlines(bufnr, 1)
+ if first_line:find('^#') and first_line:lower():find('perl') then
+ return true
+ end
+ for _, line in ipairs(getlines(bufnr, 1, 30)) do
+ if matchregex(line, [[\c^use\s\s*\k]]) then
+ return true
end
end
- return 0
+ return false
end
-function M.perl(path, bufnr) end
+function M.pl(bufnr)
+ if vim.g.filetype_pl then
+ return vim.g.filetype_pl
+ end
+ -- Recognize Prolog by specific text in the first non-empty line;
+ -- require a blank after the '%' because Perl uses "%list" and "%translate"
+ local line = nextnonblank(bufnr, 1)
+ if
+ line and line:find(':%-')
+ or matchregex(line, [[\c\<prolog\>]])
+ or findany(line, { '^%s*%%+%s', '^%s*%%+$', '^%s*/%*' })
+ then
+ return 'prolog'
+ else
+ return 'perl'
+ end
+end
-function M.pl(path, bufnr) end
+function M.pp(bufnr)
+ if vim.g.filetype_pp then
+ return vim.g.filetype_pp
+ end
+ local line = nextnonblank(bufnr, 1)
+ if findany(line, pascal_comments) or matchregex(line, pascal_keywords) then
+ return 'pascal'
+ else
+ return 'puppet'
+ end
+end
-function M.pp(path, bufnr) end
+function M.prg(bufnr)
+ if vim.g.filetype_prg then
+ return vim.g.filetype_prg
+ elseif is_rapid(bufnr) then
+ return 'rapid'
+ else
+ -- Nothing recognized, assume Clipper
+ return 'clipper'
+ end
+end
-function M.prg(path, bufnr) end
+-- This function checks for an assembly comment in the first ten lines.
+-- If not found, assume Progress.
+function M.progress_asm(bufnr)
+ if vim.g.filetype_i then
+ return vim.g.filetype_i
+ end
-function M.progress_asm(path, bufnr) end
+ for _, line in ipairs(getlines(bufnr, 1, 10)) do
+ if line:find('^%s*;') or line:find('^/%*') then
+ return M.asm(bufnr)
+ elseif not line:find('^%s*$') or line:find('^/%*') then
+ -- Not an empty line: doesn't look like valid assembly code
+ -- or it looks like a Progress /* comment.
+ break
+ end
+ end
+ return 'progress'
+end
function M.progress_cweb(bufnr)
if vim.g.filetype_w then
- vim.bo[bufnr].filetype = vim.g.filetype_w
+ return vim.g.filetype_w
else
- if getlines(bufnr, 1):find('^&ANALYZE') or getlines(bufnr, 3):find('^&GLOBAL%-DEFINE') then
- vim.bo[bufnr].filetype = 'progress'
+ if getlines(bufnr, 1):lower():find('^&analyze') or getlines(bufnr, 3):lower():find('^&global%-define') then
+ return 'progress'
else
- vim.bo[bufnr].filetype = 'cweb'
+ return 'cweb'
end
end
end
-function M.progress_pascal(path, bufnr) end
+-- This function checks for valid Pascal syntax in the first 10 lines.
+-- Look for either an opening comment or a program start.
+-- If not found, assume Progress.
+function M.progress_pascal(bufnr)
+ if vim.g.filetype_p then
+ return vim.g.filetype_p
+ end
+ for _, line in ipairs(getlines(bufnr, 1, 10)) do
+ if findany(line, pascal_comments) or matchregex(line, pascal_keywords) then
+ return 'pascal'
+ elseif not line:find('^%s*$') or line:find('^/%*') then
+ -- Not an empty line: Doesn't look like valid Pascal code.
+ -- Or it looks like a Progress /* comment
+ break
+ end
+ end
+ return 'progress'
+end
-function M.proto(path, bufnr) end
+-- Distinguish between "default" and Cproto prototype file.
+function M.proto(bufnr, default)
+ -- Cproto files have a comment in the first line and a function prototype in
+ -- the second line, it always ends in ";". Indent files may also have
+ -- comments, thus we can't match comments to see the difference.
+ -- IDL files can have a single ';' in the second line, require at least one
+ -- character before the ';'.
+ if getlines(bufnr, 2):find('.;$') then
+ return 'cpp'
+ else
+ return default
+ end
+end
function M.r(bufnr)
local lines = getlines(bufnr, 1, 50)
- -- TODO: \< / \> which match the beginning / end of a word
-- Rebol is easy to recognize, check for that first
- if table.concat(lines):lower():find('rebol') then
- vim.bo[bufnr].filetype = 'rebol'
- return
+ if matchregex(table.concat(lines), [[\c\<rebol\>]]) then
+ return 'rebol'
end
for _, line in ipairs(lines) do
-- R has # comments
if line:find('^%s*#') then
- vim.bo[bufnr].filetype = 'r'
- return
+ return 'r'
end
-- Rexx has /* comments */
if line:find('^%s*/%*') then
- vim.bo[bufnr].filetype = 'rexx'
- return
+ return 'rexx'
end
end
-- Nothing recognized, use user default or assume R
if vim.g.filetype_r then
- vim.bo[bufnr].filetype = vim.g.filetype_r
+ return vim.g.filetype_r
else
-- Rexx used to be the default, but R appears to be much more popular.
- vim.bo[bufnr].filetype = 'r'
+ return 'r'
end
end
function M.redif(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 5)) do
if line:lower():find('^template%-type:') then
- vim.bo[bufnr].filetype = 'redif'
+ return 'redif'
end
end
end
-function M.rules(path, bufnr) end
+local udev_rules_pattern = '^%s*udev_rules%s*=%s*"([%^"]+)/*".*'
+function M.rules(path, bufnr)
+ path = path:lower()
+ if
+ findany(path, {
+ '/etc/udev/.*%.rules$',
+ '/etc/udev/rules%.d/.*$.rules$',
+ '/usr/lib/udev/.*%.rules$',
+ '/usr/lib/udev/rules%.d/.*%.rules$',
+ '/lib/udev/.*%.rules$',
+ '/lib/udev/rules%.d/.*%.rules$',
+ })
+ then
+ return 'udevrules'
+ elseif path:find('^/etc/ufw/') then
+ -- Better than hog
+ return 'conf'
+ elseif findany(path, { '^/etc/polkit%-1/rules%.d', '/usr/share/polkit%-1/rules%.d' }) then
+ return 'javascript'
+ else
+ local ok, config_lines = pcall(vim.fn.readfile, '/etc/udev/udev.conf')
+ if not ok then
+ return 'hog'
+ end
+ local dir = vim.fn.expand(path, ':h')
+ for _, line in ipairs(config_lines) do
+ local match = line:match(udev_rules_pattern)
+ local udev_rules = line:gsub(udev_rules_pattern, match, 1)
+ if dir == udev_rules then
+ return 'udevrules'
+ end
+ end
+ return 'hog'
+ end
+end
-- This function checks the first 25 lines of file extension "sc" to resolve
-- detection between scala and SuperCollider
@@ -327,11 +794,10 @@ function M.sc(bufnr)
{ '[A-Za-z0-9]*%s:%s[A-Za-z0-9]', 'var%s<', 'classvar%s<', '%^this.*', '|%w*|', '%+%s%w*%s{', '%*ar%s' }
)
then
- vim.bo[bufnr].filetype = 'supercollider'
- return
+ return 'supercollider'
end
end
- vim.bo[bufnr].filetype = 'scala'
+ return 'scala'
end
-- This function checks the first line of file extension "scd" to resolve
@@ -341,29 +807,140 @@ function M.scd(bufnr)
local opt = [[%s+"[^"]*"]]
local line = getlines(bufnr, 1)
if findany(line, { first .. '$', first .. opt .. '$', first .. opt .. opt .. '$' }) then
- vim.bo[bufnr].filetype = 'scdoc'
+ return 'scdoc'
else
- vim.bo[bufnr].filetype = 'supercollider'
+ return 'supercollider'
end
end
-function M.sh(path, bufnr) end
+-- Also called from filetype.lua
+function M.sh(path, bufnr, name)
+ if did_filetype() or path:find(vim.g.ft_ignore_pat) then
+ -- Filetype was already detected or detection should be skipped
+ return
+ end
+
+ if matchregex(name, [[\<csh\>]]) then
+ -- Some .sh scripts contain #!/bin/csh.
+ return M.shell(path, bufnr, 'csh')
+ -- Some .sh scripts contain #!/bin/tcsh.
+ elseif matchregex(name, [[\<tcsh\>]]) then
+ return M.shell(path, bufnr, 'tcsh')
+ -- Some .sh scripts contain #!/bin/zsh.
+ elseif matchregex(name, [[\<zsh\>]]) then
+ return M.shell(path, bufnr, 'zsh')
+ elseif matchregex(name, [[\<ksh\>]]) then
+ vim.b[bufnr].is_kornshell = 1
+ vim.b[bufnr].is_bash = nil
+ vim.b[bufnr].is_sh = nil
+ elseif vim.g.bash_is_sh or matchregex(name, [[\<bash\>]]) or matchregex(name, [[\<bash2\>]]) then
+ vim.b[bufnr].is_bash = 1
+ vim.b[bufnr].is_kornshell = nil
+ vim.b[bufnr].is_sh = nil
+ elseif matchregex(name, [[\<sh\>]]) then
+ vim.b[bufnr].is_sh = 1
+ vim.b[bufnr].is_kornshell = nil
+ vim.b[bufnr].is_bash = nil
+ end
+ return M.shell(path, bufnr, 'sh')
+end
-function M.shell(path, bufnr) end
+-- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl.
+-- Also called from scripts.vim, thus can't be local to this script. [TODO]
+function M.shell(path, bufnr, name)
+ if did_filetype() or matchregex(path, vim.g.ft_ignore_pat) then
+ -- Filetype was already detected or detection should be skipped
+ return
+ end
+ local prev_line = ''
+ for _, line in ipairs(getlines(bufnr, 2, -1)) do
+ line = line:lower()
+ if line:find('%s*exec%s') and not prev_line:find('^%s*#.*\\$') then
+ -- Found an "exec" line after a comment with continuation
+ local n = line:gsub('%s*exec%s+([^ ]*/)?', '', 1)
+ if matchregex(n, [[\c\<tclsh\|\<wish]]) then
+ return 'tcl'
+ end
+ end
+ prev_line = line
+ end
+ return name
+end
function M.sql(bufnr)
if vim.g.filetype_sql then
- vim.bo[bufnr].filetype = vim.g.filetype_sql
+ return vim.g.filetype_sql
else
- vim.bo[bufnr].filetype = 'sql'
+ return 'sql'
end
end
-function M.src(path, bufnr) end
+-- Determine if a *.src file is Kuka Robot Language
+function M.src(bufnr)
+ if vim.g.filetype_src then
+ return vim.g.filetype_src
+ end
+ local line = nextnonblank(bufnr, 1)
+ if matchregex(line, [[\c\v^\s*%(\&\w+|%(global\s+)?def%(fct)?>)]]) then
+ return 'krl'
+ end
+end
-function M.sys(path, bufnr) end
+function M.sys(bufnr)
+ if vim.g.filetype_sys then
+ return vim.g.filetype_sys
+ elseif is_rapid(bufnr) then
+ return 'rapid'
+ else
+ return 'bat'
+ end
+end
-function M.tex(path, bufnr) end
+-- Choose context, plaintex, or tex (LaTeX) based on these rules:
+-- 1. Check the first line of the file for "%&<format>".
+-- 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
+-- 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc.
+function M.tex(path, bufnr)
+ local format = getlines(bufnr, 1):find('^%%&%s*(%a+)')
+ if format then
+ format = format:lower():gsub('pdf', '', 1)
+ if format == 'tex' then
+ return 'tex'
+ elseif format == 'plaintex' then
+ return 'plaintex'
+ end
+ elseif path:lower():find('tex/context/.*/.*%.tex') then
+ return 'context'
+ else
+ local lpat = [[documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>]]
+ local cpat =
+ [[start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>]]
+
+ for i, l in ipairs(getlines(bufnr, 1, 1000)) do
+ -- Find first non-comment line
+ if not l:find('^%s*%%%S') then
+ -- Check the next thousand lines for a LaTeX or ConTeXt keyword.
+ for _, line in ipairs(getlines(bufnr, i + 1, i + 1000)) do
+ local lpat_match, cpat_match = matchregex(line, [[\c^\s*\\\%(]] .. lpat .. [[\)\|^\s*\\\(]] .. cpat .. [[\)]])
+ if lpat_match then
+ return 'tex'
+ elseif cpat_match then
+ return 'context'
+ end
+ end
+ end
+ end
+ -- TODO: add AMSTeX, RevTex, others?
+ if not vim.g.tex_flavor or vim.g.tex_flavor == 'plain' then
+ return 'plaintex'
+ elseif vim.g.tex_flavor == 'context' then
+ return 'context'
+ else
+ -- Probably LaTeX
+ return 'tex'
+ end
+ end
+end
-- Determine if a *.tf file is TF mud client or terraform
function M.tf(bufnr)
@@ -371,45 +948,39 @@ function M.tf(bufnr)
-- Assume terraform file on a non-empty line (not whitespace-only)
-- and when the first non-whitespace character is not a ; or /
if not line:find('^%s*$') and not line:find('^%s*[;/]') then
- vim.bo[bufnr].filetype = 'terraform'
- return
+ return 'terraform'
end
end
- vim.bo[bufnr].filetype = 'tf'
+ return 'tf'
end
function M.xml(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 100)) do
+ local is_docbook4 = line:find('<!DOCTYPE.*DocBook')
line = line:lower()
- local is_docbook4 = line:find('<!doctype.*docbook')
local is_docbook5 = line:find([[ xmlns="http://docbook.org/ns/docbook"]])
if is_docbook4 or is_docbook5 then
vim.b[bufnr].docbk_type = 'xml'
vim.b[bufnr].docbk_ver = is_docbook4 and 4 or 5
- vim.bo[bufnr].filetype = 'docbk'
- return
+ return 'docbk'
end
if line:find([[xmlns:xbl="http://www.mozilla.org/xbl"]]) then
- vim.bo[bufnr].filetype = 'xbl'
- return
+ return 'xbl'
end
end
- vim.bo[bufnr].filetype = 'xml'
+ return 'xml'
end
function M.y(bufnr)
for _, line in ipairs(getlines(bufnr, 1, 100)) do
if line:find('^%s*%%') then
- vim.bo[bufnr].filetype = 'yacc'
- return
+ return 'yacc'
end
- -- TODO: in the Vim regex, \> is used to match the end of the word after "class",
- -- can this be omitted?
- if findany(line, { '^%s*#', '^%class', '^%s*#%s*include' }) then
- vim.bo[bufnr].filetype = 'racc'
+ if matchregex(line, [[\c^\s*\(#\|class\>\)]]) and not line:lower():find('^%s*#%s*include') then
+ return 'racc'
end
end
- vim.bo[bufnr].filetype = 'yacc'
+ return 'yacc'
end
-- luacheck: pop
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index e99a7c282c..07987ee003 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -1,5 +1,3 @@
-local if_nil = vim.F.if_nil
-
local default_handlers = require('vim.lsp.handlers')
local log = require('vim.lsp.log')
local lsp_rpc = require('vim.lsp.rpc')
@@ -8,11 +6,16 @@ local util = require('vim.lsp.util')
local sync = require('vim.lsp.sync')
local vim = vim
-local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option =
- vim.api.nvim_err_writeln, vim.api.nvim_buf_get_lines, vim.api.nvim_command, vim.api.nvim_buf_get_option
+local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option, nvim_exec_autocmds =
+ vim.api.nvim_err_writeln,
+ vim.api.nvim_buf_get_lines,
+ vim.api.nvim_command,
+ vim.api.nvim_buf_get_option,
+ vim.api.nvim_exec_autocmds
local uv = vim.loop
local tbl_isempty, tbl_extend = vim.tbl_isempty, vim.tbl_extend
local validate = vim.validate
+local if_nil = vim.F.if_nil
local lsp = {
protocol = protocol,
@@ -867,15 +870,27 @@ function lsp.start_client(config)
pcall(config.on_exit, code, signal, client_id)
end
+ for bufnr, client_ids in pairs(all_buffer_active_clients) do
+ if client_ids[client_id] then
+ vim.schedule(function()
+ nvim_exec_autocmds('LspDetach', {
+ buffer = bufnr,
+ modeline = false,
+ data = { client_id = client_id },
+ })
+
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id)
+ vim.diagnostic.reset(namespace, bufnr)
+ end)
+
+ client_ids[client_id] = nil
+ end
+ end
+
active_clients[client_id] = nil
uninitialized_clients[client_id] = nil
- lsp.diagnostic.reset(client_id, all_buffer_active_clients)
changetracking.reset(client_id)
- for _, client_ids in pairs(all_buffer_active_clients) do
- client_ids[client_id] = nil
- end
-
if code ~= 0 or (signal ~= 0 and signal ~= 15) then
local msg = string.format('Client %s quit with exit code %s and signal %s', client_id, code, signal)
vim.schedule(function()
@@ -1213,6 +1228,13 @@ function lsp.start_client(config)
---@param bufnr (number) Buffer number
function client._on_attach(bufnr)
text_document_did_open_handler(bufnr, client)
+
+ nvim_exec_autocmds('LspAttach', {
+ buffer = bufnr,
+ modeline = false,
+ data = { client_id = client.id },
+ })
+
if config.on_attach then
-- TODO(ashkan) handle errors.
pcall(config.on_attach, client, bufnr)
@@ -1359,6 +1381,12 @@ function lsp.buf_detach_client(bufnr, client_id)
return
end
+ nvim_exec_autocmds('LspDetach', {
+ buffer = bufnr,
+ modeline = false,
+ data = { client_id = client_id },
+ })
+
changetracking.reset_buf(client, bufnr)
if vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then
@@ -1435,11 +1463,29 @@ function lsp.stop_client(client_id, force)
end
end
---- Gets all active clients.
+--- Get active clients.
---
----@returns Table of |vim.lsp.client| objects
-function lsp.get_active_clients()
- return vim.tbl_values(active_clients)
+---@param filter (table|nil) A table with key-value pairs used to filter the
+--- returned clients. The available keys are:
+--- - id (number): Only return clients with the given id
+--- - bufnr (number): Only return clients attached to this buffer
+--- - name (string): Only return clients with the given name
+---@returns (table) List of |vim.lsp.client| objects
+function lsp.get_active_clients(filter)
+ validate({ filter = { filter, 't', true } })
+
+ filter = filter or {}
+
+ local clients = {}
+
+ local t = filter.bufnr and (all_buffer_active_clients[resolve_bufnr(filter.bufnr)] or {}) or active_clients
+ for client_id in pairs(t) do
+ local client = active_clients[client_id]
+ if (filter.id == nil or client.id == filter.id) and (filter.name == nil or client.name == filter.name) then
+ clients[#clients + 1] = client
+ end
+ end
+ return clients
end
function lsp._vim_exit_handler()
@@ -1814,12 +1860,13 @@ end
--- is a |vim.lsp.client| object.
---
---@param bufnr (optional, number): Buffer handle, or 0 for current
+---@returns (table) Table of (client_id, client) pairs
+---@deprecated Use |vim.lsp.get_active_clients()| instead.
function lsp.buf_get_clients(bufnr)
- bufnr = resolve_bufnr(bufnr)
local result = {}
- for_each_buffer_client(bufnr, function(client, client_id)
- result[client_id] = client
- end)
+ for _, client in ipairs(lsp.get_active_clients({ bufnr = resolve_bufnr(bufnr) })) do
+ result[client.id] = client
+ end
return result
end
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index b0bf2c6e5b..1207da094a 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -63,26 +63,45 @@ function M.hover()
request('textDocument/hover', params)
end
+---@private
+local function request_with_options(name, params, options)
+ local req_handler
+ if options then
+ req_handler = function(err, result, ctx, config)
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
+ local handler = client.handlers[name] or vim.lsp.handlers[name]
+ handler(err, result, ctx, vim.tbl_extend('force', config or {}, options))
+ end
+ end
+ request(name, params, req_handler)
+end
+
--- Jumps to the declaration of the symbol under the cursor.
---@note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead.
---
-function M.declaration()
+---@param options table|nil additional options
+--- - reuse_win: (boolean) Jump to existing window if buffer is already open.
+function M.declaration(options)
local params = util.make_position_params()
- request('textDocument/declaration', params)
+ request_with_options('textDocument/declaration', params, options)
end
--- Jumps to the definition of the symbol under the cursor.
---
-function M.definition()
+---@param options table|nil additional options
+--- - reuse_win: (boolean) Jump to existing window if buffer is already open.
+function M.definition(options)
local params = util.make_position_params()
- request('textDocument/definition', params)
+ request_with_options('textDocument/definition', params, options)
end
--- Jumps to the definition of the type of the symbol under the cursor.
---
-function M.type_definition()
+---@param options table|nil additional options
+--- - reuse_win: (boolean) Jump to existing window if buffer is already open.
+function M.type_definition(options)
local params = util.make_position_params()
- request('textDocument/typeDefinition', params)
+ request_with_options('textDocument/typeDefinition', params, options)
end
--- Lists all the implementations for the symbol under the cursor in the
@@ -844,7 +863,8 @@ function M.code_action(options)
end
local context = options.context or {}
if not context.diagnostics then
- context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
+ local bufnr = vim.api.nvim_get_current_buf()
+ context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr)
end
local params = util.make_range_params()
params.context = context
@@ -870,7 +890,8 @@ function M.range_code_action(context, start_pos, end_pos)
validate({ context = { context, 't', true } })
context = context or {}
if not context.diagnostics then
- context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
+ local bufnr = vim.api.nvim_get_current_buf()
+ context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr)
end
local params = util.make_given_range_params(start_pos, end_pos)
params.context = context
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index b3a253c118..61cc89dcac 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -327,18 +327,20 @@ M['textDocument/hover'] = M.hover
---@param result (table) result of LSP method; a location or a list of locations.
---@param ctx (table) table containing the context of the request, including the method
---(`textDocument/definition` can return `Location` or `Location[]`
-local function location_handler(_, result, ctx, _)
+local function location_handler(_, result, ctx, config)
if result == nil or vim.tbl_isempty(result) then
local _ = log.info() and log.info(ctx.method, 'No location found')
return nil
end
local client = vim.lsp.get_client_by_id(ctx.client_id)
+ config = config or {}
+
-- textDocument/definition can return Location or Location[]
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
if vim.tbl_islist(result) then
- util.jump_to_location(result[1], client.offset_encoding)
+ util.jump_to_location(result[1], client.offset_encoding, config.reuse_win)
if #result > 1 then
vim.fn.setqflist({}, ' ', {
@@ -348,7 +350,7 @@ local function location_handler(_, result, ctx, _)
api.nvim_command('botright copen')
end
else
- util.jump_to_location(result, client.offset_encoding)
+ util.jump_to_location(result, client.offset_encoding, config.reuse_win)
end
end
diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua
index 74714ebc6b..bf8fe0932e 100644
--- a/runtime/lua/vim/lsp/health.lua
+++ b/runtime/lua/vim/lsp/health.lua
@@ -17,7 +17,8 @@ function M.check()
local log_path = vim.lsp.get_log_path()
report_info(string.format('Log path: %s', log_path))
- local log_size = vim.loop.fs_stat(log_path).size
+ local log_file = vim.loop.fs_stat(log_path)
+ local log_size = log_file and log_file.size or 0
local report_fn = (log_size / 1000000 > 100 and report_warn or report_info)
report_fn(string.format('Log size: %d KB', log_size / 1000))
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 2dcafc92bc..ad2498fb6f 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -4,6 +4,8 @@ local log = require('vim.lsp.log')
local protocol = require('vim.lsp.protocol')
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
+local is_win = uv.os_uname().version:find('Windows')
+
---@private
--- Checks whether a given path exists and is a directory.
---@param filename (string) path to check
@@ -321,7 +323,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
local spawn_params = {
args = cmd_args,
stdio = { stdin, stdout, stderr },
- detached = true,
+ detached = not is_win,
}
if extra_spawn_params then
spawn_params.cwd = extra_spawn_params.cwd
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index e8a8e06f46..4663cf9f09 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -684,6 +684,16 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
return matches
end
+---@private
+--- Like vim.fn.bufwinid except it works across tabpages.
+local function bufwinid(bufnr)
+ for _, win in ipairs(api.nvim_list_wins()) do
+ if api.nvim_win_get_buf(win) == bufnr then
+ return win
+ end
+ end
+end
+
--- Rename old_fname to new_fname
---
---@param opts (table)
@@ -708,10 +718,9 @@ function M.rename(old_fname, new_fname, opts)
assert(ok, err)
local newbuf = vim.fn.bufadd(new_fname)
- for _, win in pairs(api.nvim_list_wins()) do
- if api.nvim_win_get_buf(win) == oldbuf then
- api.nvim_win_set_buf(win, newbuf)
- end
+ local win = bufwinid(oldbuf)
+ if win then
+ api.nvim_win_set_buf(win, newbuf)
end
api.nvim_buf_delete(oldbuf, { force = true })
end
@@ -1004,8 +1013,9 @@ end
---
---@param location table (`Location`|`LocationLink`)
---@param offset_encoding string utf-8|utf-16|utf-32 (required)
+---@param reuse_win boolean Jump to existing window if buffer is already opened.
---@returns `true` if the jump succeeded
-function M.jump_to_location(location, offset_encoding)
+function M.jump_to_location(location, offset_encoding, reuse_win)
-- location may be Location or LocationLink
local uri = location.uri or location.targetUri
if uri == nil then
@@ -1024,8 +1034,13 @@ function M.jump_to_location(location, offset_encoding)
vim.fn.settagstack(vim.fn.win_getid(), { items = items }, 't')
--- Jump to new location (adjusting for UTF-16 encoding of characters)
- api.nvim_set_current_buf(bufnr)
- api.nvim_buf_set_option(bufnr, 'buflisted', true)
+ local win = reuse_win and bufwinid(bufnr)
+ if win then
+ api.nvim_set_current_win(win)
+ else
+ api.nvim_set_current_buf(bufnr)
+ api.nvim_buf_set_option(bufnr, 'buflisted', true)
+ end
local range = location.range or location.targetSelectionRange
local row = range.start.line
local col = get_line_byte_from_position(bufnr, range.start, offset_encoding)
@@ -1676,7 +1691,7 @@ end
---
---@param items (table) list of items
function M.set_loclist(items, win_id)
- vim.api.nvim_echo({ { 'vim.lsp.util.set_loclist is deprecated. See :h deprecated', 'WarningMsg' } }, true, {})
+ vim.deprecate('vim.lsp.util.set_loclist', 'setloclist', '0.8')
vim.fn.setloclist(win_id or 0, {}, ' ', {
title = 'Language Server',
items = items,
@@ -1690,7 +1705,7 @@ end
---
---@param items (table) list of items
function M.set_qflist(items)
- vim.api.nvim_echo({ { 'vim.lsp.util.set_qflist is deprecated. See :h deprecated', 'WarningMsg' } }, true, {})
+ vim.deprecate('vim.lsp.util.set_qflist', 'setqflist', '0.8')
vim.fn.setqflist({}, ' ', {
title = 'Language Server',
items = items,
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 2157112d2f..57d8c5fd21 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -519,17 +519,11 @@ local function tree_contains(tree, range)
local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2])
local end_fits = end_row > range[3] or (end_row == range[3] and end_col >= range[4])
- if start_fits and end_fits then
- return true
- end
-
- return false
+ return start_fits and end_fits
end
--- Determines whether {range} is contained in this language tree
---
---- This goes down the tree to recursively check children.
----
---@param range A range, that is a `{ start_line, start_col, end_line, end_col }` table.
function LanguageTree:contains(range)
for _, tree in pairs(self._trees) do
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index a13e945098..54f57a260c 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -229,8 +229,6 @@ call append("$", "compatible\tbehave very Vi compatible (not advisable)")
call <SID>BinOptionG("cp", &cp)
call append("$", "cpoptions\tlist of flags to specify Vi compatibility")
call <SID>OptionG("cpo", &cpo)
-call append("$", "insertmode\tuse Insert mode as the default mode")
-call <SID>BinOptionG("im", &im)
call append("$", "paste\tpaste mode, insert typed text literally")
call <SID>BinOptionG("paste", &paste)
call append("$", "pastetoggle\tkey sequence to toggle paste mode")
@@ -956,7 +954,6 @@ call <SID>Header("mapping")
call append("$", "maxmapdepth\tmaximum depth of mapping")
call append("$", " \tset mmd=" . &mmd)
call append("$", "remap\trecognize mappings in mapped keys")
-call <SID>BinOptionG("remap", &remap)
call append("$", "timeout\tallow timing out halfway into a mapping")
call <SID>BinOptionG("to", &to)
call append("$", "ttimeout\tallow timing out halfway into a key code")
diff --git a/src/clint.py b/src/clint.py
index b0992fcd63..944946bd16 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -49,7 +49,6 @@ import re
import sre_compile
import string
import sys
-import unicodedata
import json
import collections # for defaultdict
@@ -173,12 +172,9 @@ _ERROR_CATEGORIES = [
'build/deprecated',
'build/endif_comment',
'build/header_guard',
- 'build/include',
'build/include_alpha',
'build/printf_format',
'build/storage_class',
- 'build/useless_fattr',
- 'readability/alt_tokens',
'readability/bool',
'readability/braces',
'readability/multiline_comment',
@@ -189,7 +185,6 @@ _ERROR_CATEGORIES = [
'readability/increment',
'runtime/arrays',
'runtime/int',
- 'runtime/invalid_increment',
'runtime/memset',
'runtime/printf',
'runtime/printf_format',
@@ -197,20 +192,13 @@ _ERROR_CATEGORIES = [
'runtime/deprecated',
'syntax/parenthesis',
'whitespace/alignment',
- 'whitespace/blank_line',
'whitespace/braces',
'whitespace/comments',
- 'whitespace/empty_conditional_body',
- 'whitespace/empty_loop_body',
- 'whitespace/end_of_line',
- 'whitespace/ending_newline',
'whitespace/indent',
'whitespace/newline',
'whitespace/operators',
'whitespace/parens',
- 'whitespace/tab',
'whitespace/todo',
- 'whitespace/line_continuation',
'whitespace/cast',
]
@@ -220,11 +208,6 @@ _ERROR_CATEGORIES = [
# All entries here should start with a '-' or '+', as in the --filter= flag.
_DEFAULT_FILTERS = ['-build/include_alpha']
-# These constants define types of headers for use with
-# _IncludeState.CheckNextIncludeOrder().
-_C_SYS_HEADER = 1
-_OTHER_HEADER = 5
-
# These constants define the current inline assembly state
_NO_ASM = 0 # Outside of inline assembly block
_INSIDE_ASM = 1 # Inside inline assembly block
@@ -356,96 +339,6 @@ def Search(pattern, s):
return _regexp_compile_cache[pattern].search(s)
-class _IncludeState(dict): # lgtm [py/missing-equals]
-
- """Tracks line numbers for includes, and the order in which includes appear.
-
- As a dict, an _IncludeState object serves as a mapping between include
- filename and line number on which that file was included.
-
- Call CheckNextIncludeOrder() once for each header in the file, passing
- in the type constants defined above.
-
- """
- # self._section will move monotonically through this set. If it ever
- # needs to move backwards, CheckNextIncludeOrder will raise an error.
- _INITIAL_SECTION = 0
- _C_SECTION = 2
- _OTHER_H_SECTION = 4
-
- _TYPE_NAMES = {
- _C_SYS_HEADER: 'C system header',
- _OTHER_HEADER: 'other header',
- }
- _SECTION_NAMES = {
- _INITIAL_SECTION: "... nothing. (This can't be an error.)",
- _C_SECTION: 'C system header',
- _OTHER_H_SECTION: 'other header',
- }
-
- def __init__(self):
- dict.__init__(self)
- self.ResetSection()
-
- def ResetSection(self):
- # The name of the current section.
- self._section = self._INITIAL_SECTION
- # The path of last found header.
- self._last_header = ''
-
- def SetLastHeader(self, header_path):
- self._last_header = header_path
-
- def CanonicalizeAlphabeticalOrder(self, header_path):
- """Returns a path canonicalized for alphabetical comparison.
-
- - replaces "-" with "_" so they both cmp the same.
- - lowercase everything, just in case.
-
- Args:
- header_path: Path to be canonicalized.
-
- Returns:
- Canonicalized path.
- """
- return header_path.replace('-', '_').lower()
-
- def CheckNextIncludeOrder(self, header_type):
- """Returns a non-empty error message if the next header is out of order.
-
- This function also updates the internal state to be ready to check
- the next include.
-
- Args:
- header_type: One of the _XXX_HEADER constants defined above.
-
- Returns:
- The empty string if the header is in the right order, or an
- error message describing what's wrong.
-
- """
- error_message = ('Found %s after %s' %
- (self._TYPE_NAMES[header_type],
- self._SECTION_NAMES[self._section]))
-
- last_section = self._section
-
- if header_type == _C_SYS_HEADER:
- if self._section <= self._C_SECTION:
- self._section = self._C_SECTION
- else:
- self._last_header = ''
- return error_message
- else:
- assert header_type == _OTHER_HEADER
- self._section = self._OTHER_H_SECTION
-
- if last_section != self._section:
- self._last_header = ''
-
- return ''
-
-
class _CppLintState:
"""Maintains module-wide state.."""
@@ -932,7 +825,6 @@ BRACES = {
'(': ')',
'{': '}',
'[': ']',
- # '<': '>', C++-specific pair removed
}
@@ -1253,24 +1145,6 @@ def CheckForBadCharacters(filename, lines, error):
5, 'Line contains NUL byte.')
-def CheckForNewlineAtEOF(filename, lines, error):
- """Logs an error if there is no newline char at the end of the file.
-
- Args:
- filename: The name of the current file.
- lines: An array of strings, each representing a line of the file.
- error: The function to call with any errors found.
- """
-
- # The array lines() was created by adding two newlines to the
- # original file (go figure), then splitting on \n.
- # To verify that the file ends in \n, we just have to make sure the
- # last-but-two element of lines() exists and is empty.
- if len(lines) < 3 or lines[-2]:
- error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
- 'Could not find a newline character at the end of the file.')
-
-
def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
"""Logs an error if we see /* ... */ or "..." that extend past one line.
@@ -2156,7 +2030,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
# for the case where the previous line is indented 6 spaces, which
# may happen when the initializers of a constructor do not fit into
# a 80 column line.
- exception = False
if Match(r' {6}\w', prev_line): # Initializer list?
# We are looking for the opening column of initializer list,
# which should be indented 4 spaces to cause 6 space indentation
@@ -2165,39 +2038,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
while (search_position >= 0
and Match(r' {6}\w', elided[search_position])):
search_position -= 1
- exception = (search_position >= 0
- and elided[search_position][:5] == ' :')
- else:
- # Search for the function arguments or an initializer list. We
- # use a simple heuristic here: If the line is indented 4 spaces;
- # and we have a closing paren, without the opening paren,
- # followed by an opening brace or colon (for initializer lists)
- # we assume that it is the last line of a function header. If
- # we have a colon indented 4 spaces, it is an initializer list.
- exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
- prev_line)
- or Match(r' {4}:', prev_line))
-
- if not exception:
- error(filename, linenum, 'whitespace/blank_line', 2,
- 'Redundant blank line at the start of a code block '
- 'should be deleted.')
- # Ignore blank lines at the end of a block in a long if-else
- # chain, like this:
- # if (condition1) {
- # // Something followed by a blank line
- #
- # } else if (condition2) {
- # // Something else
- # }
- if linenum + 1 < clean_lines.NumLines():
- next_line = raw[linenum + 1]
- if (next_line
- and Match(r'\s*}', next_line)
- and next_line.find('} else ') == -1):
- error(filename, linenum, 'whitespace/blank_line', 3,
- 'Redundant blank line at the end of a code block '
- 'should be deleted.')
# Next, we complain if there's a comment too near the text
commentpos = line.find('//')
@@ -2334,12 +2174,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
error(filename, linenum, 'whitespace/operators', 4,
'Extra space for operator %s' % match.group(1))
- # A pet peeve of mine: no spaces after an if, while, switch, or for
- match = Search(r' (if\(|for\(|while\(|switch\()', line)
- if match:
- error(filename, linenum, 'whitespace/parens', 5,
- 'Missing space before ( in %s' % match.group(1))
-
# For if/for/while/switch, the left and right parens should be
# consistent about how many spaces are inside the parens, and
# there should either be zero or one spaces inside the parens.
@@ -2407,9 +2241,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
for offset in range(endlinenum + 1,
min(endlinenum + 3, clean_lines.NumLines() - 1)):
trailing_text += clean_lines.elided[offset]
- if not Match(r'^[\s}]*[{.;,)<\]]', trailing_text):
- error(filename, linenum, 'whitespace/braces', 5,
- 'Missing space before {')
# Make sure '} else {' has spaces.
if Search(r'}else', line):
@@ -2429,18 +2260,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
error(filename, linenum, 'whitespace/braces', 5,
'Missing space before }')
- if Search(r'\S {2,}\\$', line):
- error(filename, linenum, 'whitespace/line_continuation', 5,
- 'Too many spaces before \\, line continuation character must be '
- 'preceded by exactly one space. For “blank lines” '
- 'it is preferred to use the same amount of spaces as preceding '
- 'indent')
-
- if Match(r'^ +#', line):
- error(filename, linenum, 'whitespace/indent', 5,
- 'Must not indent preprocessor directives, use 1-space indent '
- 'after the hash')
-
cast_line = re.sub(r'^# *define +\w+\([^)]*\)', '', line)
match = Search(r'(?<!\bkvec_t)'
r'(?<!\bkvec_withinit_t)'
@@ -2717,65 +2536,6 @@ def CheckBraces(filename, clean_lines, linenum, error):
"You don't need a ; after a }")
-def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
- """Look for empty loop/conditional body with only a single semicolon.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
-
- # Search for loop keywords at the beginning of the line. Because only
- # whitespaces are allowed before the keywords, this will also ignore most
- # do-while-loops, since those lines should start with closing brace.
- #
- # We also check "if" blocks here, since an empty conditional block
- # is likely an error.
- line = clean_lines.elided[linenum]
- matched = Match(r'\s*(for|while|if)\s*\(', line)
- if matched:
- # Find the end of the conditional expression
- (end_line, end_linenum, end_pos) = CloseExpression(
- clean_lines, linenum, line.find('('))
-
- # Output warning if what follows the condition expression is a
- # semicolon. No warning for all other cases, including whitespace or
- # newline, since we have a separate check for semicolons preceded by
- # whitespace.
- if end_pos >= 0 and Match(r';', end_line[end_pos:]):
- if matched.group(1) == 'if':
- error(filename, end_linenum,
- 'whitespace/empty_conditional_body', 5,
- 'Empty conditional bodies should use {}')
- else:
- error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
- 'Empty loop bodies should use {} or continue')
-
-
-def GetLineWidth(line):
- """Determines the width of the line in column positions.
-
- Args:
- line: A string, which may be a Unicode string.
-
- Returns:
- The width of the line in column positions, accounting for Unicode
- combining characters and wide characters.
- """
- if isinstance(line, str):
- width = 0
- for uc in unicodedata.normalize('NFC', line):
- if unicodedata.east_asian_width(uc) in ('W', 'F'):
- width += 2
- elif not unicodedata.combining(uc):
- width += 1
- return width
- else:
- return len(line)
-
-
def CheckStyle(filename, clean_lines, linenum, error):
"""Checks rules from the 'C++ style rules' section of cppguide.html.
@@ -2796,10 +2556,6 @@ def CheckStyle(filename, clean_lines, linenum, error):
raw_lines = clean_lines.lines_without_raw_strings
line = raw_lines[linenum]
- if line.find('\t') != -1:
- error(filename, linenum, 'whitespace/tab', 1,
- 'Tab found; better to use spaces')
-
# One or three blank spaces at the beginning of the line is weird; it's
# hard to reconcile that with 2-space indents.
# NOTE: here are the conditions rob pike used for his tests. Mine aren't
@@ -2815,18 +2571,9 @@ def CheckStyle(filename, clean_lines, linenum, error):
# if(prevodd && match(prevprev, " +for \\(")) complain = 0;
initial_spaces = 0
cleansed_line = clean_lines.elided[linenum]
+
while initial_spaces < len(line) and line[initial_spaces] == ' ':
initial_spaces += 1
- if line and line[-1].isspace():
- error(filename, linenum, 'whitespace/end_of_line', 4,
- 'Line ends in whitespace. Consider deleting these extra spaces.')
- # There are certain situations we allow one space, notably for section
- # labels
- elif ((initial_spaces == 1 or initial_spaces == 3) and
- not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
- error(filename, linenum, 'whitespace/indent', 3,
- 'Weird number of spaces at line-start. '
- 'Are you using a 2-space indent?')
if (cleansed_line.count(';') > 1 and
# for loops are allowed two ;'s (and may run over two lines).
@@ -2842,45 +2589,12 @@ def CheckStyle(filename, clean_lines, linenum, error):
# Some more style checks
CheckBraces(filename, clean_lines, linenum, error)
- CheckEmptyBlockBody(filename, clean_lines, linenum, error)
CheckSpacing(filename, clean_lines, linenum, error)
_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
-def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
- """Check rules that are applicable to #include lines.
-
- Strings on #include lines are NOT removed from elided line, to make
- certain tasks easier. However, to prevent false positives, checks
- applicable to #include lines in CheckLanguage must be put here.
-
- Args:
- filename : The name of the current file.
- clean_lines : A CleansedLines instance containing the file.
- linenum : The number of the line to check.
- include_state : An _IncludeState instance in which the headers are
- inserted.
- error : The function to call with any errors found.
- """
-
- line = clean_lines.lines[linenum]
-
- # we shouldn't include a file more than once. actually, there are a
- # handful of instances where doing so is okay, but in general it's
- # not.
- match = _RE_PATTERN_INCLUDE.search(line)
- if match:
- include = match.group(2)
- is_system = (match.group(1) == '<')
- if include in include_state:
- if is_system or not include.endswith('.c.h'):
- error(filename, linenum, 'build/include', 4,
- '"%s" already included at %s:%s' %
- (include, filename, include_state[include]))
-
-
def _GetTextInside(text, start_pattern):
r"""Retrieves all the text between matching open and close parentheses.
@@ -2938,7 +2652,7 @@ def _GetTextInside(text, start_pattern):
return text[start_position:position - 1]
-def CheckLanguage(filename, clean_lines, linenum, include_state, error):
+def CheckLanguage(filename, clean_lines, linenum, error):
"""Checks rules from the 'C++ language rules' section of cppguide.html.
Some of these rules are hard to test (function overloading, using
@@ -2948,8 +2662,6 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
filename : The name of the current file.
clean_lines : A CleansedLines instance containing the file.
linenum : The number of the line to check.
- include_state : An _IncludeState instance in which the headers are
- inserted.
error : The function to call with any errors found.
"""
# If the line is empty or consists of entirely a comment, no need to
@@ -2958,16 +2670,6 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
if not line:
return
- match = _RE_PATTERN_INCLUDE.search(line)
- if match:
- CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
- return
-
- # Reset include state across preprocessor directives. This is meant
- # to silence warnings for conditional includes.
- if Match(r'^\s*#\s*(?:ifdef|elif|else|endif)\b', line):
- include_state.ResetSection()
-
# TODO(unknown): figure out if they're using default arguments in fn proto.
# Check if people are using the verboten C basic types.
@@ -3125,7 +2827,7 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
def ProcessLine(filename, clean_lines, line,
- include_state, function_state, nesting_state, error,
+ function_state, nesting_state, error,
extra_check_functions=[]):
"""Processes a single line in the file.
@@ -3134,8 +2836,6 @@ def ProcessLine(filename, clean_lines, line,
clean_lines : An array of strings, each representing a line of
the file, with comments stripped.
line : Number of line being processed.
- include_state : An _IncludeState instance in which the headers are
- inserted.
function_state : A _FunctionState instance which counts function
lines, etc.
nesting_state : A _NestingState instance which maintains
@@ -3158,7 +2858,7 @@ def ProcessLine(filename, clean_lines, line,
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
CheckForOldStyleComments(filename, init_lines[line], line, error)
CheckStyle(filename, clean_lines, line, error)
- CheckLanguage(filename, clean_lines, line, include_state, error)
+ CheckLanguage(filename, clean_lines, line, error)
CheckForNonStandardConstructs(filename, clean_lines, line, error)
CheckPosixThreading(filename, clean_lines, line, error)
CheckMemoryFunctions(filename, clean_lines, line, error)
@@ -3185,7 +2885,6 @@ def ProcessFileData(filename, file_extension, lines, error,
lines = (['// marker so line numbers and indices both start at 1'] + lines +
['// marker so line numbers end in a known way'])
- include_state = _IncludeState()
function_state = _FunctionState()
nesting_state = _NestingState()
@@ -3216,15 +2915,13 @@ def ProcessFileData(filename, file_extension, lines, error,
clean_lines = CleansedLines(lines, init_lines)
for line in range(clean_lines.NumLines()):
ProcessLine(filename, clean_lines, line,
- include_state, function_state, nesting_state, error,
+ function_state, nesting_state, error,
extra_check_functions)
# We check here rather than inside ProcessLine so that we see raw
# lines rather than "cleaned" lines.
CheckForBadCharacters(filename, lines, error)
- CheckForNewlineAtEOF(filename, lines, error)
-
def ProcessFile(filename, vlevel, extra_check_functions=[]):
"""Does neovim-lint on a single file.
diff --git a/src/coverity-model.c b/src/coverity-model.c
index 2fd55c332c..4338b75ea2 100644
--- a/src/coverity-model.c
+++ b/src/coverity-model.c
@@ -42,3 +42,72 @@ int tv_dict_add(dict_T *const d, dictitem_T *const item)
{
__coverity_escape__(item);
}
+
+void *malloc(size_t size)
+{
+ int has_mem;
+ if (has_mem)
+ return __coverity_alloc__(size);
+ else
+ return 0;
+}
+
+void *try_malloc(size_t size)
+{
+ size_t allocated_size = size ? size : 1;
+ return malloc(allocated_size);
+}
+
+void *xmalloc(size_t size)
+{
+ void *p = malloc(size);
+ if (!p)
+ __coverity_panic__();
+ return p;
+}
+
+void xfree(void * ptr)
+{
+ __coverity_free__(ptr);
+}
+
+void *xcalloc(size_t count, size_t size)
+{
+ size_t allocated_count = count && size ? count : 1;
+ size_t allocated_size = count && size ? size : 1;
+ void *p = try_malloc(allocated_count * allocated_size);
+ if (!p)
+ __coverity_panic__();
+ __coverity_writeall0__(p);
+ return p;
+}
+
+void *xrealloc(void *ptr, size_t size)
+{
+ __coverity_escape__(ptr);
+ void * p = xmalloc(size);
+ __coverity_writeall__(p);
+ return p;
+}
+
+void *xmallocz(size_t size)
+{
+ void * p = malloc(size + 1);
+ ((char*)p)[size] = 0;
+ return p;
+}
+
+void * xmemdupz(const void * data, size_t len)
+{
+ void * p = xmallocz(len);
+ __coverity_writeall__(p);
+ ((char*)p)[len] = 0;
+ return p;
+}
+
+void * xmemdup(const void *data, size_t len)
+{
+ void * p = xmalloc(len);
+ __coverity_writeall__(p);
+ return p;
+}
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 76e531e7aa..4ee834d75a 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -283,7 +283,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
PUT(autocmd_info,
"command",
- STRING_OBJ(cstr_to_string(aucmd_exec_to_string(ac, ac->exec))));
+ STRING_OBJ(cstr_as_string(aucmd_exec_to_string(ac, ac->exec))));
PUT(autocmd_info,
"pattern",
@@ -405,6 +405,7 @@ cleanup:
/// - match: (string) the expanded value of |<amatch>|
/// - buf: (number) the expanded value of |<abuf>|
/// - file: (string) the expanded value of |<afile>|
+/// - data: (any) arbitrary data passed to |nvim_exec_autocmds()|
/// - command (string) optional: Vim command to execute on event. Cannot be used with
/// {callback}
/// - once (boolean) optional: defaults to false. Run the autocommand
@@ -749,6 +750,8 @@ void nvim_del_augroup_by_name(String name, Error *err)
/// {pattern}.
/// - modeline (bool) optional: defaults to true. Process the
/// modeline after the autocommands |<nomodeline>|.
+/// - data (any): arbitrary data to send to the autocommand callback. See
+/// |nvim_create_autocmd()| for details.
/// @see |:doautocmd|
void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
FUNC_API_SINCE(9)
@@ -760,6 +763,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
bool set_buf = false;
char *pattern = NULL;
+ Object *data = NULL;
bool set_pattern = false;
Array event_array = ARRAY_DICT_INIT;
@@ -818,6 +822,10 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
set_pattern = true;
}
+ if (opts->data.type != kObjectTypeNil) {
+ data = &opts->data;
+ }
+
modeline = api_object_to_bool(opts->modeline, "modeline", true, err);
if (set_pattern && set_buf) {
@@ -829,7 +837,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
FOREACH_ITEM(event_array, event_str, {
GET_ONE_EVENT(event_nr, event_str, cleanup)
- did_aucmd |= apply_autocmds_group(event_nr, pattern, NULL, true, au_group, buf, NULL);
+ did_aucmd |= apply_autocmds_group(event_nr, pattern, NULL, true, au_group, buf, NULL, data);
})
if (did_aucmd && modeline) {
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index e05d80812d..94b2af9a6f 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -95,27 +95,27 @@ static bool ns_initialized(uint32_t ns)
}
-static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
+static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict)
{
Array rv = ARRAY_DICT_INIT;
if (id) {
- ADD(rv, INTEGER_OBJ((Integer)extmark.mark_id));
+ ADD(rv, INTEGER_OBJ((Integer)extmark->mark_id));
}
- ADD(rv, INTEGER_OBJ(extmark.row));
- ADD(rv, INTEGER_OBJ(extmark.col));
+ ADD(rv, INTEGER_OBJ(extmark->row));
+ ADD(rv, INTEGER_OBJ(extmark->col));
if (add_dict) {
Dictionary dict = ARRAY_DICT_INIT;
- PUT(dict, "right_gravity", BOOLEAN_OBJ(extmark.right_gravity));
+ PUT(dict, "right_gravity", BOOLEAN_OBJ(extmark->right_gravity));
- if (extmark.end_row >= 0) {
- PUT(dict, "end_row", INTEGER_OBJ(extmark.end_row));
- PUT(dict, "end_col", INTEGER_OBJ(extmark.end_col));
- PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark.end_right_gravity));
+ if (extmark->end_row >= 0) {
+ PUT(dict, "end_row", INTEGER_OBJ(extmark->end_row));
+ PUT(dict, "end_col", INTEGER_OBJ(extmark->end_col));
+ PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark->end_right_gravity));
}
- Decoration *decor = &extmark.decor;
+ const Decoration *decor = &extmark->decor;
if (decor->hl_id) {
String name = cstr_to_string((const char *)syn_id2name(decor->hl_id));
PUT(dict, "hl_group", STRING_OBJ(name));
@@ -238,7 +238,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
if (extmark.row < 0) {
return rv;
}
- return extmark_to_array(extmark, false, details);
+ return extmark_to_array(&extmark, false, details);
}
/// Gets extmarks in "traversal order" from a |charwise| region defined by
@@ -357,7 +357,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
u_row, u_col, (int64_t)limit, reverse);
for (size_t i = 0; i < kv_size(marks); i++) {
- ADD(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, (bool)details)));
+ ADD(rv, ARRAY_OBJ(extmark_to_array(&kv_A(marks, i), true, (bool)details)));
}
kv_destroy(marks);
@@ -366,12 +366,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// Creates or updates an extmark.
///
-/// To create a new extmark, pass id=0. The extmark id will be returned.
-/// To move an existing mark, pass its id.
-///
-/// It is also allowed to create a new mark by passing in a previously unused
-/// id, but the caller must then keep track of existing and unused ids itself.
-/// (Useful over RPC, to avoid waiting for the return value.)
+/// By default a new extmark is created when no id is passed in, but it is also
+/// possible to create a new mark by passing in a previously unused id or move
+/// an existing mark by passing in its id. The caller must then keep track of
+/// existing and unused ids itself. (Useful over RPC, to avoid waiting for the
+/// return value.)
///
/// Using the optional arguments, it is possible to use this to highlight
/// a range of text, and also to associate virtual text to the mark.
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 78f8ed3cca..6924e2ef8f 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -80,6 +80,7 @@ return {
"maxwidth";
"fillchar";
"highlights";
+ "use_winbar";
"use_tabline";
};
option = {
@@ -145,6 +146,7 @@ return {
"group";
"modeline";
"pattern";
+ "data";
};
get_autocmds = {
"event";
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index dcede27bcb..adabb1471e 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1418,14 +1418,14 @@ bool set_mark(buf_T *buf, String name, Integer line, Integer col, Error *err)
}
/// Get default statusline highlight for window
-const char *get_default_stl_hl(win_T *wp)
+const char *get_default_stl_hl(win_T *wp, bool use_winbar)
{
if (wp == NULL) {
return "TabLineFill";
- } else if (wp == curwin) {
- return "StatusLine";
+ } else if (use_winbar) {
+ return (wp == curwin) ? "WinBar" : "WinBarNC";
} else {
- return "StatusLineNC";
+ return (wp == curwin) ? "StatusLine" : "StatusLineNC";
}
}
@@ -1616,7 +1616,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts,
if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref,
addr_type_arg, luaref, force) != OK) {
api_set_error(err, kErrorTypeException, "Failed to create user command");
- goto err;
+ // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg
}
return;
@@ -1624,6 +1624,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts,
err:
NLUA_CLEAR_REF(luaref);
NLUA_CLEAR_REF(compl_luaref);
+ xfree(compl_arg);
}
int find_sid(uint64_t channel_id)
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index b4d20ed975..52f76f4650 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -349,7 +349,11 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, I
return;
}
- ui_grid_resize((handle_T)grid, (int)width, (int)height, err);
+ if (grid == DEFAULT_GRID_HANDLE) {
+ nvim_ui_try_resize(channel_id, width, height, err);
+ } else {
+ ui_grid_resize((handle_T)grid, (int)width, (int)height, err);
+ }
}
/// Tells Nvim the number of elements displaying in the popumenu, to decide
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 63aaaae38a..0030f9edf7 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -174,4 +174,6 @@ void msg_ruler(Array content)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void msg_history_show(Array entries)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
+void msg_history_clear(void)
+ FUNC_API_SINCE(10) FUNC_API_REMOTE_ONLY;
#endif // NVIM_API_UI_EVENTS_IN_H
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index a257dd6478..15992a98be 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -2140,8 +2140,8 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
}
}
- if (row < 0 || row >= g->Rows
- || col < 0 || col >= g->Columns) {
+ if (row < 0 || row >= g->rows
+ || col < 0 || col >= g->cols) {
return ret;
}
size_t off = g->line_offset[(size_t)row] + (size_t)col;
@@ -2274,8 +2274,9 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err)
/// - fillchar: (string) Character to fill blank spaces in the statusline (see
/// 'fillchars'). Treated as single-width even if it isn't.
/// - highlights: (boolean) Return highlight information.
+/// - use_winbar: (boolean) Evaluate winbar instead of statusline.
/// - use_tabline: (boolean) Evaluate tabline instead of statusline. When |TRUE|, {winid}
-/// is ignored.
+/// is ignored. Mutually exclusive with {use_winbar}.
///
/// @param[out] err Error details, if any.
/// @return Dictionary containing statusline information, with these keys:
@@ -2294,6 +2295,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
int maxwidth;
int fillchar = 0;
Window window = 0;
+ bool use_winbar = false;
bool use_tabline = false;
bool highlights = false;
@@ -2313,7 +2315,6 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
window = (Window)opts->winid.data.integer;
}
-
if (HAS_KEY(opts->fillchar)) {
if (opts->fillchar.type != kObjectTypeString || opts->fillchar.data.string.size == 0
|| ((size_t)utf_ptr2len(opts->fillchar.data.string.data)
@@ -2323,7 +2324,6 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
}
fillchar = utf_ptr2char(opts->fillchar.data.string.data);
}
-
if (HAS_KEY(opts->highlights)) {
highlights = api_object_to_bool(opts->highlights, "highlights", false, err);
@@ -2331,7 +2331,13 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
return result;
}
}
+ if (HAS_KEY(opts->use_winbar)) {
+ use_winbar = api_object_to_bool(opts->use_winbar, "use_winbar", false, err);
+ if (ERROR_SET(err)) {
+ return result;
+ }
+ }
if (HAS_KEY(opts->use_tabline)) {
use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err);
@@ -2339,6 +2345,10 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
return result;
}
}
+ if (use_winbar && use_tabline) {
+ api_set_error(err, kErrorTypeValidation, "use_winbar and use_tabline are mutually exclusive");
+ return result;
+ }
win_T *wp, *ewp;
@@ -2348,7 +2358,6 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
fillchar = ' ';
} else {
wp = find_window_by_handle(window, err);
-
if (wp == NULL) {
api_set_error(err, kErrorTypeException, "unknown winid %d", window);
return result;
@@ -2356,8 +2365,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
ewp = wp;
if (fillchar == 0) {
- int attr;
- fillchar = fillchar_status(&attr, wp);
+ if (use_winbar) {
+ fillchar = wp->w_p_fcs_chars.wbr;
+ } else {
+ int attr;
+ fillchar = fillchar_status(&attr, wp);
+ }
}
}
@@ -2369,7 +2382,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
maxwidth = (int)opts->maxwidth.data.integer;
} else {
- maxwidth = (use_tabline || global_stl_height() > 0) ? Columns : wp->w_width;
+ maxwidth = (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width;
}
char buf[MAXPATHL];
@@ -2404,7 +2417,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
// add the default highlight at the beginning of the highlight list
if (hltab->start == NULL || ((char *)hltab->start - buf) != 0) {
Dictionary hl_info = ARRAY_DICT_INIT;
- grpname = get_default_stl_hl(wp);
+ grpname = get_default_stl_hl(wp, use_winbar);
PUT(hl_info, "start", INTEGER_OBJ(0));
PUT(hl_info, "group", CSTR_TO_OBJ(grpname));
@@ -2418,22 +2431,18 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
PUT(hl_info, "start", INTEGER_OBJ((char *)sp->start - buf));
if (sp->userhl == 0) {
- grpname = get_default_stl_hl(wp);
+ grpname = get_default_stl_hl(wp, use_winbar);
} else if (sp->userhl < 0) {
grpname = (char *)syn_id2name(-sp->userhl);
} else {
snprintf(user_group, sizeof(user_group), "User%d", sp->userhl);
grpname = user_group;
}
-
PUT(hl_info, "group", CSTR_TO_OBJ(grpname));
-
ADD(hl_values, DICTIONARY_OBJ(hl_info));
}
-
PUT(result, "highlights", ARRAY_OBJ(hl_values));
}
-
PUT(result, "str", CSTR_TO_OBJ((char *)buf));
return result;
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index b8f7b33cd5..e71f1a11ec 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -1304,20 +1304,23 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
capture_ga = &capture_local;
}
- try_start();
- if (output) {
- msg_silent++;
- }
+ TRY_WRAP({
+ try_start();
+ if (output) {
+ msg_silent++;
+ }
- WITH_SCRIPT_CONTEXT(channel_id, {
- execute_cmd(&ea, &cmdinfo);
- });
+ WITH_SCRIPT_CONTEXT(channel_id, {
+ execute_cmd(&ea, &cmdinfo);
+ });
- if (output) {
- capture_ga = save_capture_ga;
- msg_silent = save_msg_silent;
- }
- try_end(err);
+ if (output) {
+ capture_ga = save_capture_ga;
+ msg_silent = save_msg_silent;
+ }
+
+ try_end(err);
+ });
if (ERROR_SET(err)) {
goto clear_ga;
diff --git a/src/nvim/assert.h b/src/nvim/assert.h
index bc5260b914..ad92d9a2af 100644
--- a/src/nvim/assert.h
+++ b/src/nvim/assert.h
@@ -108,8 +108,6 @@
# define STATIC_ASSERT_STATEMENT STATIC_ASSERT_EXPR
#endif
-// uncrustify:off
-
#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
// These can't be used after statements in c89.
@@ -125,8 +123,6 @@
((enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)), }) 0)
#endif
-// uncrustify:on
-
/// @def STRICT_ADD
/// @brief Adds (a + b) and stores result in `c`. Aborts on overflow.
///
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 9e3eb06752..93a870fe04 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -70,6 +70,8 @@ return {
'InsertEnter', -- when entering Insert mode
'InsertLeave', -- just after leaving Insert mode
'InsertLeavePre', -- just before leaving Insert mode
+ 'LspAttach', -- after an LSP client attaches to a buffer
+ 'LspDetach', -- after an LSP client detaches from a buffer
'MenuPopup', -- just before popup menu is displayed
'ModeChanged', -- after changing the mode
'OptionSet', -- after setting any option
@@ -133,6 +135,8 @@ return {
nvim_specific = {
BufModifiedSet=true,
DiagnosticChanged=true,
+ LspAttach=true,
+ LspDetach=true,
RecordingEnter=true,
RecordingLeave=true,
Signal=true,
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 6c7950fdd1..bc9e548b77 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -190,7 +190,18 @@ static void aupat_show(AutoPat *ap, event_T event, int previous_group)
if (got_int) {
return;
}
- msg_outtrans((char_u *)aucmd_exec_to_string(ac, ac->exec));
+
+ char *exec_to_string = aucmd_exec_to_string(ac, ac->exec);
+ if (ac->desc != NULL) {
+ size_t msglen = 100;
+ char *msg = (char *)xmallocz(msglen);
+ snprintf(msg, msglen, "%s [%s]", exec_to_string, ac->desc);
+ msg_outtrans((char_u *)msg);
+ XFREE_CLEAR(msg);
+ } else {
+ msg_outtrans((char_u *)exec_to_string);
+ }
+ XFREE_CLEAR(exec_to_string);
if (p_verbose > 0) {
last_set_msg(ac->script_ctx);
}
@@ -1136,8 +1147,6 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group
// perhaps: <lua>DESCRIPTION or similar
if (desc != NULL) {
ac->desc = xstrdup(desc);
- } else {
- ac->desc = aucmd_exec_default_desc(aucmd);
}
return OK;
@@ -1220,7 +1229,7 @@ int do_doautocmd(char *arg_start, bool do_msg, bool *did_something)
// Loop over the events.
while (*arg && !ends_excmd(*arg) && !ascii_iswhite(*arg)) {
if (apply_autocmds_group(event_name2nr(arg, &arg), fname, NULL, true, group,
- curbuf, NULL)) {
+ curbuf, NULL, NULL)) {
nothing_done = false;
}
}
@@ -1505,7 +1514,7 @@ win_found:
/// @return true if some commands were executed.
bool apply_autocmds(event_T event, char *fname, char *fname_io, bool force, buf_T *buf)
{
- return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, NULL);
+ return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, NULL, NULL);
}
/// Like apply_autocmds(), but with extra "eap" argument. This takes care of
@@ -1522,7 +1531,7 @@ bool apply_autocmds(event_T event, char *fname, char *fname_io, bool force, buf_
bool apply_autocmds_exarg(event_T event, char *fname, char *fname_io, bool force, buf_T *buf,
exarg_T *eap)
{
- return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, eap);
+ return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, eap, NULL);
}
/// Like apply_autocmds(), but handles the caller's retval. If the script
@@ -1546,7 +1555,7 @@ bool apply_autocmds_retval(event_T event, char *fname, char *fname_io, bool forc
}
bool did_cmd = apply_autocmds_group(event, fname, fname_io, force,
- AUGROUP_ALL, buf, NULL);
+ AUGROUP_ALL, buf, NULL, NULL);
if (did_cmd && aborting()) {
*retval = FAIL;
}
@@ -1595,7 +1604,7 @@ bool trigger_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
///
/// @return true if some commands were executed.
bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force, int group,
- buf_T *buf, exarg_T *eap)
+ buf_T *buf, exarg_T *eap, Object *data)
{
char *sfname = NULL; // short file name
bool retval = false;
@@ -1811,6 +1820,9 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
patcmd.next = active_apc_list;
active_apc_list = &patcmd;
+ // Attach data to command
+ patcmd.data = data;
+
// set v:cmdarg (only when there is a matching pattern)
save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
if (eap != NULL) {
@@ -2026,6 +2038,10 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc)
PUT(data, "file", CSTR_TO_OBJ((char *)autocmd_fname));
PUT(data, "buf", INTEGER_OBJ(autocmd_bufnr));
+ if (apc->data) {
+ PUT(data, "data", copy_object(*apc->data));
+ }
+
int group = apc->curpat->group;
switch (group) {
case AUGROUP_ERROR:
@@ -2111,8 +2127,10 @@ char *getnextac(int c, void *cookie, int indent, bool do_concat)
if (p_verbose >= 9) {
verbose_enter_scroll();
- smsg(_("autocommand %s"), aucmd_exec_to_string(ac, ac->exec));
+ char *exec_to_string = aucmd_exec_to_string(ac, ac->exec);
+ smsg(_("autocommand %s"), exec_to_string);
msg_puts("\n"); // don't overwrite this either
+ XFREE_CLEAR(exec_to_string);
verbose_leave_scroll();
}
@@ -2463,45 +2481,42 @@ bool autocmd_delete_id(int64_t id)
// ===========================================================================
// AucmdExecutable Functions
// ===========================================================================
-char *aucmd_exec_default_desc(AucmdExecutable acc)
+
+/// Generate a string description of a callback
+static char *aucmd_callback_to_string(Callback cb)
{
+ // NOTE: this function probably belongs in a helper
+
size_t msglen = 100;
+ char *msg = (char *)xmallocz(msglen);
- switch (acc.type) {
- case CALLABLE_CB:
- switch (acc.callable.cb.type) {
- case kCallbackLua: {
- char *msg = (char *)xmallocz(msglen);
- snprintf(msg, msglen, "<Lua function %d>", acc.callable.cb.data.luaref);
- return msg;
- }
- case kCallbackFuncref: {
- // TODO(tjdevries): Is this enough space for this?
- char *msg = (char *)xmallocz(msglen);
- snprintf(msg, msglen, "<vim function: %s>", acc.callable.cb.data.funcref);
- return msg;
- }
- case kCallbackPartial: {
- char *msg = (char *)xmallocz(msglen);
- snprintf(msg, msglen, "<vim partial: %s>", acc.callable.cb.data.partial->pt_name);
- return msg;
- }
- default:
- return NULL;
- }
+ switch (cb.type) {
+ case kCallbackLua:
+ snprintf(msg, msglen, "<lua: %d>", cb.data.luaref);
+ break;
+ case kCallbackFuncref:
+ // TODO(tjdevries): Is this enough space for this?
+ snprintf(msg, msglen, "<vim function: %s>", cb.data.funcref);
+ break;
+ case kCallbackPartial:
+ snprintf(msg, msglen, "<vim partial: %s>", cb.data.partial->pt_name);
+ break;
default:
- return NULL;
+ snprintf(msg, msglen, "%s", "");
+ break;
}
+ return msg;
}
+/// Generate a string description for the command/callback of an autocmd
char *aucmd_exec_to_string(AutoCmd *ac, AucmdExecutable acc)
FUNC_ATTR_PURE
{
switch (acc.type) {
case CALLABLE_EX:
- return acc.callable.cmd;
+ return xstrdup(acc.callable.cmd);
case CALLABLE_CB:
- return ac->desc;
+ return aucmd_callback_to_string(acc.callable.cb);
case CALLABLE_NONE:
return "This is not possible";
}
diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h
index d3503672fd..47f583ae13 100644
--- a/src/nvim/autocmd.h
+++ b/src/nvim/autocmd.h
@@ -57,6 +57,7 @@ typedef struct AutoPatCmd {
char *tail; // tail of fname
event_T event; // current event
int arg_bufnr; // initially equal to <abuf>, set to zero when buf is deleted
+ Object *data; // arbitrary data
struct AutoPatCmd *next; // chain of active apc-s for auto-invalidation
} AutoPatCmd;
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 2adeeadbca..b5980612f8 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -6,6 +6,8 @@
// for FILE
#include <stdio.h>
+#include "grid_defs.h"
+
typedef struct file_buffer buf_T; // Forward declaration
// Reference to a buffer that stores the value of buf_free_count.
@@ -233,6 +235,8 @@ typedef struct {
#define w_p_sbr w_onebuf_opt.wo_sbr // 'showbreak'
char_u *wo_stl;
#define w_p_stl w_onebuf_opt.wo_stl // 'statusline'
+ char *wo_wbr;
+#define w_p_wbr w_onebuf_opt.wo_wbr // 'winbar'
int wo_scb;
#define w_p_scb w_onebuf_opt.wo_scb // 'scrollbind'
int wo_diff_saved; // options were saved for starting diff mode
@@ -1235,6 +1239,7 @@ struct window_S {
struct {
int stl;
int stlnc;
+ int wbr;
int horiz;
int horizup;
int horizdown;
@@ -1282,14 +1287,20 @@ struct window_S {
//
int w_winrow; // first row of window in screen
int w_height; // number of rows in window, excluding
- // status/command/winbar line(s)
+ // status/command line(s)
int w_status_height; // number of status lines (0 or 1)
+ int w_winbar_height; // number of window bars (0 or 1)
int w_wincol; // Leftmost column of window in screen.
int w_width; // Width of window, excluding separation.
int w_hsep_height; // Number of horizontal separator rows (0 or 1)
int w_vsep_width; // Number of vertical separator columns (0 or 1).
pos_save_T w_save_cursor; // backup of cursor pos and topline
+ int w_winrow_off; ///< offset from winrow to the inner window area
+ int w_wincol_off; ///< offset from wincol to the inner window area
+ ///< this includes float border but excludes special columns
+ ///< implemented in win_line() (i.e. signs, folds, numbers)
+
// inner size of window, which can be overridden by external UI
int w_height_inner;
int w_width_inner;
@@ -1378,7 +1389,7 @@ struct window_S {
// w_redr_type is REDRAW_TOP
linenr_T w_redraw_top; // when != 0: first line needing redraw
linenr_T w_redraw_bot; // when != 0: last line needing redraw
- bool w_redr_status; // if true status line must be redrawn
+ bool w_redr_status; // if true statusline/winbar must be redrawn
bool w_redr_border; // if true border must be redrawn
// remember what is shown in the ruler for this window (if 'ruler' set)
@@ -1408,6 +1419,7 @@ struct window_S {
// A few options have local flags for P_INSECURE.
uint32_t w_p_stl_flags; // flags for 'statusline'
+ uint32_t w_p_wbr_flags; // flags for 'winbar'
uint32_t w_p_fde_flags; // flags for 'foldexpr'
uint32_t w_p_fdt_flags; // flags for 'foldtext'
int *w_p_cc_cols; // array of columns to highlight or NULL
@@ -1481,6 +1493,16 @@ struct window_S {
// Location list reference used in the location list window.
// In a non-location list window, w_llist_ref is NULL.
qf_info_T *w_llist_ref;
+
+ // Status line click definitions
+ StlClickDefinition *w_status_click_defs;
+ // Size of the w_status_click_defs array
+ size_t w_status_click_defs_size;
+
+ // Window bar click definitions
+ StlClickDefinition *w_winbar_click_defs;
+ // Size of the w_winbar_click_defs array
+ size_t w_winbar_click_defs_size;
};
static inline int win_hl_attr(win_T *wp, int hlf)
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 94e5a19edc..c1fe5bc405 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -1033,8 +1033,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// If 'autoindent' and/or 'smartindent' is set, try to figure out what
// indent to use for the new line.
- if (curbuf->b_p_ai
- || do_si) {
+ if (curbuf->b_p_ai || do_si) {
// count white space on current line
newindent = get_indent_str_vtab(saved_line,
curbuf->b_p_ts,
@@ -1189,7 +1188,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
if (flags & OPENLINE_DO_COM) {
lead_len = get_leader_len(saved_line, &lead_flags, dir == BACKWARD, true);
if (lead_len == 0 && curbuf->b_p_cin && do_cindent && dir == FORWARD
- && !has_format_option(FO_NO_OPEN_COMS)) {
+ && (!has_format_option(FO_NO_OPEN_COMS) || (flags & OPENLINE_FORMAT))) {
// Check for a line comment after code.
comment_start = check_linecomment(saved_line);
if (comment_start != MAXCOL) {
@@ -1482,8 +1481,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
// Recompute the indent, it may have changed.
- if (curbuf->b_p_ai
- || do_si) {
+ if (curbuf->b_p_ai || do_si) {
newindent = get_indent_str_vtab(leader,
curbuf->b_p_ts,
curbuf->b_p_vts_array, false);
@@ -1526,15 +1524,13 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// if a new indent will be set below, remove the indent that
// is in the comment leader
- if (newindent
- || did_si) {
+ if (newindent || did_si) {
while (lead_len && ascii_iswhite(*leader)) {
lead_len--;
newcol--;
leader++;
}
}
-
did_si = can_si = false;
} else if (comment_end != NULL) {
// We have finished a comment, so we don't use the leader.
@@ -1646,8 +1642,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
inhibit_delete_count++;
- if (newindent
- || did_si) {
+ if (newindent || did_si) {
curwin->w_cursor.lnum++;
if (did_si) {
int sw = get_sw_value(curbuf);
@@ -1764,6 +1759,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
} else {
vreplace_mode = 0;
}
+
// May do lisp indenting.
if (!p_paste
&& leader == NULL
@@ -1772,11 +1768,13 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
fixthisline(get_lisp_indent);
ai_col = (colnr_T)getwhitecols_curline();
}
+
// May do indenting after opening a new line.
if (do_cindent) {
do_c_expr_indent();
ai_col = (colnr_T)getwhitecols_curline();
}
+
if (vreplace_mode != 0) {
State = vreplace_mode;
}
diff --git a/src/nvim/change.h b/src/nvim/change.h
index e7c8a2b031..fdfa8a29ec 100644
--- a/src/nvim/change.h
+++ b/src/nvim/change.h
@@ -5,11 +5,12 @@
#include "nvim/pos.h" // for linenr_T
// flags for open_line()
-#define OPENLINE_DELSPACES 1 // delete spaces after cursor
-#define OPENLINE_DO_COM 2 // format comments
-#define OPENLINE_KEEPTRAIL 4 // keep trailing spaces
-#define OPENLINE_MARKFIX 8 // fix mark positions
-#define OPENLINE_COM_LIST 16 // format comments with list/2nd line indent
+#define OPENLINE_DELSPACES 0x01 // delete spaces after cursor
+#define OPENLINE_DO_COM 0x02 // format comments
+#define OPENLINE_KEEPTRAIL 0x04 // keep trailing spaces
+#define OPENLINE_MARKFIX 0x08 // fix mark positions
+#define OPENLINE_COM_LIST 0x10 // format comments with list/2nd line indent
+#define OPENLINE_FORMAT 0x20 // formatting long comment
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "change.h.generated.h"
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index aa77c03b48..568a8573db 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -459,9 +459,8 @@ static void insert_enter(InsertState *s)
where_paste_started.lnum = 0;
can_cindent = true;
- // The cursor line is not in a closed fold, unless 'insertmode' is set or
- // restarting.
- if (!p_im && did_restart_edit == 0) {
+ // The cursor line is not in a closed fold, unless restarting.
+ if (did_restart_edit == 0) {
foldOpenCursor();
}
@@ -473,7 +472,7 @@ static void insert_enter(InsertState *s)
s->i = showmode();
}
- if (!p_im && did_restart_edit == 0) {
+ if (did_restart_edit == 0) {
change_warning(curbuf, s->i == 0 ? 0 : s->i + 1);
}
@@ -554,7 +553,7 @@ static int insert_check(VimState *state)
}
if (stop_insert_mode && !compl_started) {
- // ":stopinsert" used or 'insertmode' reset
+ // ":stopinsert" used
s->count = 0;
return 0; // exit insert mode
}
@@ -756,7 +755,6 @@ static int insert_execute(VimState *state, int key)
}
// CTRL-\ CTRL-N goes to Normal mode,
- // CTRL-\ CTRL-G goes to mode selected with 'insertmode',
// CTRL-\ CTRL-O is like CTRL-O but without moving the cursor
if (s->c == Ctrl_BSL) {
// may need to redraw when no more chars available now
@@ -770,8 +768,6 @@ static int insert_execute(VimState *state, int key)
// it's something else
vungetc(s->c);
s->c = Ctrl_BSL;
- } else if (s->c == Ctrl_G && p_im) {
- return 1; // continue
} else {
if (s->c == Ctrl_O) {
ins_ctrl_o();
@@ -843,16 +839,6 @@ static int insert_execute(VimState *state, int key)
}
-/// Return true when need to go to Insert mode because of 'insertmode'.
-///
-/// Don't do this when still processing a command or a mapping.
-/// Don't do this when inside a ":normal" command.
-bool goto_im(void)
- FUNC_ATTR_PURE
-{
- return p_im && stuff_empty() && typebuf_typed();
-}
-
static int insert_handle_key(InsertState *s)
{
// The big switch to handle a character in insert mode.
@@ -884,26 +870,10 @@ static int insert_handle_key(InsertState *s)
}
}
- // when 'insertmode' set, and not halfway through a mapping, don't leave
- // Insert mode
- if (goto_im()) {
- if (got_int) {
- (void)vgetc(); // flush all buffers
- got_int = false;
- } else {
- vim_beep(BO_IM);
- }
- break;
- }
return 0; // exit insert mode
- case Ctrl_Z: // suspend when 'insertmode' set
- if (!p_im) {
- goto normalchar; // insert CTRL-Z as normal char
- }
- do_cmdline_cmd("stop");
- ui_cursor_shape(); // may need to update cursor shape
- break;
+ case Ctrl_Z:
+ goto normalchar; // insert CTRL-Z as normal char
case Ctrl_O: // execute one command
if (ctrl_x_mode == CTRL_X_OMNI) {
@@ -939,9 +909,6 @@ static int insert_handle_key(InsertState *s)
case K_F1:
case K_XF1:
stuffcharReadbuff(K_HELP);
- if (p_im) {
- need_start_insertmode = true;
- }
return 0; // exit insert mode
@@ -956,7 +923,7 @@ static int insert_handle_key(InsertState *s)
// For ^@ the trailing ESC will end the insert, unless there is an
// error.
if (stuff_inserted(NUL, 1L, (s->c == Ctrl_A)) == FAIL
- && s->c != Ctrl_A && !p_im) {
+ && s->c != Ctrl_A) {
return 0; // exit insert mode
}
s->inserted_space = false;
@@ -1236,7 +1203,7 @@ check_pum:
}
break;
}
- if (!ins_eol(s->c) && !p_im) {
+ if (!ins_eol(s->c)) {
return 0; // out of memory
}
auto_format(false, false);
@@ -1288,13 +1255,6 @@ check_pum:
case Ctrl_L: // Whole line completion after ^X
if (ctrl_x_mode != CTRL_X_WHOLE_LINE) {
- // CTRL-L with 'insertmode' set: Leave Insert mode
- if (p_im) {
- if (echeck_abbr(Ctrl_L + ABBR_OFF)) {
- break;
- }
- return 0; // exit insert mode
- }
goto normalchar;
}
FALLTHROUGH;
@@ -1632,7 +1592,7 @@ void edit_putchar(int c, bool highlight)
pc_col = 0;
pc_status = PC_STATUS_UNSET;
if (curwin->w_p_rl) {
- pc_col += curwin->w_grid.Columns - 1 - curwin->w_wcol;
+ pc_col += curwin->w_grid.cols - 1 - curwin->w_wcol;
const int fix_col = grid_fix_col(&curwin->w_grid, pc_col, pc_row);
if (fix_col != pc_col) {
@@ -1759,7 +1719,7 @@ void display_dollar(colnr_T col)
char_u *p = get_cursor_line_ptr();
curwin->w_cursor.col -= utf_head_off(p, p + col);
curs_columns(curwin, false); // Recompute w_wrow and w_wcol
- if (curwin->w_wcol < curwin->w_grid.Columns) {
+ if (curwin->w_wcol < curwin->w_grid.cols) {
edit_putchar('$', false);
dollar_vcol = curwin->w_virtcol;
}
@@ -3799,6 +3759,7 @@ static bool ins_compl_prep(int c)
}
bool want_cindent = (can_cindent && cindent_on());
+
// When completing whole lines: fix indent for 'cindent'.
// Otherwise, break line if it's too long.
if (compl_cont_mode == CTRL_X_WHOLE_LINE) {
@@ -6285,6 +6246,7 @@ static void internal_format(int textwidth, int second_indent, int flags, int for
open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
+ (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
+ (do_comments ? OPENLINE_DO_COM : 0)
+ + OPENLINE_FORMAT
+ ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0),
((flags & INSCHAR_COM_LIST) ? second_indent : old_indent),
&did_do_comment);
@@ -7963,10 +7925,8 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
}
if (!arrow_used) {
// Don't append the ESC for "r<CR>" and "grx".
- // When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
- // when "count" is non-zero.
if (cmdchar != 'r' && cmdchar != 'v') {
- AppendToRedobuff(p_im ? "\014" : ESC_STR);
+ AppendToRedobuff(ESC_STR);
}
/*
@@ -8412,9 +8372,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
mincol = 0;
// keep indent
if (mode == BACKSPACE_LINE
- && (curbuf->b_p_ai
- || cindent_on()
- )
+ && (curbuf->b_p_ai || cindent_on())
&& !revins_on) {
save_col = curwin->w_cursor.col;
beginline(BL_WHITE);
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 9c2069663d..33080c145d 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6405,7 +6405,7 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
tv_dict_add_nr(dict, S_LEN("winrow"), wp->w_winrow + 1);
tv_dict_add_nr(dict, S_LEN("topline"), wp->w_topline);
tv_dict_add_nr(dict, S_LEN("botline"), wp->w_botline - 1);
- tv_dict_add_nr(dict, S_LEN("winbar"), 0);
+ tv_dict_add_nr(dict, S_LEN("winbar"), wp->w_winbar_height);
tv_dict_add_nr(dict, S_LEN("width"), wp->w_width);
tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1);
@@ -6865,8 +6865,8 @@ void screenchar_adjust_grid(ScreenGrid **grid, int *row, int *col)
// have its own buffer, this should just read from it instead.
msg_scroll_flush();
if (msg_grid.chars && msg_grid.comp_index > 0 && *row >= msg_grid.comp_row
- && *row < (msg_grid.Rows + msg_grid.comp_row)
- && *col < msg_grid.Columns) {
+ && *row < (msg_grid.rows + msg_grid.comp_row)
+ && *col < msg_grid.cols) {
*grid = &msg_grid;
*row -= msg_grid.comp_row;
}
@@ -6886,6 +6886,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
buf_T *curbuf_save = NULL;
win_T *curwin_save = NULL;
const bool is_curbuf = buf == curbuf;
+ const bool save_VIsual_active = VIsual_active;
// When using the current buffer ml_mfp will be set if needed. Useful when
// setline() is used on startup. For other buffers the buffer must be
@@ -6896,6 +6897,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
}
if (!is_curbuf) {
+ VIsual_active = false;
curbuf_save = curbuf;
curwin_save = curwin;
curbuf = buf;
@@ -6986,6 +6988,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
if (!is_curbuf) {
curbuf = curbuf_save;
curwin = curwin_save;
+ VIsual_active = save_VIsual_active;
}
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 68c2e37f22..59c290a5b1 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -90,11 +90,13 @@ typedef enum {
# pragma function(floor)
# endif
+// uncrustify:off
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
# include "funcs.generated.h"
PRAGMA_DIAG_POP
PRAGMA_DIAG_POP
+// uncrustify:on
#endif
@@ -1634,6 +1636,7 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
const bool is_curbuf = buf == curbuf;
+ const bool save_VIsual_active = VIsual_active;
const linenr_T first = tv_get_lnum_buf(&argvars[1], buf);
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -1649,6 +1652,7 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (!is_curbuf) {
+ VIsual_active = false;
curbuf_save = curbuf;
curwin_save = curwin;
curbuf = buf;
@@ -1692,6 +1696,7 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (!is_curbuf) {
curbuf = curbuf_save;
curwin = curwin_save;
+ VIsual_active = save_VIsual_active;
}
}
@@ -3611,8 +3616,8 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// necessary for a top border since `row` starts at -1 in that case.
if (row < height + wp->w_border_adj[2]) {
winid = wp->handle;
- winrow = row + 1 + wp->w_border_adj[0]; // Adjust by 1 for top border
- wincol = col + 1 + wp->w_border_adj[3]; // Adjust by 1 for left border
+ winrow = row + 1 + wp->w_winrow_off; // Adjust by 1 for top border
+ wincol = col + 1 + wp->w_wincol_off; // Adjust by 1 for left border
if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width) {
(void)mouse_comp_pos(wp, &row, &col, &lnum);
col = vcol2col(wp, lnum, col);
@@ -8047,8 +8052,8 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+ if (row < 0 || row >= default_grid.rows
+ || col < 0 || col >= default_grid.cols) {
c = -1;
} else {
ScreenGrid *grid = &default_grid;
@@ -8065,8 +8070,8 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int row = tv_get_number_chk(&argvars[0], NULL) - 1;
int col = tv_get_number_chk(&argvars[1], NULL) - 1;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+ if (row < 0 || row >= default_grid.rows
+ || col < 0 || col >= default_grid.cols) {
c = -1;
} else {
ScreenGrid *grid = &default_grid;
@@ -8081,8 +8086,8 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int row = tv_get_number_chk(&argvars[0], NULL) - 1;
int col = tv_get_number_chk(&argvars[1], NULL) - 1;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+ if (row < 0 || row >= default_grid.rows
+ || col < 0 || col >= default_grid.cols) {
tv_list_alloc_ret(rettv, 0);
return;
}
@@ -8148,8 +8153,8 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
int row = tv_get_number_chk(&argvars[0], NULL) - 1;
int col = tv_get_number_chk(&argvars[1], NULL) - 1;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+ if (row < 0 || row >= default_grid.rows
+ || col < 0 || col >= default_grid.cols) {
return;
}
ScreenGrid *grid = &default_grid;
@@ -10790,10 +10795,16 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "/home/foo/…" => "~/…"
size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true);
// Trim slash.
- if (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/') {
+ if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) {
IObuff[len - 1] = '\0';
}
+ if (len == 1 && IObuff[0] == '/') {
+ // Avoid ambiguity in the URI when CWD is root directory.
+ IObuff[1] = '.';
+ IObuff[2] = '\0';
+ }
+
// Terminal URI: "term://$CWD//$PID:$CMD"
snprintf((char *)NameBuff, sizeof(NameBuff), "term://%s//%d:%s",
(char *)IObuff, pid, cmd);
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index e5f48501f7..2059d423d5 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -3598,5 +3598,6 @@ char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
STRCPY(fp->uf_name, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
+ // coverity[leaked_storage]
return fp->uf_name;
}
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index 89fced59c5..d4e20e2f66 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -143,7 +143,7 @@ bool loop_close(Loop *loop, bool wait)
while (true) {
// Run the loop to tickle close-callbacks (which should then free memory).
// Use UV_RUN_NOWAIT to avoid a hang. #11820
- uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT);
+ uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT); // -V547
if ((uv_loop_close(&loop->uv) != UV_EBUSY) || !wait) {
break;
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 8369db7de1..f5fa424514 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -971,7 +971,11 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
*/
last_line = curbuf->b_ml.ml_line_count;
mark_adjust_nofold(line1, line2, last_line - line2, 0L, kExtmarkNOOP);
+
+ disable_fold_update++;
changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines, false);
+ disable_fold_update--;
+
int line_off = 0;
bcount_t byte_off = 0;
if (dest >= line2) {
@@ -1005,7 +1009,9 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
mark_adjust_nofold(last_line - num_lines + 1, last_line,
-(last_line - dest - extra), 0L, kExtmarkNOOP);
+ disable_fold_update++;
changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra, false);
+ disable_fold_update--;
// send update regarding the new lines that were added
buf_updates_send_changes(curbuf, dest + 1, num_lines, 0, true);
@@ -2874,10 +2880,6 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
redraw_curbuf_later(NOT_VALID); // redraw this buffer later
}
- if (p_im && (State & MODE_INSERT) == 0) {
- need_start_insertmode = true;
- }
-
// Change directories when the 'acd' option is set.
do_autochdir();
@@ -4903,9 +4905,8 @@ void ex_help(exarg_T *eap)
}
}
- if (!p_im) {
- restart_edit = 0; // don't want insert mode in help file
- }
+ restart_edit = 0; // don't want insert mode in help file
+
// Restore KeyTyped, setting 'filetype=help' may reset it.
// It is needed for do_tag top open folds under the cursor.
KeyTyped = old_KeyTyped;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index e845073c12..ae6d26227b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -345,7 +345,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
// here. The value of 200 allows nested function calls, ":source", etc.
// Allow 200 or 'maxfuncdepth', whatever is larger.
if (call_depth >= 200 && call_depth >= p_mfd) {
- emsg(_("E169: Command too recursive"));
+ emsg(_(e_command_too_recursive));
// When converting to an exception, we do not include the command name
// since this is not an error of the specific command.
do_errthrow((cstack_T *)NULL, NULL);
@@ -1583,13 +1583,14 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
/// @param cmdinfo Command parse information
void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
{
+ char *errormsg = NULL;
+
#define ERROR(msg) \
do { \
- emsg(msg); \
+ errormsg = msg; \
goto end; \
} while (0)
- char *errormsg = NULL;
cmdmod_T save_cmdmod = cmdmod;
cmdmod = cmdinfo->cmdmod;
@@ -1648,7 +1649,7 @@ void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
// If filename expansion is enabled, expand filenames
if (cmdinfo->magic.file) {
if (expand_filename(eap, (char_u **)eap->cmdlinep, &errormsg) == FAIL) {
- ERROR(errormsg);
+ goto end;
}
}
@@ -1683,14 +1684,13 @@ void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
(eap->argt & EX_BUFUNL) != 0, false, false);
eap->addr_count = 1;
// Shift each argument by 1
- if (eap->args != NULL) {
- for (size_t i = 0; i < eap->argc - 1; i++) {
- eap->args[i] = eap->args[i + 1];
- }
- // Make the last argument point to the NUL terminator at the end of string
- eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1];
- eap->argc -= 1;
+ for (size_t i = 0; i < eap->argc - 1; i++) {
+ eap->args[i] = eap->args[i + 1];
}
+ // Make the last argument point to the NUL terminator at the end of string
+ eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1];
+ eap->argc -= 1;
+
eap->arg = eap->args[0];
}
if (eap->line2 < 0) { // failed
@@ -1707,14 +1707,20 @@ void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
eap->errmsg = NULL;
(cmdnames[eap->cmdidx].cmd_func)(eap);
if (eap->errmsg != NULL) {
- ERROR(_(eap->errmsg));
+ errormsg = _(eap->errmsg);
}
}
+
end:
+ if (errormsg != NULL && *errormsg != NUL) {
+ emsg(errormsg);
+ }
// Undo command modifiers
undo_cmdmod(eap, msg_scroll);
cmdmod = save_cmdmod;
-
+ if (eap->did_sandbox) {
+ sandbox--;
+ }
#undef ERROR
}
@@ -5522,6 +5528,11 @@ char *uc_validate_name(char *name)
return name;
}
+/// Create a new user command {name}, if one doesn't already exist.
+///
+/// This function takes ownership of compl_arg, compl_luaref, and luaref.
+///
+/// @return OK if the command is created, FAIL otherwise.
int uc_add_command(char *name, size_t name_len, char *rep, uint32_t argt, long def, int flags,
int compl, char *compl_arg, LuaRef compl_luaref, cmd_addr_T addr_type,
LuaRef luaref, bool force)
@@ -8831,7 +8842,7 @@ static void ex_redraw(exarg_T *eap)
ui_flush();
}
-/// ":redrawstatus": force redraw of status line(s)
+/// ":redrawstatus": force redraw of status line(s) and window bar(s)
static void ex_redrawstatus(exarg_T *eap)
{
if (State & MODE_CMDPREVIEW) {
@@ -8847,8 +8858,7 @@ static void ex_redrawstatus(exarg_T *eap)
} else {
status_redraw_curbuf();
}
- update_screen(VIsual_active ? INVERTED :
- 0);
+ update_screen(VIsual_active ? INVERTED : 0);
RedrawingDisabled = r;
p_lz = p;
ui_flush();
@@ -8969,7 +8979,6 @@ bool save_current_state(save_state_T *sst)
sst->save_restart_edit = restart_edit;
sst->save_msg_didout = msg_didout;
sst->save_State = State;
- sst->save_insertmode = p_im;
sst->save_finish_op = finish_op;
sst->save_opcount = opcount;
sst->save_reg_executing = reg_executing;
@@ -8977,7 +8986,6 @@ bool save_current_state(save_state_T *sst)
msg_scroll = false; // no msg scrolling in Normal mode
restart_edit = 0; // don't go to Insert mode
- p_im = false; // don't use 'insertmode
// Save the current typeahead. This is required to allow using ":normal"
// from an event handler and makes sure we don't hang when the argument
@@ -9000,7 +9008,6 @@ void restore_current_state(save_state_T *sst)
// override the value of restart_edit anyway.
restart_edit = sst->save_restart_edit;
}
- p_im = sst->save_insertmode;
finish_op = sst->save_finish_op;
opcount = sst->save_opcount;
reg_executing = sst->save_reg_executing;
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index 874e0e599e..24656f3851 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -25,7 +25,6 @@ typedef struct {
int save_restart_edit;
bool save_msg_didout;
int save_State;
- int save_insertmode;
bool save_finish_op;
long save_opcount;
int save_reg_executing;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 114f1e2ae5..3b1ff9ffed 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -804,6 +804,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
ccline.cmdlen = s->indent;
}
+ if (cmdline_level == 50) {
+ // Somehow got into a loop recursively calling getcmdline(), bail out.
+ emsg(_(e_command_too_recursive));
+ goto theend;
+ }
+
ExpandInit(&s->xpc);
ccline.xpc = &s->xpc;
@@ -995,12 +1001,13 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
State = s->save_State;
setmouse();
ui_cursor_shape(); // may show different cursor shape
+ sb_text_end_cmdline();
+
+theend:
xfree(s->save_p_icm);
xfree(ccline.last_colors.cmdbuff);
kv_destroy(ccline.last_colors.colors);
- sb_text_end_cmdline();
-
char_u *p = ccline.cmdbuff;
if (ui_has(kUICmdline)) {
@@ -1329,8 +1336,7 @@ static int command_line_execute(VimState *state, int key)
}
}
- // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert
- // mode when 'insertmode' is set, CTRL-\ e prompts for an expression.
+ // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ e prompts for an expression.
if (s->c == Ctrl_BSL) {
no_mapping++;
allow_keys++;
@@ -1392,9 +1398,6 @@ static int command_line_execute(VimState *state, int key)
redrawcmd();
return command_line_not_changed(s);
} else {
- if (s->c == Ctrl_G && p_im && restart_edit == 0) {
- restart_edit = 'a';
- }
s->gotesc = true; // will free ccline.cmdbuff after putting it
// in history
return 0; // back to Normal mode
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 7eef6707dd..3b6f7b90bf 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -181,6 +181,10 @@ static bool ses_do_frame(const frame_T *fr)
/// @return non-zero if window "wp" is to be stored in the Session.
static int ses_do_win(win_T *wp)
{
+ // Skip floating windows to avoid issues when restoring the Session. #18432
+ if (wp->w_floating) {
+ return false;
+ }
if (wp->w_buffer->b_fname == NULL
// When 'buftype' is "nofile" can't restore the window contents.
|| (!wp->w_buffer->terminal && bt_nofile(wp->w_buffer))) {
@@ -598,9 +602,14 @@ static int makeopens(FILE *fd, char_u *dirnow)
PUTLINE_FAIL("let s:shortmess_save = &shortmess");
}
- // Now save the current files, current buffer first.
- PUTLINE_FAIL("set shortmess=aoO");
+ // set 'shortmess' for the following. Add the 'A' flag if it was there
+ PUTLINE_FAIL("if &shortmess =~ 'A'");
+ PUTLINE_FAIL(" set shortmess=aoOA");
+ PUTLINE_FAIL("else");
+ PUTLINE_FAIL(" set shortmess=aoO");
+ PUTLINE_FAIL("endif");
+ // Now save the current files, current buffer first.
// Put all buffers into the buffer list.
// Do it very early to preserve buffer order after loading session (which
// can be disrupted by prior `edit` or `tabedit` calls).
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 090f754e93..1bd6cfb0a4 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -775,7 +775,7 @@ void clearFolding(win_T *win)
/// The changes in lines from top to bot (inclusive).
void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
{
- if (compl_busy || State & MODE_INSERT) {
+ if (disable_fold_update || compl_busy || State & MODE_INSERT) {
return;
}
@@ -785,11 +785,18 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
}
if (wp->w_folds.ga_len > 0) {
- // Mark all folds from top to bot as maybe-small.
+ linenr_T maybe_small_start = top;
+ linenr_T maybe_small_end = bot;
+
+ // Mark all folds from top to bot (or bot to top) as maybe-small.
+ if (top > bot) {
+ maybe_small_start = bot;
+ maybe_small_end = top;
+ }
fold_T *fp;
- (void)foldFind(&wp->w_folds, top, &fp);
+ (void)foldFind(&wp->w_folds, maybe_small_start, &fp);
while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len
- && fp->fd_top < bot) {
+ && fp->fd_top <= maybe_small_end) {
fp->fd_small = kNone;
fp++;
}
@@ -1929,7 +1936,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
bot = wp->w_buffer->b_ml.ml_line_count;
wp->w_foldinvalid = false;
- // Mark all folds a maybe-small.
+ // Mark all folds as maybe-small.
setSmallMaybe(&wp->w_folds);
}
@@ -1996,7 +2003,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
// start one line back, because a "<1" may indicate the end of a
// fold in the topline
if (top > 1) {
- --fline.lnum;
+ fline.lnum--;
}
} else if (foldmethodIsSyntax(wp)) {
getlevel = foldlevelSyntax;
@@ -2004,6 +2011,12 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
getlevel = foldlevelDiff;
} else {
getlevel = foldlevelIndent;
+ // Start one line back, because if the line above "top" has an
+ // undefined fold level, folding it relies on the line under it,
+ // which is "top".
+ if (top > 1) {
+ fline.lnum--;
+ }
}
// Backup to a line for which the fold level is defined. Since it's
@@ -2310,6 +2323,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level,
}
fp->fd_len += fp->fd_top - firstlnum;
fp->fd_top = firstlnum;
+ fp->fd_small = kNone;
fold_changed = true;
} else if ((flp->start != 0 && lvl == level)
|| (firstlnum != startlnum)) {
diff --git a/src/nvim/fold.h b/src/nvim/fold.h
index 6b29214760..60ea4b322e 100644
--- a/src/nvim/fold.h
+++ b/src/nvim/fold.h
@@ -23,6 +23,7 @@ typedef struct foldinfo {
#define FOLDINFO_INIT { 0, 0, 0, 0 }
+EXTERN int disable_fold_update INIT(= 0);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "fold.h.generated.h"
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 2cc068b30d..005415514c 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1352,14 +1352,12 @@ void openscript(char_u *name, bool directly)
int oldcurscript;
int save_State = State;
int save_restart_edit = restart_edit;
- int save_insertmode = p_im;
int save_finish_op = finish_op;
int save_msg_scroll = msg_scroll;
State = MODE_NORMAL;
msg_scroll = false; // no msg scrolling in Normal mode
restart_edit = 0; // don't go to Insert mode
- p_im = false; // don't use 'insertmode'
clear_oparg(&oa);
finish_op = false;
@@ -1373,7 +1371,6 @@ void openscript(char_u *name, bool directly)
State = save_State;
msg_scroll = save_msg_scroll;
restart_edit = save_restart_edit;
- p_im = save_insertmode;
finish_op = save_finish_op;
}
}
@@ -1881,8 +1878,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
if (no_mapping == 0 && maphash_valid
&& (no_zero_mapping == 0 || tb_c1 != '0')
&& (typebuf.tb_maplen == 0 || is_plug_map
- || (p_remap
- && !(typebuf.tb_noremap[typebuf.tb_off] & (RM_NONE|RM_ABBR))))
+ || (!(typebuf.tb_noremap[typebuf.tb_off] & (RM_NONE|RM_ABBR))))
&& !(p_paste && (State & (MODE_INSERT | MODE_CMDLINE)))
&& !(State == MODE_HITRETURN && (tb_c1 == CAR || tb_c1 == ' '))
&& State != MODE_ASKMORE
@@ -2514,16 +2510,12 @@ static int vgetorpeek(bool advance)
timedout = true;
continue;
}
- // When 'insertmode' is set, ESC just beeps in Insert
- // mode. Use CTRL-L to make edit() return.
// In Ex-mode \n is compatible with original Vim behaviour.
// For the command line only CTRL-C always breaks it.
// For the cmdline window: Alternate between ESC and
// CTRL-C: ESC for most situations and CTRL-C to close the
// cmdline window.
- if (p_im && (State & MODE_INSERT)) {
- c = Ctrl_L;
- } else if ((State & MODE_CMDLINE) || (cmdwin_type > 0 && tc == ESC)) {
+ if ((State & MODE_CMDLINE) || (cmdwin_type > 0 && tc == ESC)) {
c = Ctrl_C;
} else {
c = ESC;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index e34e3983db..1819af7ee4 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -84,7 +84,7 @@ EXTERN struct nvim_stats_s {
// 0 not starting anymore
// Number of Rows and Columns in the screen.
-// Note: Use default_grid.Rows and default_grid.Columns to access items in
+// Note: Use default_grid.rows and default_grid.cols to access items in
// default_grid.chars[]. They may have different values when the screen
// wasn't (re)allocated yet after setting Rows or Columns (e.g., when starting
// up).
@@ -421,10 +421,6 @@ EXTERN vimmenu_T *root_menu INIT(= NULL);
// overruling of menus that the user already defined.
EXTERN int sys_menu INIT(= false);
-// While redrawing the screen this flag is set. It means the screen size
-// ('lines' and 'rows') must not be changed.
-EXTERN int updating_screen INIT(= 0);
-
// All windows are linked in a list. firstwin points to the first entry,
// lastwin to the last entry (can be the same as firstwin) and curwin to the
// currently active window.
@@ -877,7 +873,8 @@ EXTERN char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
EXTERN char e_argreq[] INIT(= N_("E471: Argument required"));
EXTERN char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
EXTERN char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
-EXTERN char e_curdir[] INIT(= N_( "E12: Command not allowed from exrc/vimrc in current dir or tag search"));
+EXTERN char e_curdir[] INIT(= N_("E12: Command not allowed from exrc/vimrc in current dir or tag search"));
+EXTERN char e_command_too_recursive[] INIT(= N_("E169: Command too recursive"));
EXTERN char e_endif[] INIT(= N_("E171: Missing :endif"));
EXTERN char e_endtry[] INIT(= N_("E600: Missing :endtry"));
EXTERN char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index 8a5d8081c0..d241f86d1c 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -4,6 +4,7 @@
#include "nvim/arabic.h"
#include "nvim/grid.h"
#include "nvim/highlight.h"
+#include "nvim/screen.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -63,7 +64,7 @@ void grid_clear_line(ScreenGrid *grid, size_t off, int width, bool valid)
void grid_invalidate(ScreenGrid *grid)
{
- (void)memset(grid->attrs, -1, sizeof(sattr_T) * (size_t)(grid->Rows * grid->Columns));
+ (void)memset(grid->attrs, -1, sizeof(sattr_T) * (size_t)grid->rows * (size_t)grid->cols);
}
bool grid_invalid_row(ScreenGrid *grid, int row)
@@ -92,7 +93,7 @@ bool grid_lefthalve(ScreenGrid *grid, int row, int col)
grid_adjust(&grid, &row, &col);
return grid_off2cells(grid, grid->line_offset[row] + (size_t)col,
- grid->line_offset[row] + (size_t)grid->Columns) > 1;
+ grid->line_offset[row] + (size_t)grid->cols) > 1;
}
/// Correct a position on the screen, if it's the right half of a double-wide
@@ -128,7 +129,7 @@ void grid_getbytes(ScreenGrid *grid, int row, int col, char_u *bytes, int *attrp
grid_adjust(&grid, &row, &col);
// safety check
- if (grid->chars != NULL && row < grid->Rows && col < grid->Columns) {
+ if (grid->chars != NULL && row < grid->rows && col < grid->cols) {
off = grid->line_offset[row] + (size_t)col;
*attrp = grid->attrs[off];
schar_copy(bytes, grid->chars[off]);
@@ -202,8 +203,8 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
// Safety check. The check for negative row and column is to fix issue
// vim/vim#4102. TODO(neovim): find out why row/col could be negative.
if (grid->chars == NULL
- || row >= grid->Rows || row < 0
- || col >= grid->Columns || col < 0) {
+ || row >= grid->rows || row < 0
+ || col >= grid->cols || col < 0) {
return;
}
@@ -225,8 +226,8 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
put_dirty_last = MAX(put_dirty_last, 1);
}
- max_off = grid->line_offset[row] + (size_t)grid->Columns;
- while (col < grid->Columns
+ max_off = grid->line_offset[row] + (size_t)grid->cols;
+ while (col < grid->cols
&& (len < 0 || (int)(ptr - text) < len)
&& *ptr != NUL) {
c = *ptr;
@@ -259,7 +260,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
} else {
prev_c = u8c;
}
- if (col + mbyte_cells > grid->Columns) {
+ if (col + mbyte_cells > grid->cols) {
// Only 1 cell left, but character requires 2 cells:
// display a '>' in the last column to avoid wrapping. */
c = '>';
@@ -338,7 +339,7 @@ void grid_puts_line_flush(bool set_cursor)
if (put_dirty_first < put_dirty_last) {
if (set_cursor) {
ui_grid_cursor_goto(put_dirty_grid->handle, put_dirty_row,
- MIN(put_dirty_last, put_dirty_grid->Columns - 1));
+ MIN(put_dirty_last, put_dirty_grid->cols - 1));
}
if (!put_dirty_grid->throttled) {
ui_line(put_dirty_grid, put_dirty_row, put_dirty_first, put_dirty_last,
@@ -371,11 +372,11 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int
end_col += col_off;
// safety check
- if (end_row > grid->Rows) {
- end_row = grid->Rows;
+ if (end_row > grid->rows) {
+ end_row = grid->rows;
}
- if (end_col > grid->Columns) {
- end_col = grid->Columns;
+ if (end_col > grid->cols) {
+ end_col = grid->cols;
}
// nothing to do
@@ -391,7 +392,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int
if (start_col > 0 && grid_fix_col(grid, start_col, row) != start_col) {
grid_puts_len(grid, (char_u *)" ", 1, row, start_col - 1, 0);
}
- if (end_col < grid->Columns
+ if (end_col < grid->cols
&& grid_fix_col(grid, end_col, row) != end_col) {
grid_puts_len(grid, (char_u *)" ", 1, row, end_col, 0);
}
@@ -443,7 +444,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int
}
}
- if (end_col == grid->Columns) {
+ if (end_col == grid->cols) {
grid->line_wraps[row] = false;
}
}
@@ -491,17 +492,17 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
// TODO(bfredl): check all callsites and eliminate
// Check for illegal row and col, just in case
- if (row >= grid->Rows) {
- row = grid->Rows - 1;
+ if (row >= grid->rows) {
+ row = grid->rows - 1;
}
- if (endcol > grid->Columns) {
- endcol = grid->Columns;
+ if (endcol > grid->cols) {
+ endcol = grid->cols;
}
grid_adjust(&grid, &row, &coloff);
// Safety check. Avoids clang warnings down the call stack.
- if (grid->chars == NULL || row >= grid->Rows || coloff >= grid->Columns) {
+ if (grid->chars == NULL || row >= grid->rows || coloff >= grid->cols) {
DLOG("invalid state, skipped");
return;
}
@@ -509,7 +510,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
size_t off_from = 0;
size_t off_to = grid->line_offset[row] + (size_t)coloff;
max_off_from = linebuf_size;
- max_off_to = grid->line_offset[row] + (size_t)grid->Columns;
+ max_off_to = grid->line_offset[row] + (size_t)grid->cols;
if (rlflag) {
// Clear rest first, because it's left of the text.
@@ -617,7 +618,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
}
}
- if (clear_width > 0 || wp->w_width != grid->Columns) {
+ if (clear_width > 0 || wp->w_width != grid->cols) {
// If we cleared after the end of the line, it did not wrap.
// For vsplit, line wrapping is not possible.
grid->line_wraps[row] = false;
@@ -646,11 +647,11 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
new.line_offset = xmalloc((size_t)rows * sizeof(*new.line_offset));
new.line_wraps = xmalloc((size_t)rows * sizeof(*new.line_wraps));
- new.Rows = rows;
- new.Columns = columns;
+ new.rows = rows;
+ new.cols = columns;
- for (new_row = 0; new_row < new.Rows; new_row++) {
- new.line_offset[new_row] = (size_t)new_row * (size_t)new.Columns;
+ for (new_row = 0; new_row < new.rows; new_row++) {
+ new.line_offset[new_row] = (size_t)new_row * (size_t)new.cols;
new.line_wraps[new_row] = false;
grid_clear_line(&new, new.line_offset[new_row], columns, valid);
@@ -660,8 +661,8 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
// possible from the old screen to the new one and clear the rest
// (used when resizing the window at the "--more--" prompt or when
// executing an external command, for the GUI).
- if (new_row < grid->Rows && grid->chars != NULL) {
- int len = MIN(grid->Columns, new.Columns);
+ if (new_row < grid->rows && grid->chars != NULL) {
+ int len = MIN(grid->cols, new.cols);
memmove(new.chars + new.line_offset[new_row],
grid->chars + grid->line_offset[new_row],
(size_t)len * sizeof(schar_T));
@@ -705,3 +706,83 @@ void grid_free_all_mem(void)
xfree(linebuf_char);
xfree(linebuf_attr);
}
+
+/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
+/// Updates size, offsets and handle for the grid regardless.
+///
+/// If "doclear" is true, don't try to copy from the old grid rather clear the
+/// resized grid.
+void win_grid_alloc(win_T *wp)
+{
+ ScreenGrid *grid = &wp->w_grid;
+ ScreenGrid *grid_allocated = &wp->w_grid_alloc;
+
+ int rows = wp->w_height_inner;
+ int cols = wp->w_width_inner;
+ int total_rows = wp->w_height_outer;
+ int total_cols = wp->w_width_outer;
+
+ bool want_allocation = ui_has(kUIMultigrid) || wp->w_floating;
+ bool has_allocation = (grid_allocated->chars != NULL);
+
+ if (grid->rows != rows) {
+ wp->w_lines_valid = 0;
+ xfree(wp->w_lines);
+ wp->w_lines = xcalloc((size_t)rows + 1, sizeof(wline_T));
+ }
+
+ int was_resized = false;
+ if (want_allocation && (!has_allocation
+ || grid_allocated->rows != total_rows
+ || grid_allocated->cols != total_cols)) {
+ grid_alloc(grid_allocated, total_rows, total_cols,
+ wp->w_grid_alloc.valid, false);
+ grid_allocated->valid = true;
+ if (wp->w_floating && wp->w_float_config.border) {
+ wp->w_redr_border = true;
+ }
+ was_resized = true;
+ } else if (!want_allocation && has_allocation) {
+ // Single grid mode, all rendering will be redirected to default_grid.
+ // Only keep track of the size and offset of the window.
+ grid_free(grid_allocated);
+ grid_allocated->valid = false;
+ was_resized = true;
+ } else if (want_allocation && has_allocation && !wp->w_grid_alloc.valid) {
+ grid_invalidate(grid_allocated);
+ grid_allocated->valid = true;
+ }
+
+ grid->rows = rows;
+ grid->cols = cols;
+
+ if (want_allocation) {
+ grid->target = grid_allocated;
+ grid->row_offset = wp->w_winrow_off;
+ grid->col_offset = wp->w_wincol_off;
+ } else {
+ grid->target = &default_grid;
+ grid->row_offset = wp->w_winrow + wp->w_winrow_off;
+ grid->col_offset = wp->w_wincol + wp->w_wincol_off;
+ }
+
+ // send grid resize event if:
+ // - a grid was just resized
+ // - screen_resize was called and all grid sizes must be sent
+ // - the UI wants multigrid event (necessary)
+ if ((resizing_screen || was_resized) && want_allocation) {
+ ui_call_grid_resize(grid_allocated->handle,
+ grid_allocated->cols, grid_allocated->rows);
+ }
+}
+
+/// assign a handle to the grid. The grid need not be allocated.
+void grid_assign_handle(ScreenGrid *grid)
+{
+ static int last_grid_handle = DEFAULT_GRID_HANDLE;
+
+ // only assign a grid handle if not already
+ if (grid->handle == 0) {
+ grid->handle = ++last_grid_handle;
+ }
+}
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index 2516ea52a7..f2427f8aef 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -58,8 +58,8 @@ struct ScreenGrid {
int *dirty_col;
// the size of the allocated grid.
- int Rows;
- int Columns;
+ int rows;
+ int cols;
// The state of the grid is valid. Otherwise it needs to be redrawn.
bool valid;
@@ -111,4 +111,22 @@ struct ScreenGrid {
false, 0, 0, NULL, false, true, 0, \
0, 0, 0, 0, 0, false }
+/// Status line click definition
+typedef struct {
+ enum {
+ kStlClickDisabled = 0, ///< Clicks to this area are ignored.
+ kStlClickTabSwitch, ///< Switch to the given tab.
+ kStlClickTabClose, ///< Close given tab.
+ kStlClickFuncRun, ///< Run user function.
+ } type; ///< Type of the click.
+ int tabnr; ///< Tab page number.
+ char *func; ///< Function to run.
+} StlClickDefinition;
+
+/// Used for tabline clicks
+typedef struct {
+ StlClickDefinition def; ///< Click definition.
+ const char *start; ///< Location where region starts.
+} StlClickRecord;
+
#endif // NVIM_GRID_DEFS_H
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 0515842b61..d293865efd 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -111,7 +111,9 @@ typedef enum {
HLF_NFLOAT, // Floating window
HLF_MSG, // Message area
HLF_BORDER, // Floating window border
- HLF_COUNT, // MUST be the last one
+ HLF_WBR, // Window bars
+ HLF_WBRNC, // Window bars of not-current windows
+ HLF_COUNT, // MUST be the last one
} hlf_T;
EXTERN const char *hlf_names[] INIT(= {
@@ -172,6 +174,8 @@ EXTERN const char *hlf_names[] INIT(= {
[HLF_NFLOAT] = "NormalFloat",
[HLF_MSG] = "MsgArea",
[HLF_BORDER] = "FloatBorder",
+ [HLF_WBR] = "WinBar",
+ [HLF_WBRNC] = "WinBarNC",
});
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 240a96cb4b..0047cb02d6 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -103,9 +103,11 @@ static const char *highlight_init_both[] = {
"TabLineFill cterm=reverse gui=reverse",
"TabLineSel cterm=bold gui=bold",
"TermCursor cterm=reverse gui=reverse",
+ "WinBar cterm=bold gui=bold",
"WildMenu ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
"default link VertSplit Normal",
"default link WinSeparator VertSplit",
+ "default link WinBarNC WinBar",
"default link EndOfBuffer NonText",
"default link LineNrAbove LineNr",
"default link LineNrBelow LineNr",
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 80a856e91a..0ffd6cddff 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -530,11 +530,6 @@ int main(int argc, char **argv)
// 'autochdir' has been postponed.
do_autochdir();
- // start in insert mode
- if (p_im) {
- need_start_insertmode = true;
- }
-
set_vim_var_nr(VV_VIM_DID_ENTER, 1L);
apply_autocmds(EVENT_VIMENTER, NULL, NULL, false, curbuf);
TIME_MSG("VimEnter autocommands");
diff --git a/src/nvim/math.c b/src/nvim/math.c
index 63a29509bd..04ded0fd39 100644
--- a/src/nvim/math.c
+++ b/src/nvim/math.c
@@ -1,7 +1,9 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+// uncrustify:off
#include <math.h>
+// uncrustify:on
#include <stdint.h>
#include <string.h>
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 3868d65ab9..adf071fa77 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -473,27 +473,12 @@ static bool intable(const struct interval *table, size_t n_items, int c)
int utf_char2cells(int c)
{
if (c >= 0x100) {
-#ifdef USE_WCHAR_FUNCTIONS
- //
- // Assume the library function wcwidth() works better than our own
- // stuff. It should return 1 for ambiguous width chars!
- //
- int n = wcwidth(c);
-
- if (n < 0) {
- return 6; // unprintable, displays <xxxx>
- }
- if (n > 1) {
- return n;
- }
-#else
if (!utf_printable(c)) {
return 6; // unprintable, displays <xxxx>
}
if (intable(doublewidth, ARRAY_SIZE(doublewidth), c)) {
return 2;
}
-#endif
if (p_emoji && intable(emoji_width, ARRAY_SIZE(emoji_width), c)) {
return 2;
}
@@ -1061,12 +1046,6 @@ bool utf_iscomposing(int c)
*/
bool utf_printable(int c)
{
-#ifdef USE_WCHAR_FUNCTIONS
- /*
- * Assume the iswprint() library function works better than our own stuff.
- */
- return iswprint(c);
-#else
// Sorted list of non-overlapping intervals.
// 0xd800-0xdfff is reserved for UTF-16, actually illegal.
static struct interval nonprint[] =
@@ -1077,7 +1056,6 @@ bool utf_printable(int c)
};
return !intable(nonprint, ARRAY_SIZE(nonprint), c);
-#endif
}
/*
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 9ab086f1ea..35a57b708d 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -125,6 +125,8 @@ static size_t msg_ext_cur_len = 0;
static bool msg_ext_overwrite = false; ///< will overwrite last message
static int msg_ext_visible = 0; ///< number of messages currently visible
+static bool msg_ext_history_visible = false;
+
/// Shouldn't clear message after leaving cmdline
static bool msg_ext_keep_after_cmdline = false;
@@ -162,7 +164,7 @@ void msg_grid_validate(void)
{
grid_assign_handle(&msg_grid);
bool should_alloc = msg_use_grid();
- if (should_alloc && (msg_grid.Rows != Rows || msg_grid.Columns != Columns
+ if (should_alloc && (msg_grid.rows != Rows || msg_grid.cols != Columns
|| !msg_grid.chars)) {
// TODO(bfredl): eventually should be set to "invalid". I e all callers
// will use the grid including clear to EOS if necessary.
@@ -174,9 +176,9 @@ void msg_grid_validate(void)
// Tricky: allow resize while pager is active
int pos = msg_scrolled ? msg_grid_pos : Rows - p_ch;
- ui_comp_put_grid(&msg_grid, pos, 0, msg_grid.Rows, msg_grid.Columns,
+ ui_comp_put_grid(&msg_grid, pos, 0, msg_grid.rows, msg_grid.cols,
false, true);
- ui_call_grid_resize(msg_grid.handle, msg_grid.Columns, msg_grid.Rows);
+ ui_call_grid_resize(msg_grid.handle, msg_grid.cols, msg_grid.rows);
msg_grid.throttled = false; // don't throttle in 'cmdheight' area
msg_scrolled_at_flush = msg_scrolled;
@@ -1025,6 +1027,9 @@ void ex_messages(void *const eap_p)
// Display what was not skipped.
if (ui_has(kUIMessages)) {
+ if (msg_silent) {
+ return;
+ }
Array entries = ARRAY_DICT_INIT;
for (; p != NULL; p = p->next) {
if (p->msg != NULL && p->msg[0] != NUL) {
@@ -1040,6 +1045,8 @@ void ex_messages(void *const eap_p)
}
}
ui_call_msg_history_show(entries);
+ msg_ext_history_visible = true;
+ wait_return(false);
} else {
msg_hist_off = true;
for (; p != NULL && !got_int; p = p->next) {
@@ -2320,10 +2327,10 @@ void msg_scroll_up(bool may_throttle)
if (msg_grid_pos > 0) {
msg_grid_set_pos(msg_grid_pos - 1, true);
} else {
- grid_del_lines(&msg_grid, 0, 1, msg_grid.Rows, 0, msg_grid.Columns);
+ grid_del_lines(&msg_grid, 0, 1, msg_grid.rows, 0, msg_grid.cols);
memmove(msg_grid.dirty_col, msg_grid.dirty_col + 1,
- (msg_grid.Rows - 1) * sizeof(*msg_grid.dirty_col));
- msg_grid.dirty_col[msg_grid.Rows - 1] = 0;
+ (msg_grid.rows - 1) * sizeof(*msg_grid.dirty_col));
+ msg_grid.dirty_col[msg_grid.rows - 1] = 0;
}
} else {
grid_del_lines(&msg_grid_adj, 0, 1, Rows, 0, Columns);
@@ -2356,7 +2363,7 @@ void msg_scroll_flush(void)
msg_grid.throttled = false;
int pos_delta = msg_grid_pos_at_flush - msg_grid_pos;
assert(pos_delta >= 0);
- int delta = MIN(msg_scrolled - msg_scrolled_at_flush, msg_grid.Rows);
+ int delta = MIN(msg_scrolled - msg_scrolled_at_flush, msg_grid.rows);
if (pos_delta > 0) {
ui_ext_msg_set_pos(msg_grid_pos, true);
@@ -2374,7 +2381,7 @@ void msg_scroll_flush(void)
for (int i = MAX(Rows - MAX(delta, 1), 0); i < Rows; i++) {
int row = i - msg_grid_pos;
assert(row >= 0);
- ui_line(&msg_grid, row, 0, msg_grid.dirty_col[row], msg_grid.Columns,
+ ui_line(&msg_grid, row, 0, msg_grid.dirty_col[row], msg_grid.cols,
HL_ATTR(HLF_MSG), false);
msg_grid.dirty_col[row] = 0;
}
@@ -2400,9 +2407,9 @@ void msg_reset_scroll(void)
clear_cmdline = true;
if (msg_grid.chars) {
// non-displayed part of msg_grid is considered invalid.
- for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.Rows); i++) {
+ for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) {
grid_clear_line(&msg_grid, msg_grid.line_offset[i],
- msg_grid.Columns, false);
+ msg_grid.cols, false);
}
}
} else {
@@ -3126,6 +3133,10 @@ void msg_ext_clear(bool force)
msg_ext_visible = 0;
msg_ext_overwrite = false; // nothing to overwrite
}
+ if (msg_ext_history_visible) {
+ ui_call_msg_history_clear();
+ msg_ext_history_visible = false;
+ }
// Only keep once.
msg_ext_keep_after_cmdline = false;
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 8038ba2cad..347adc589f 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -68,12 +68,12 @@ bool is_mouse_key(int c)
/// mouse was previously on a status line, then the status line may be dragged.
///
/// If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
-/// cursor is moved unless the cursor was on a status line.
+/// cursor is moved unless the cursor was on a status line or window bar.
/// This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
/// IN_SEP_LINE depending on where the cursor was clicked.
///
/// If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
-/// the mouse is on the status line of the same window.
+/// the mouse is on the status line or window bar of the same window.
///
/// If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
/// the last call.
@@ -87,6 +87,7 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button)
{
static int on_status_line = 0; // #lines below bottom of window
static int on_sep_line = 0; // on separator right of window
+ static bool on_winbar = false;
static int prev_row = -1;
static int prev_col = -1;
static win_T *dragwin = NULL; // window being dragged
@@ -126,6 +127,9 @@ retnomove:
if (on_sep_line) {
return IN_SEP_LINE;
}
+ if (on_winbar) {
+ return IN_OTHER_WIN | MOUSE_WINBAR;
+ }
if (flags & MOUSE_MAY_STOP_VIS) {
end_visual_mode();
redraw_curbuf_later(INVERTED); // delete the inversion
@@ -156,13 +160,15 @@ retnomove:
dragwin = NULL;
if (row == -1) {
- return IN_OTHER_WIN;
+ on_winbar = wp->w_winbar_height != 0;
+ return IN_OTHER_WIN | (on_winbar ? MOUSE_WINBAR : 0);
}
+ on_winbar = false;
// winpos and height may change in win_enter()!
- if (grid == DEFAULT_GRID_HANDLE && row >= wp->w_height) {
+ if (grid == DEFAULT_GRID_HANDLE && row + wp->w_winbar_height >= wp->w_height) {
// In (or below) status line
- on_status_line = row - wp->w_height + 1;
+ on_status_line = row + wp->w_winbar_height - wp->w_height + 1;
dragwin = wp;
} else {
on_status_line = 0;
@@ -235,8 +241,8 @@ retnomove:
}
curwin->w_cursor.lnum = curwin->w_topline;
- } else if (on_status_line && which_button == MOUSE_LEFT) {
- if (dragwin != NULL) {
+ } else if (on_status_line) {
+ if (which_button == MOUSE_LEFT && dragwin != NULL) {
// Drag the status line
count = row - dragwin->w_winrow - dragwin->w_height + 1
- on_status_line;
@@ -253,6 +259,9 @@ retnomove:
did_drag |= count;
}
return IN_SEP_LINE; // Cursor didn't move
+ } else if (on_winbar) {
+ // After a click on the window bar don't start Visual mode.
+ return IN_OTHER_WIN | MOUSE_WINBAR;
} else {
// keep_window_focus must be true
// before moving the cursor for a left click, stop Visual mode
@@ -264,6 +273,9 @@ retnomove:
if (grid == 0) {
row -= curwin->w_grid_alloc.comp_row + curwin->w_grid.row_offset;
col -= curwin->w_grid_alloc.comp_col + curwin->w_grid.col_offset;
+ } else if (grid != DEFAULT_GRID_HANDLE) {
+ row -= curwin->w_grid.row_offset;
+ col -= curwin->w_grid.col_offset;
}
// When clicking beyond the end of the window, scroll the screen.
@@ -497,6 +509,7 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp)
// exist.
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp == fp->fr_win) {
+ *rowp -= wp->w_winbar_height;
return wp;
}
}
@@ -512,8 +525,8 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp)
win_T *wp = get_win_by_grid_handle(*gridp);
if (wp && wp->w_grid_alloc.chars
&& !(wp->w_floating && !wp->w_float_config.focusable)) {
- *rowp = MIN(*rowp - wp->w_grid.row_offset, wp->w_grid.Rows - 1);
- *colp = MIN(*colp - wp->w_grid.col_offset, wp->w_grid.Columns - 1);
+ *rowp = MIN(*rowp - wp->w_grid.row_offset, wp->w_grid.rows - 1);
+ *colp = MIN(*colp - wp->w_grid.col_offset, wp->w_grid.cols - 1);
return wp;
}
} else if (*gridp == 0) {
@@ -784,8 +797,8 @@ int mouse_check_fold(void)
wp = mouse_find_win(&click_grid, &click_row, &click_col);
if (wp && multigrid) {
- max_row = wp->w_grid_alloc.Rows;
- max_col = wp->w_grid_alloc.Columns;
+ max_row = wp->w_grid_alloc.rows;
+ max_col = wp->w_grid_alloc.cols;
}
if (wp && mouse_row >= 0 && mouse_row < max_row
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 11feb497ea..97ce92f6a9 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1016,7 +1016,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
col -= wp->w_leftcol;
if (col >= 0 && col < wp->w_width) {
- coloff = col - scol + (local ? 0 : wp->w_wincol + wp->w_border_adj[3]) + 1;
+ coloff = col - scol + (local ? 0 : wp->w_wincol + wp->w_wincol_off) + 1;
} else {
scol = ccol = ecol = 0;
// character is left or right of the window
@@ -1027,7 +1027,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
}
}
}
- *rowp = (local ? 0 : wp->w_winrow + wp->w_border_adj[0]) + row + rowoff;
+ *rowp = (local ? 0 : wp->w_winrow + wp->w_winrow_off) + row + rowoff;
*scolp = scol + coloff;
*ccolp = ccol + coloff;
*ecolp = ecol + coloff;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 2826b7dad1..7c7a042eac 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -32,6 +32,7 @@
#include "nvim/fold.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
+#include "nvim/grid_defs.h"
#include "nvim/indent.h"
#include "nvim/keycodes.h"
#include "nvim/log.h"
@@ -1126,9 +1127,6 @@ static int normal_execute(VimState *state, int key)
if (s->ca.nchar == ESC) {
clearop(&s->oa);
- if (restart_edit == 0 && goto_im()) {
- restart_edit = 'a';
- }
s->command_finished = true;
goto finish;
}
@@ -1178,14 +1176,6 @@ static void normal_check_stuff_buffer(NormalState *s)
// if wait_return still needed call it now
wait_return(false);
}
-
- if (need_start_insertmode && goto_im() && !VIsual_active) {
- need_start_insertmode = false;
- stuffReadbuff("i"); // start insert mode next
- // skip the fileinfo message now, because it would be shown
- // after insert mode finishes!
- need_fileinfo = false;
- }
}
}
@@ -1280,7 +1270,8 @@ static void normal_redraw(NormalState *s)
validate_cursor();
if (VIsual_active) {
- update_curbuf(INVERTED); // update inverted part
+ redraw_curbuf_later(INVERTED); // update inverted part
+ update_screen(INVERTED);
} else if (must_redraw) {
update_screen(0);
} else if (redraw_cmdline || clear_cmdline) {
@@ -1442,6 +1433,63 @@ static void move_tab_to_mouse(void)
}
}
+/// Call click definition function for column "col" in the "click_defs" array for button
+/// "which_button".
+static void call_click_def_func(StlClickDefinition *click_defs, int col, int which_button)
+{
+ typval_T argv[] = {
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_NUMBER,
+ .vval = {
+ .v_number = (varnumber_T)click_defs[col].tabnr
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_NUMBER,
+ .vval = {
+ .v_number = ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK
+ ? 4
+ : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK
+ ? 3
+ : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK
+ ? 2
+ : 1)))
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = {
+ .v_string = (which_button == MOUSE_LEFT
+ ? "l"
+ : (which_button == MOUSE_RIGHT
+ ? "r"
+ : (which_button == MOUSE_MIDDLE
+ ? "m"
+ : "?")))
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = {
+ .v_string = (char[]) {
+ (char)(mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
+ (char)(mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
+ (char)(mod_mask & MOD_MASK_ALT ? 'a' : ' '),
+ (char)(mod_mask & MOD_MASK_META ? 'm' : ' '),
+ NUL
+ }
+ },
+ }
+ };
+ typval_T rettv;
+ (void)call_vim_function(click_defs[col].func, ARRAY_SIZE(argv), argv, &rettv);
+ tv_clear(&rettv);
+}
+
/// Do the appropriate action for the current mouse click in the current mode.
/// Not used for Command-line mode.
///
@@ -1491,6 +1539,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
int jump_flags = 0; // flags for jump_to_mouse()
pos_T start_visual;
bool moved; // Has cursor moved?
+ bool in_winbar; // mouse in window bar
bool in_status_line; // mouse in status line
static bool in_tab_line = false; // mouse clicked in tab line
bool in_sep_line; // mouse in vertical separator line
@@ -1721,66 +1770,10 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
}
}
break;
- case kStlClickFuncRun: {
- typval_T argv[] = {
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_NUMBER,
- .vval = {
- .v_number = (varnumber_T)tab_page_click_defs[mouse_col].tabnr
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_NUMBER,
- .vval = {
- .v_number = ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK
- ? 4
- : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK
- ? 3
- : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK
- ? 2
- : 1)))
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_STRING,
- .vval = {
- .v_string = (which_button == MOUSE_LEFT
- ? "l"
- : (which_button == MOUSE_RIGHT
- ? "r"
- : (which_button == MOUSE_MIDDLE
- ? "m"
- : "?")))
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_STRING,
- .vval = {
- .v_string = (char[]) {
- (char)(mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
- (char)(mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
- (char)(mod_mask & MOD_MASK_ALT ? 'a' : ' '),
- (char)(mod_mask & MOD_MASK_META ? 'm' : ' '),
- NUL
- }
- },
- }
- };
- typval_T rettv;
- funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.firstline = curwin->w_cursor.lnum;
- funcexe.lastline = curwin->w_cursor.lnum;
- funcexe.evaluate = true;
- (void)call_func(tab_page_click_defs[mouse_col].func, -1,
- &rettv, ARRAY_SIZE(argv), argv, &funcexe);
- tv_clear(&rettv);
+ case kStlClickFuncRun:
+ call_click_def_func(tab_page_click_defs, mouse_col, which_button);
break;
}
- }
}
return true;
} else if (is_drag && in_tab_line) {
@@ -1851,9 +1844,38 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
which_button);
moved = (jump_flags & CURSOR_MOVED);
+ in_winbar = (jump_flags & MOUSE_WINBAR);
in_status_line = (jump_flags & IN_STATUS_LINE);
in_sep_line = (jump_flags & IN_SEP_LINE);
+ if ((in_winbar || in_status_line) && is_click) {
+ // Handle click event on window bar or status lin
+ int click_grid = mouse_grid;
+ int click_row = mouse_row;
+ int click_col = mouse_col;
+ win_T *wp = mouse_find_win(&click_grid, &click_row, &click_col);
+
+ StlClickDefinition *click_defs = in_status_line ? wp->w_status_click_defs
+ : wp->w_winbar_click_defs;
+
+ if (click_defs != NULL) {
+ switch (click_defs[click_col].type) {
+ case kStlClickDisabled:
+ break;
+ case kStlClickFuncRun:
+ call_click_def_func(click_defs, click_col, which_button);
+ break;
+ default:
+ assert(false && "winbar and statusline only support %@ for clicks");
+ break;
+ }
+ }
+
+ return false;
+ } else if (in_winbar) {
+ // A drag or release event in the window bar has no side effects.
+ return false;
+ }
// When jumping to another window, clear a pending operator. That's a bit
// friendlier than beeping and not jumping to that window.
@@ -3898,7 +3920,6 @@ static void nv_regreplay(cmdarg_T *cap)
/// Handle a ":" command and <Cmd> or Lua keymaps.
static void nv_colon(cmdarg_T *cap)
{
- int old_p_im;
bool cmd_result;
bool is_cmdkey = cap->cmdchar == K_COMMAND;
bool is_lua = cap->cmdchar == K_LUA;
@@ -3924,8 +3945,6 @@ static void nv_colon(cmdarg_T *cap)
compute_cmdrow();
}
- old_p_im = p_im;
-
if (is_lua) {
cmd_result = map_execute_lua();
} else {
@@ -3934,15 +3953,6 @@ static void nv_colon(cmdarg_T *cap)
cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
}
- // If 'insertmode' changed, enter or exit Insert mode
- if (p_im != old_p_im) {
- if (p_im) {
- restart_edit = 'i';
- } else {
- restart_edit = 0;
- }
- }
-
if (cmd_result == false) {
// The Ex command failed, do not execute the operator.
clearop(cap->oap);
@@ -6729,10 +6739,6 @@ static void nv_normal(cmdarg_T *cap)
end_visual_mode(); // stop Visual
redraw_curbuf_later(INVERTED);
}
- // CTRL-\ CTRL-G restarts Insert mode when 'insertmode' is set.
- if (cap->nchar == Ctrl_G && p_im) {
- restart_edit = 'a';
- }
} else {
clearopbeep(cap->oap);
}
@@ -6747,8 +6753,7 @@ static void nv_esc(cmdarg_T *cap)
no_reason = (cap->oap->op_type == OP_NOP
&& cap->opcount == 0
&& cap->count0 == 0
- && cap->oap->regname == 0
- && !p_im);
+ && cap->oap->regname == 0);
if (cap->arg) { // true for CTRL-C
if (restart_edit == 0
@@ -6765,9 +6770,8 @@ static void nv_esc(cmdarg_T *cap)
// Don't reset "restart_edit" when 'insertmode' is set, it won't be
// set again below when halfway through a mapping.
- if (!p_im) {
- restart_edit = 0;
- }
+ restart_edit = 0;
+
if (cmdwin_type != 0) {
cmdwin_result = K_IGNORE;
got_int = false; // don't stop executing autocommands et al.
@@ -6790,13 +6794,6 @@ static void nv_esc(cmdarg_T *cap)
vim_beep(BO_ESC);
}
clearop(cap->oap);
-
- // A CTRL-C is often used at the start of a menu. When 'insertmode' is
- // set return to Insert mode afterwards.
- if (restart_edit == 0 && goto_im()
- && ex_normal_busy == 0) {
- restart_edit = 'a';
- }
}
// Move the cursor for the "A" command.
@@ -6831,8 +6828,7 @@ static void nv_edit(cmdarg_T *cap)
} else if ((cap->cmdchar == 'a' || cap->cmdchar == 'i')
&& (cap->oap->op_type != OP_NOP || VIsual_active)) {
nv_object(cap);
- } else if (!curbuf->b_p_ma && !p_im && !curbuf->terminal) {
- // Only give this error when 'insertmode' is off.
+ } else if (!curbuf->b_p_ma && !curbuf->terminal) {
emsg(_(e_modifiable));
clearop(cap->oap);
} else if (!checkclearopq(cap->oap)) {
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index c3d7742307..8ea55579bb 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -4911,12 +4911,19 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
ssize_t change_cnt = 0;
linenr_T amount = Prenum1;
+ // do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the
+ // buffer is not completly updated yet. Postpone updating folds until before
+ // the call to changed_lines().
+ disable_fold_update++;
+
if (!VIsual_active) {
pos = curwin->w_cursor;
if (u_save_cursor() == FAIL) {
+ disable_fold_update--;
return;
}
change_cnt = do_addsub(oap->op_type, &pos, 0, amount);
+ disable_fold_update--;
if (change_cnt) {
changed_lines(pos.lnum, 0, pos.lnum + 1, 0L, true);
}
@@ -4927,6 +4934,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
if (u_save((linenr_T)(oap->start.lnum - 1),
(linenr_T)(oap->end.lnum + 1)) == FAIL) {
+ disable_fold_update--;
return;
}
@@ -4973,6 +4981,8 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
amount += Prenum1;
}
}
+
+ disable_fold_update--;
if (change_cnt) {
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
}
@@ -6709,7 +6719,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
// remember it to make 'insertmode' work with mappings for
// Visual mode. But do this only once and not when typed and
// 'insertmode' isn't set.
- if (p_im || !KeyTyped) {
+ if (!KeyTyped) {
restart_edit_save = restart_edit;
} else {
restart_edit_save = 0;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 8267bcf9da..0d02bae5f7 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2149,6 +2149,8 @@ static uint32_t *insecure_flag(win_T *const wp, int opt_idx, int opt_flags)
switch ((int)options[opt_idx].indir) {
case PV_STL:
return &wp->w_p_stl_flags;
+ case PV_WBR:
+ return &wp->w_p_wbr_flags;
case PV_FDE:
return &wp->w_p_fde_flags;
case PV_FDT:
@@ -2930,8 +2932,8 @@ ambw_end:
curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
redraw_titles();
}
- } else if (gvarp == &p_stl || varp == &p_tal || varp == &p_ruf) {
- // 'statusline', 'tabline' or 'rulerformat'
+ } else if (gvarp == &p_stl || gvarp == (char_u **)&p_wbr || varp == &p_tal || varp == &p_ruf) {
+ // 'statusline', 'winbar', 'tabline' or 'rulerformat'
int wid;
if (varp == &p_ruf) { // reset ru_wid first
@@ -2950,12 +2952,16 @@ ambw_end:
errmsg = check_stl_option(p_ruf);
}
} else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') {
- // check 'statusline' or 'tabline' only if it doesn't start with "%!"
+ // check 'statusline', 'winbar' or 'tabline' only if it doesn't start with "%!"
errmsg = check_stl_option(s);
}
if (varp == &p_ruf && errmsg == NULL) {
comp_col();
}
+ // add / remove window bars for 'winbar'
+ if (gvarp == (char_u **)&p_wbr) {
+ set_winbar();
+ }
} else if (gvarp == &p_cpt) {
// check if it is a valid value for 'complete' -- Acevedo
for (s = *varp; *s;) {
@@ -3570,6 +3576,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
struct chars_tab fcs_tab[] = {
{ &wp->w_p_fcs_chars.stl, "stl", ' ' },
{ &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
+ { &wp->w_p_fcs_chars.wbr, "wbr", ' ' },
{ &wp->w_p_fcs_chars.horiz, "horiz", 9472 }, // ─
{ &wp->w_p_fcs_chars.horizup, "horizup", 9524 }, // ┴
{ &wp->w_p_fcs_chars.horizdown, "horizdown", 9516 }, // ┬
@@ -3612,15 +3619,15 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
if (*p_ambw == 'd') {
// XXX: If ambiwidth=double then some characters take 2 columns,
// which is forbidden (TUI limitation?). Set old defaults.
- fcs_tab[2].def = '-';
fcs_tab[3].def = '-';
fcs_tab[4].def = '-';
- fcs_tab[5].def = '|';
+ fcs_tab[5].def = '-';
fcs_tab[6].def = '|';
fcs_tab[7].def = '|';
- fcs_tab[8].def = '+';
- fcs_tab[9].def = '-';
- fcs_tab[12].def = '|';
+ fcs_tab[8].def = '|';
+ fcs_tab[9].def = '+';
+ fcs_tab[10].def = '-';
+ fcs_tab[13].def = '|';
}
}
@@ -4042,36 +4049,9 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va
// buf->b_p_swf
mf_close_file(curbuf, true); // remove the swap file
}
- } else if ((int *)varp == &p_terse) {
- // when 'terse' is set change 'shortmess'
- char *p = vim_strchr((char *)p_shm, SHM_SEARCH);
-
- // insert 's' in p_shm
- if (p_terse && p == NULL) {
- STRCPY(IObuff, p_shm);
- STRCAT(IObuff, "s");
- set_string_option_direct("shm", -1, IObuff, OPT_FREE, 0);
- } else if (!p_terse && p != NULL) { // remove 's' from p_shm
- STRMOVE(p, p + 1);
- }
} else if ((int *)varp == &p_paste) {
// when 'paste' is set or reset also change other options
paste_option_changed();
- } else if ((int *)varp == &p_im) {
- // when 'insertmode' is set from an autocommand need to do work here
- if (p_im) {
- if ((State & MODE_INSERT) == 0) {
- need_start_insertmode = true;
- }
- stop_insert_mode = false;
- } else if (old_value) { // only reset if it was set previously
- need_start_insertmode = false;
- stop_insert_mode = true;
- if (restart_edit != 0 && mode_displayed) {
- clear_cmdline = true; // remove "(insert)"
- }
- restart_edit = 0;
- }
} else if ((int *)varp == &p_ic && p_hls) {
// when 'ignorecase' is set or reset and 'hlsearch' is set, redraw
redraw_all_later(SOME_VALID);
@@ -4766,7 +4746,7 @@ static void check_redraw(uint32_t flags)
bool doclear = (flags & P_RCLR) == P_RCLR;
bool all = ((flags & P_RALL) == P_RALL || doclear);
- if ((flags & P_RSTAT) || all) { // mark all status lines dirty
+ if ((flags & P_RSTAT) || all) { // mark all status lines and window bars dirty
status_redraw_all();
}
@@ -5814,6 +5794,9 @@ void unset_global_local_option(char *name, void *from)
case PV_STL:
clear_string_option(&((win_T *)from)->w_p_stl);
break;
+ case PV_WBR:
+ clear_string_option((char_u **)&((win_T *)from)->w_p_wbr);
+ break;
case PV_UL:
buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
break;
@@ -5891,6 +5874,8 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
return (char_u *)&(curwin->w_p_sbr);
case PV_STL:
return (char_u *)&(curwin->w_p_stl);
+ case PV_WBR:
+ return (char_u *)&(curwin->w_p_wbr);
case PV_UL:
return (char_u *)&(curbuf->b_p_ul);
case PV_LW:
@@ -5984,6 +5969,9 @@ static char_u *get_varp(vimoption_T *p)
case PV_STL:
return *curwin->w_p_stl != NUL
? (char_u *)&(curwin->w_p_stl) : p->var;
+ case PV_WBR:
+ return *curwin->w_p_wbr != NUL
+ ? (char_u *)&(curwin->w_p_wbr) : p->var;
case PV_UL:
return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL
? (char_u *)&(curbuf->b_p_ul) : p->var;
@@ -6252,6 +6240,7 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_rlc = vim_strsave(from->wo_rlc);
to->wo_sbr = vim_strsave(from->wo_sbr);
to->wo_stl = vim_strsave(from->wo_stl);
+ to->wo_wbr = xstrdup(from->wo_wbr);
to->wo_wrap = from->wo_wrap;
to->wo_wrap_save = from->wo_wrap_save;
to->wo_lbr = from->wo_lbr;
@@ -6327,6 +6316,7 @@ static void check_winopt(winopt_T *wop)
check_string_option(&wop->wo_fcs);
check_string_option(&wop->wo_lcs);
check_string_option(&wop->wo_ve);
+ check_string_option((char_u **)&wop->wo_wbr);
}
/// Free the allocated memory inside a winopt_T.
@@ -6352,6 +6342,7 @@ void clear_winopt(winopt_T *wop)
clear_string_option(&wop->wo_fcs);
clear_string_option(&wop->wo_lcs);
clear_string_option(&wop->wo_ve);
+ clear_string_option((char_u **)&wop->wo_wbr);
}
void didset_window_options(win_T *wp)
@@ -6538,6 +6529,7 @@ void buf_copy_options(buf_T *buf, int flags)
COPY_OPT_SCTX(buf, BV_SI);
buf->b_p_channel = 0;
buf->b_p_ci = p_ci;
+
COPY_OPT_SCTX(buf, BV_CI);
buf->b_p_cin = p_cin;
COPY_OPT_SCTX(buf, BV_CIN);
@@ -6547,6 +6539,7 @@ void buf_copy_options(buf_T *buf, int flags)
COPY_OPT_SCTX(buf, BV_CINO);
buf->b_p_cinsd = vim_strsave(p_cinsd);
COPY_OPT_SCTX(buf, BV_CINSD);
+
// Don't copy 'filetype', it must be detected
buf->b_p_ft = empty_option;
buf->b_p_pi = p_pi;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index e358a29622..0dc4bd1b90 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -334,9 +334,9 @@ EXTERN unsigned bo_flags;
#ifdef IN_OPTION_C
static char *(p_bo_values[]) = { "all", "backspace", "cursor", "complete",
"copy", "ctrlg", "error", "esc", "ex",
- "hangul", "insertmode", "lang", "mess",
- "showmatch", "operator", "register", "shell",
- "spell", "wildmode", NULL };
+ "hangul", "lang", "mess", "showmatch",
+ "operator", "register", "shell", "spell",
+ "wildmode", NULL };
#endif
// values for the 'belloff' option
@@ -485,7 +485,6 @@ EXTERN char_u *p_iconstring; // 'iconstring'
EXTERN int p_ic; // 'ignorecase'
EXTERN int p_is; // 'incsearch'
EXTERN char_u *p_icm; // 'inccommand'
-EXTERN int p_im; // 'insertmode'
EXTERN char_u *p_isf; // 'isfname'
EXTERN char_u *p_isi; // 'isident'
EXTERN char_u *p_isp; // 'isprint'
@@ -557,7 +556,6 @@ static char *(p_rdb_values[]) = {
#define RDB_NODELTA 0x008
EXTERN long p_rdt; // 'redrawtime'
-EXTERN int p_remap; // 'remap'
EXTERN long p_re; // 'regexpengine'
EXTERN long p_report; // 'report'
EXTERN long p_pvh; // 'previewheight'
@@ -618,6 +616,7 @@ EXTERN int p_stmp; // 'shelltemp'
EXTERN int p_ssl; // 'shellslash'
#endif
EXTERN char_u *p_stl; // 'statusline'
+EXTERN char *p_wbr; // 'winbar'
EXTERN int p_sr; // 'shiftround'
EXTERN char_u *p_shm; // 'shortmess'
EXTERN char_u *p_sbr; // 'showbreak'
@@ -678,7 +677,6 @@ EXTERN int p_tr; ///< 'tagrelative'
EXTERN char_u *p_tags; ///< 'tags'
EXTERN int p_tgst; ///< 'tagstack'
EXTERN int p_tbidi; ///< 'termbidi'
-EXTERN int p_terse; ///< 'terse'
EXTERN int p_to; ///< 'tildeop'
EXTERN int p_timeout; ///< 'timeout'
EXTERN long p_tm; ///< 'timeoutlen'
@@ -897,6 +895,7 @@ enum {
WV_FCS,
WV_LCS,
WV_WINBL,
+ WV_WBR,
WV_COUNT, // must be the last one
};
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 313cace4b2..a0fbf8d9f0 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1250,9 +1250,9 @@ return {
},
{
full_name='insertmode', abbreviation='im',
- short_desc=N_("start the edit of a file in Insert mode"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
- varname='p_im',
+ varname='p_force_off',
defaults={if_true=false}
},
{
@@ -1911,9 +1911,9 @@ return {
},
{
full_name='remap',
- short_desc=N_("mappings to work recursively"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
- varname='p_remap',
+ varname='p_force_on',
defaults={if_true=true}
},
{
@@ -2529,9 +2529,9 @@ return {
},
{
full_name='terse',
- short_desc=N_("hides notification of search wrap"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
- varname='p_terse',
+ varname='p_force_off',
defaults={if_true=false}
},
{
@@ -2832,6 +2832,16 @@ return {
defaults={if_true="menu"}
},
{
+ full_name='winbar', abbreviation='wbr',
+ short_desc=N_("custom format for the window bar"),
+ type='string', scope={'global', 'window'},
+ alloced=true,
+ modelineexpr=true,
+ redraw={'statuslines'},
+ varname='p_wbr',
+ defaults={if_true=""}
+ },
+ {
full_name='winblend', abbreviation='winbl',
short_desc=N_("Controls transparency level for floating windows"),
type='number', scope={'window'},
diff --git a/src/nvim/os/fs.h b/src/nvim/os/fs.h
new file mode 100644
index 0000000000..c68081da02
--- /dev/null
+++ b/src/nvim/os/fs.h
@@ -0,0 +1,10 @@
+#ifndef NVIM_OS_FS_H
+#define NVIM_OS_FS_H
+
+#include "nvim/os/fs_defs.h" // for uv_*
+#include "nvim/types.h" // for char_u
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/fs.h.generated.h"
+#endif
+#endif // NVIM_OS_FS_H
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index c99d2869da..ac21b32a3e 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -19,6 +19,7 @@
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/os/input.h"
+#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -178,15 +179,7 @@ void os_breakcheck(void)
return;
}
- int save_us = updating_screen;
- // We do not want screen_resize() to redraw here.
- // TODO(bfredl): we are already special casing redraw events, is this
- // hack still needed?
- updating_screen++;
-
loop_poll_events(&main_loop, 0);
-
- updating_screen = save_us;
}
#define BREAKCHECK_SKIP 1000
diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c
index 4803be20c3..3d67ae4ce0 100644
--- a/src/nvim/os/users.c
+++ b/src/nvim/os/users.c
@@ -30,7 +30,7 @@ static void add_user(garray_T *users, char *user, bool need_copy)
if (user_copy == NULL || *user_copy == NUL) {
if (need_copy) {
- xfree(user);
+ xfree(user_copy);
}
return;
}
diff --git a/src/nvim/po/check.vim b/src/nvim/po/check.vim
index aca878f9d5..7705ba8577 100644
--- a/src/nvim/po/check.vim
+++ b/src/nvim/po/check.vim
@@ -41,7 +41,7 @@ set nowrapscan
" Start at the first "msgid" line.
let wsv = winsaveview()
1
-/^msgid\>
+keeppatterns /^msgid\>
" When an error is detected this is set to the line number.
" Note: this is used in the Makefile.
@@ -104,7 +104,7 @@ while 1
" Find next msgid. Quit when there is no more.
let lnum = line('.')
- silent! /^msgid\>
+ silent! keeppatterns /^msgid\>
if line('.') == lnum
break
endif
@@ -137,7 +137,7 @@ endfunc
" Check that the \n at the end of the msgid line is also present in the msgstr
" line. Skip over the header.
1
-/^"MIME-Version:
+keeppatterns /^"MIME-Version:
while 1
let lnum = search('^msgid\>')
if lnum <= 0
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index c5c1d87919..9525a84e62 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -429,9 +429,9 @@ void pum_redraw(void)
must_redraw_pum = false;
if (!pum_grid.chars
- || pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) {
+ || pum_grid.rows != pum_height || pum_grid.cols != grid_width) {
grid_alloc(&pum_grid, pum_height, grid_width, !invalid_grid, false);
- ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows);
+ ui_call_grid_resize(pum_grid.handle, pum_grid.cols, pum_grid.rows);
} else if (invalid_grid) {
grid_invalidate(&pum_grid);
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 883de85aee..9c7b36396b 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -2540,9 +2540,7 @@ static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window)
}
}
- if (!p_im) {
- restart_edit = 0; // don't want insert mode in help file
- }
+ restart_edit = 0; // don't want insert mode in help file
return OK;
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 686516f17b..d88975fa78 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -88,6 +88,7 @@
#include "nvim/fold.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
@@ -132,10 +133,6 @@
static match_T search_hl; // used for 'hlsearch' highlight matching
-StlClickDefinition *tab_page_click_defs = NULL;
-
-long tab_page_click_defs_size = 0;
-
// for line_putchar. Contains the state that needs to be remembered from
// putting one character to the next.
typedef struct {
@@ -276,21 +273,12 @@ void redrawWinline(win_T *wp, linenr_T lnum)
}
}
-/*
- * update all windows that are editing the current buffer
- */
-void update_curbuf(int type)
-{
- redraw_curbuf_later(type);
- update_screen(type);
-}
-
/// called when the status bars for the buffer 'buf' need to be updated
void redraw_buf_status_later(buf_T *buf)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_buffer == buf
- && (wp->w_status_height || (wp == curwin && global_stl_height()))) {
+ if (wp->w_buffer == buf && (wp->w_status_height || (wp == curwin && global_stl_height())
+ || wp->w_winbar_height)) {
wp->w_redr_status = true;
if (must_redraw < VALID) {
must_redraw = VALID;
@@ -382,9 +370,9 @@ int update_screen(int type)
int valid = MAX(Rows - msg_scrollsize(), 0);
if (msg_grid.chars) {
// non-displayed part of msg_grid is considered invalid.
- for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.Rows); i++) {
+ for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) {
grid_clear_line(&msg_grid, msg_grid.line_offset[i],
- msg_grid.Columns, false);
+ msg_grid.cols, false);
}
}
if (msg_use_msgsep()) {
@@ -431,7 +419,7 @@ int update_screen(int type)
wp->w_redr_type = REDRAW_TOP;
} else {
wp->w_redr_type = NOT_VALID;
- if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height <= msg_scrolled) {
+ if (wp->w_winrow + wp->w_winbar_height <= msg_scrolled) {
wp->w_redr_status = true;
}
}
@@ -585,8 +573,9 @@ int update_screen(int type)
win_update(wp, &providers);
}
- // redraw status line after the window to minimize cursor movement
+ // redraw status line and window bar after the window to minimize cursor movement
if (wp->w_redr_status) {
+ win_redr_winbar(wp);
win_redr_status(wp);
}
}
@@ -598,8 +587,6 @@ int update_screen(int type)
pum_redraw();
}
- send_grid_resize = false;
-
/* Reset b_mod_set flags. Going through all windows is probably faster
* than going through all buffers (there could be many buffers). */
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
@@ -747,7 +734,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
// Window is zero-height: Only need to draw the separator
- if (wp->w_grid.Rows == 0) {
+ if (wp->w_grid.rows == 0) {
// draw the horizontal separator below this window
draw_hsep_win(wp);
draw_sep_connectors_win(wp);
@@ -756,7 +743,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
// Window is zero-width: Only need to draw the separator.
- if (wp->w_grid.Columns == 0) {
+ if (wp->w_grid.cols == 0) {
// draw the vertical separator right of this window
draw_vsep_win(wp);
draw_sep_connectors_win(wp);
@@ -955,7 +942,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
j = 0;
for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ln++) {
j++;
- if (j >= wp->w_grid.Rows - 2) {
+ if (j >= wp->w_grid.rows - 2) {
break;
}
(void)hasFoldingWin(wp, ln, NULL, &ln, true, NULL);
@@ -963,13 +950,13 @@ static void win_update(win_T *wp, DecorProviders *providers)
} else {
j = wp->w_lines[0].wl_lnum - wp->w_topline;
}
- if (j < wp->w_grid.Rows - 2) { // not too far off
+ if (j < wp->w_grid.rows - 2) { // not too far off
i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
// insert extra lines for previously invisible filler lines
if (wp->w_lines[0].wl_lnum != wp->w_topline) {
i += win_get_fill(wp, wp->w_lines[0].wl_lnum) - wp->w_old_topfill;
}
- if (i != 0 && i < wp->w_grid.Rows - 2) { // less than a screen off
+ if (i != 0 && i < wp->w_grid.rows - 2) { // less than a screen off
// Try to insert the correct number of lines.
// If not the last window, delete the lines at the bottom.
// win_ins_lines may fail when the terminal can't do it.
@@ -982,8 +969,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
// Move the entries that were scrolled, disable
// the entries for the lines to be redrawn.
- if ((wp->w_lines_valid += j) > wp->w_grid.Rows) {
- wp->w_lines_valid = wp->w_grid.Rows;
+ if ((wp->w_lines_valid += j) > wp->w_grid.rows) {
+ wp->w_lines_valid = wp->w_grid.rows;
}
for (idx = wp->w_lines_valid; idx - j >= 0; idx--) {
wp->w_lines[idx] = wp->w_lines[idx - j];
@@ -1036,7 +1023,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
row -= wp->w_topfill;
if (row > 0) {
win_scroll_lines(wp, 0, -row);
- bot_start = wp->w_grid.Rows - row;
+ bot_start = wp->w_grid.rows - row;
}
if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) {
/*
@@ -1052,7 +1039,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
/* stop at line that didn't fit, unless it is still
* valid (no lines deleted) */
if (row > 0 && bot_start + row
- + (int)wp->w_lines[j].wl_size > wp->w_grid.Rows) {
+ + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) {
wp->w_lines_valid = idx + 1;
break;
}
@@ -1077,18 +1064,18 @@ static void win_update(win_T *wp, DecorProviders *providers)
// When starting redraw in the first line, redraw all lines.
if (mid_start == 0) {
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
}
} else {
// Not VALID or INVERTED: redraw all lines.
mid_start = 0;
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
}
if (type == SOME_VALID) {
// SOME_VALID: redraw all lines.
mid_start = 0;
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
type = NOT_VALID;
}
@@ -1275,7 +1262,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
}
srow += mid_start;
- mid_end = wp->w_grid.Rows;
+ mid_end = wp->w_grid.rows;
for (; idx < wp->w_lines_valid; idx++) { // find end
if (wp->w_lines[idx].wl_valid
&& wp->w_lines[idx].wl_lnum >= to + 1) {
@@ -1328,7 +1315,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
for (;;) {
/* stop updating when reached the end of the window (check for _past_
* the end of the window is at the end of the loop) */
- if (row == wp->w_grid.Rows) {
+ if (row == wp->w_grid.rows) {
didline = true;
break;
}
@@ -1433,7 +1420,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
new_rows += plines_win(wp, l, true);
}
j++;
- if (new_rows > wp->w_grid.Rows - row - 2) {
+ if (new_rows > wp->w_grid.rows - row - 2) {
// it's getting too much, must redraw the rest
new_rows = 9999;
break;
@@ -1445,17 +1432,17 @@ static void win_update(win_T *wp, DecorProviders *providers)
* remaining text or scrolling fails, must redraw the
* rest. If scrolling works, must redraw the text
* below the scrolled text. */
- if (row - xtra_rows >= wp->w_grid.Rows - 2) {
+ if (row - xtra_rows >= wp->w_grid.rows - 2) {
mod_bot = MAXLNUM;
} else {
win_scroll_lines(wp, row, xtra_rows);
- bot_start = wp->w_grid.Rows + xtra_rows;
+ bot_start = wp->w_grid.rows + xtra_rows;
}
} else if (xtra_rows > 0) {
/* May scroll text down. If there is not enough
* remaining text of scrolling fails, must redraw the
* rest. */
- if (row + xtra_rows >= wp->w_grid.Rows - 2) {
+ if (row + xtra_rows >= wp->w_grid.rows - 2) {
mod_bot = MAXLNUM;
} else {
win_scroll_lines(wp, row + old_rows, xtra_rows);
@@ -1483,7 +1470,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
wp->w_lines[j] = wp->w_lines[i];
// stop at a line that won't fit
if (x + (int)wp->w_lines[j].wl_size
- > wp->w_grid.Rows) {
+ > wp->w_grid.rows) {
wp->w_lines_valid = j + 1;
break;
}
@@ -1497,8 +1484,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
// move entries in w_lines[] downwards
j -= i;
wp->w_lines_valid += j;
- if (wp->w_lines_valid > wp->w_grid.Rows) {
- wp->w_lines_valid = wp->w_grid.Rows;
+ if (wp->w_lines_valid > wp->w_grid.rows) {
+ wp->w_lines_valid = wp->w_grid.rows;
}
for (i = wp->w_lines_valid; i - j >= idx; i--) {
wp->w_lines[i] = wp->w_lines[i - j];
@@ -1529,11 +1516,11 @@ static void win_update(win_T *wp, DecorProviders *providers)
&& wp->w_lines[idx].wl_lnum == lnum
&& lnum > wp->w_topline
&& !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
- && srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows
+ && srow + wp->w_lines[idx].wl_size > wp->w_grid.rows
&& win_get_fill(wp, lnum) == 0) {
// This line is not going to fit. Don't draw anything here,
// will draw "@ " lines below.
- row = wp->w_grid.Rows + 1;
+ row = wp->w_grid.rows + 1;
} else {
prepare_search_hl(wp, &search_hl, lnum);
// Let the syntax stuff know we skipped a few lines.
@@ -1544,7 +1531,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
// Display one line
row = win_line(wp, lnum, srow,
- foldinfo.fi_lines ? srow : wp->w_grid.Rows,
+ foldinfo.fi_lines ? srow : wp->w_grid.rows,
mod_top == 0, false, foldinfo, &line_providers);
if (foldinfo.fi_lines == 0) {
@@ -1563,7 +1550,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
wp->w_lines[idx].wl_lnum = lnum;
wp->w_lines[idx].wl_valid = true;
- if (row > wp->w_grid.Rows) { // past end of grid
+ if (row > wp->w_grid.rows) { // past end of grid
// we may need the size of that too long line later on
if (dollar_vcol == -1) {
wp->w_lines[idx].wl_size = plines_win(wp, lnum, true);
@@ -1581,13 +1568,13 @@ static void win_update(win_T *wp, DecorProviders *providers)
// 'relativenumber' set and cursor moved vertically: The
// text doesn't need to be drawn, but the number column does.
foldinfo_T info = fold_info(wp, lnum);
- (void)win_line(wp, lnum, srow, wp->w_grid.Rows, true, true,
+ (void)win_line(wp, lnum, srow, wp->w_grid.rows, true, true,
info, &line_providers);
}
// This line does not need to be drawn, advance to the next one.
row += wp->w_lines[idx++].wl_size;
- if (row > wp->w_grid.Rows) { // past end of screen
+ if (row > wp->w_grid.rows) { // past end of screen
break;
}
lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
@@ -1635,41 +1622,41 @@ static void win_update(win_T *wp, DecorProviders *providers)
* Don't overwrite it, it can be edited.
*/
wp->w_botline = lnum + 1;
- } else if (win_get_fill(wp, lnum) >= wp->w_grid.Rows - srow) {
+ } else if (win_get_fill(wp, lnum) >= wp->w_grid.rows - srow) {
// Window ends in filler lines.
wp->w_botline = lnum;
- wp->w_filler_rows = wp->w_grid.Rows - srow;
+ wp->w_filler_rows = wp->w_grid.rows - srow;
} else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate"
- int scr_row = wp->w_grid.Rows - 1;
+ int scr_row = wp->w_grid.rows - 1;
// Last line isn't finished: Display "@@@" in the last screen line.
- grid_puts_len(&wp->w_grid, (char_u *)"@@", MIN(wp->w_grid.Columns, 2), scr_row, 0, at_attr);
+ grid_puts_len(&wp->w_grid, (char_u *)"@@", MIN(wp->w_grid.cols, 2), scr_row, 0, at_attr);
- grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.Columns,
+ grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.cols,
'@', ' ', at_attr);
set_empty_rows(wp, srow);
wp->w_botline = lnum;
} else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline"
- int start_col = wp->w_grid.Columns - 3;
+ int start_col = wp->w_grid.cols - 3;
// Last line isn't finished: Display "@@@" at the end.
- grid_fill(&wp->w_grid, wp->w_grid.Rows - 1, wp->w_grid.Rows,
- MAX(start_col, 0), wp->w_grid.Columns, '@', '@', at_attr);
+ grid_fill(&wp->w_grid, wp->w_grid.rows - 1, wp->w_grid.rows,
+ MAX(start_col, 0), wp->w_grid.cols, '@', '@', at_attr);
set_empty_rows(wp, srow);
wp->w_botline = lnum;
} else {
- win_draw_end(wp, '@', ' ', true, srow, wp->w_grid.Rows, HLF_AT);
+ win_draw_end(wp, '@', ' ', true, srow, wp->w_grid.rows, HLF_AT);
wp->w_botline = lnum;
}
} else {
if (eof) { // we hit the end of the file
wp->w_botline = buf->b_ml.ml_line_count + 1;
j = win_get_fill(wp, wp->w_botline);
- if (j > 0 && !wp->w_botfill && row < wp->w_grid.Rows) {
+ if (j > 0 && !wp->w_botfill && row < wp->w_grid.rows) {
// Display filler text below last line. win_line() will check
// for ml_line_count+1 and only draw filler lines
foldinfo_T info = FOLDINFO_INIT;
- row = win_line(wp, wp->w_botline, row, wp->w_grid.Rows,
+ row = win_line(wp, wp->w_botline, row, wp->w_grid.rows,
false, false, info, &line_providers);
}
} else if (dollar_vcol == -1) {
@@ -1678,7 +1665,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
// make sure the rest of the screen is blank
// write the 'eob' character to rows that aren't part of the file.
- win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.Rows,
+ win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.rows,
HLF_EOB);
}
@@ -1763,8 +1750,8 @@ static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row,
{
int nn = off + width;
- if (nn > wp->w_grid.Columns) {
- nn = wp->w_grid.Columns;
+ if (nn > wp->w_grid.cols) {
+ nn = wp->w_grid.cols;
}
if (wp->w_p_rl) {
@@ -1813,7 +1800,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, i
grid_fill(&wp->w_grid, row, endrow, W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
c1, c2, attr);
} else {
- grid_fill(&wp->w_grid, row, endrow, n, wp->w_grid.Columns, c1, c2, attr);
+ grid_fill(&wp->w_grid, row, endrow, n, wp->w_grid.cols, c1, c2, attr);
}
set_empty_rows(wp, row);
@@ -1837,7 +1824,7 @@ static int compute_foldcolumn(win_T *wp, int col)
{
int fdc = win_fdccol_count(wp);
int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
- int wwidth = wp->w_grid.Columns;
+ int wwidth = wp->w_grid.cols;
if (fdc > wwidth - (col + wmw)) {
fdc = wwidth - (col + wmw);
@@ -2621,7 +2608,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// Rightleft window: process the text in the normal direction, but put
// it in linebuf_char[off] from right to left. Start at the
// rightmost column of the window.
- col = grid->Columns - 1;
+ col = grid->cols - 1;
off += col;
}
@@ -2803,7 +2790,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_rl) {
n_extra = col + 1;
} else {
- n_extra = grid->Columns - col;
+ n_extra = grid->cols - col;
}
char_attr = 0;
} else if (filler_todo > 0) {
@@ -2818,7 +2805,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_rl) {
n_extra = col + 1;
} else {
- n_extra = grid->Columns - col;
+ n_extra = grid->cols - col;
}
char_attr = win_hl_attr(wp, HLF_DED);
}
@@ -2892,15 +2879,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& vcol >= (long)wp->w_virtcol)
|| (number_only && draw_state > WL_NR))
&& filler_todo <= 0) {
- draw_virt_text(wp, buf, win_col_offset, &col, grid->Columns, row);
- grid_put_linebuf(grid, row, 0, col, -grid->Columns, wp->w_p_rl, wp,
+ draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row);
+ grid_put_linebuf(grid, row, 0, col, -grid->cols, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
row = wp->w_cline_row + wp->w_cline_height;
} else {
- row = grid->Rows;
+ row = grid->rows;
}
break;
}
@@ -2928,19 +2915,19 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (draw_state == WL_LINE
&& has_fold
- && col < grid->Columns
+ && col < grid->cols
&& n_extra == 0
&& row == startrow) {
// fill rest of line with 'fold'
c_extra = wp->w_p_fcs_chars.fold;
c_final = NUL;
- n_extra = wp->w_p_rl ? (col + 1) : (grid->Columns - col);
+ n_extra = wp->w_p_rl ? (col + 1) : (grid->cols - col);
}
if (draw_state == WL_LINE
&& has_fold
- && col >= grid->Columns
+ && col >= grid->cols
&& n_extra != 0
&& row == startrow) {
// Truncate the folding.
@@ -3069,7 +3056,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
// If a double-width char doesn't fit display a '>' in the last column.
- if ((wp->w_p_rl ? (col <= 0) : (col >= grid->Columns - 1))
+ if ((wp->w_p_rl ? (col <= 0) : (col >= grid->cols - 1))
&& utf_char2cells(mb_c) == 2) {
c = '>';
mb_c = c;
@@ -3183,7 +3170,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// last column; the character is displayed at the start of the
// next line.
if ((wp->w_p_rl ? (col <= 0) :
- (col >= grid->Columns - 1))
+ (col >= grid->cols - 1))
&& utf_char2cells(mb_c) == 2) {
c = '>';
mb_c = c;
@@ -3388,7 +3375,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- if (c == TAB && n_extra + col > grid->Columns) {
+ if (c == TAB && n_extra + col > grid->cols) {
n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
wp->w_buffer->b_p_vts_array) - 1;
}
@@ -3591,7 +3578,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|| ((fromcol >= 0 || fromcol_prev >= 0)
&& tocol > vcol
&& VIsual_mode != Ctrl_V
- && (wp->w_p_rl ? (col >= 0) : (col < grid->Columns))
+ && (wp->w_p_rl ? (col >= 0) : (col < grid->cols))
&& !(noinvcur
&& lnum == wp->w_cursor.lnum
&& (colnr_T)vcol == wp->w_virtcol)))
@@ -3663,7 +3650,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& virtual_active()
&& tocol != MAXCOL
&& vcol < tocol
- && (wp->w_p_rl ? (col >= 0) : (col < grid->Columns))) {
+ && (wp->w_p_rl ? (col >= 0) : (col < grid->cols))) {
c = ' ';
ptr--; // put it back at the NUL
}
@@ -3745,7 +3732,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& conceal_cursor_line(wp)
&& (int)wp->w_virtcol <= vcol + n_skip) {
if (wp->w_p_rl) {
- wp->w_wcol = grid->Columns - col + boguscols - 1;
+ wp->w_wcol = grid->cols - col + boguscols - 1;
} else {
wp->w_wcol = col - boguscols;
}
@@ -3817,7 +3804,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
n = 1;
}
} else {
- if (col >= grid->Columns) {
+ if (col >= grid->cols) {
n = -1;
}
}
@@ -3885,7 +3872,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (((wp->w_p_cuc
&& (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
&& (int)wp->w_virtcol <
- (long)grid->Columns * (row - startrow + 1) + v
+ (long)grid->cols * (row - startrow + 1) + v
&& lnum != wp->w_cursor.lnum)
|| draw_color_col || line_attr_lowprio || line_attr
|| diff_hlf != (hlf_T)0 || has_virttext)) {
@@ -3923,7 +3910,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
int col_stride = wp->w_p_rl ? -1 : 1;
- while (wp->w_p_rl ? col >= 0 : col < grid->Columns) {
+ while (wp->w_p_rl ? col >= 0 : col < grid->cols) {
schar_from_ascii(linebuf_char[off], ' ');
col += col_stride;
if (draw_color_col) {
@@ -3956,7 +3943,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// terminal buffers may need to highlight beyond the end of the
// logical line
int n = wp->w_p_rl ? -1 : 1;
- while (col >= 0 && col < grid->Columns) {
+ while (col >= 0 && col < grid->cols) {
schar_from_ascii(linebuf_char[off], ' ');
linebuf_attr[off] = vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[vcol];
off += n;
@@ -3965,8 +3952,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
- draw_virt_text(wp, buf, win_col_offset, &col, grid->Columns, row);
- grid_put_linebuf(grid, row, 0, col, grid->Columns, wp->w_p_rl, wp,
+ draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row);
+ grid_put_linebuf(grid, row, 0, col, grid->cols, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
row++;
@@ -3991,7 +3978,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& wp->w_p_list
&& !wp->w_p_wrap
&& filler_todo <= 0
- && (wp->w_p_rl ? col == 0 : col == grid->Columns - 1)
+ && (wp->w_p_rl ? col == 0 : col == grid->cols - 1)
&& !has_fold
&& (*ptr != NUL
|| lcs_eol_one > 0
@@ -4181,7 +4168,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
* At end of screen line and there is more to come: Display the line
* so far. If there is no more to display it is caught above.
*/
- if ((wp->w_p_rl ? (col < 0) : (col >= grid->Columns))
+ if ((wp->w_p_rl ? (col < 0) : (col >= grid->cols))
&& foldinfo.fi_lines == 0
&& (draw_state != WL_LINE
|| *ptr != NUL
@@ -4194,7 +4181,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& filler_todo <= 0 // Not drawing diff filler lines.
&& lcs_eol_one != -1 // Haven't printed the lcs_eol character.
&& row != endrow - 1 // Not the last line being displayed.
- && (grid->Columns == Columns // Window spans the width of the screen,
+ && (grid->cols == Columns // Window spans the width of the screen,
|| ui_has(kUIMultigrid)) // or has dedicated grid.
&& !wp->w_p_rl; // Not right-to-left.
@@ -4206,13 +4193,13 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
assert(i >= 0);
int offset = kv_A(virt_lines, i).left_col ? 0 : win_col_offset;
draw_virt_text_item(buf, offset, kv_A(virt_lines, i).line,
- kHlModeReplace, grid->Columns, offset);
+ kHlModeReplace, grid->cols, offset);
}
} else {
- draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->Columns, row);
+ draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, row);
}
- grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl,
+ grid_put_linebuf(grid, row, 0, draw_col, grid->cols, wp->w_p_rl,
wp, wp->w_hl_attr_normal, wrap);
if (wrap) {
ScreenGrid *current_grid = grid;
@@ -4239,7 +4226,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// When the window is too narrow draw all "@" lines.
if (draw_state != WL_LINE && filler_todo <= 0) {
- win_draw_end(wp, '@', ' ', true, row, wp->w_grid.Rows, HLF_AT);
+ win_draw_end(wp, '@', ' ', true, row, wp->w_grid.rows, HLF_AT);
row = endrow;
}
@@ -4252,7 +4239,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
col = 0;
off = 0;
if (wp->w_p_rl) {
- col = grid->Columns - 1; // col is not used if breaking!
+ col = grid->cols - 1; // col is not used if breaking!
off += col;
}
@@ -4528,42 +4515,36 @@ void rl_mirror(char_u *str)
}
}
-/*
- * mark all status lines for redraw; used after first :cd
- */
+/// Mark all status lines and window bars for redraw; used after first :cd
void status_redraw_all(void)
{
- if (global_stl_height()) {
- curwin->w_redr_status = true;
- redraw_later(curwin, VALID);
- } else {
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_status_height) {
- wp->w_redr_status = true;
- redraw_later(wp, VALID);
- }
+ bool is_stl_global = global_stl_height() != 0;
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin)
+ || wp->w_winbar_height) {
+ wp->w_redr_status = true;
+ redraw_later(wp, VALID);
}
}
}
-/// Marks all status lines of the current buffer for redraw.
+/// Marks all status lines and window bars of the current buffer for redraw.
void status_redraw_curbuf(void)
{
status_redraw_buf(curbuf);
}
-/// Marks all status lines of the specified buffer for redraw.
+/// Marks all status lines and window bars of the given buffer for redraw.
void status_redraw_buf(buf_T *buf)
{
- if (global_stl_height() != 0 && curwin->w_buffer == buf) {
- curwin->w_redr_status = true;
- redraw_later(curwin, VALID);
- } else {
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_status_height != 0 && wp->w_buffer == buf) {
- wp->w_redr_status = true;
- redraw_later(wp, VALID);
- }
+ bool is_stl_global = global_stl_height() != 0;
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_buffer == buf && ((!is_stl_global && wp->w_status_height)
+ || (is_stl_global && wp == curwin) || wp->w_winbar_height)) {
+ wp->w_redr_status = true;
+ redraw_later(wp, VALID);
}
}
}
@@ -4575,6 +4556,7 @@ void redraw_statuslines(void)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_redr_status) {
+ win_redr_winbar(wp);
win_redr_status(wp);
}
}
@@ -5075,7 +5057,7 @@ static void redraw_custom_statusline(win_T *wp)
entered = true;
did_emsg = false;
- win_redr_custom(wp, false);
+ win_redr_custom(wp, false, false);
if (did_emsg) {
// When there is an error disable the statusline, otherwise the
// display is messed up with errors and a redraw triggers the problem
@@ -5088,6 +5070,37 @@ static void redraw_custom_statusline(win_T *wp)
entered = false;
}
+static void win_redr_winbar(win_T *wp)
+{
+ static bool entered = false;
+
+ // Return when called recursively. This can happen when the winbar contains an expression
+ // that triggers a redraw.
+ if (entered) {
+ return;
+ }
+ entered = true;
+
+ if (wp->w_winbar_height == 0 || !redrawing()) {
+ // Do nothing.
+ } else if (*p_wbr != NUL || *wp->w_p_wbr != NUL) {
+ int saved_did_emsg = did_emsg;
+
+ did_emsg = false;
+ win_redr_custom(wp, true, false);
+ if (did_emsg) {
+ // When there is an error disable the winbar, otherwise the
+ // display is messed up with errors and a redraw triggers the problem
+ // again and again.
+ set_string_option_direct("winbar", -1, (char_u *)"",
+ OPT_FREE | (*wp->w_p_stl != NUL
+ ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
+ }
+ did_emsg |= saved_did_emsg;
+ }
+ entered = false;
+}
+
/// Only call if (wp->w_vsep_width != 0).
///
/// @return true if the status line of window "wp" is connected to the status
@@ -5224,11 +5237,9 @@ bool get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len)
return buf[0] != NUL;
}
-/*
- * Redraw the status line or ruler of window "wp".
- * When "wp" is NULL redraw the tab pages line from 'tabline'.
- */
-static void win_redr_custom(win_T *wp, bool draw_ruler)
+/// Redraw the status line, window bar or ruler of window "wp".
+/// When "wp" is NULL redraw the tab pages line from 'tabline'.
+static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
{
static bool entered = false;
int attr;
@@ -5269,11 +5280,42 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
attr = HL_ATTR(HLF_TPF);
maxwidth = Columns;
use_sandbox = was_set_insecurely(wp, "tabline", 0);
+ } else if (draw_winbar) {
+ stl = (char_u *)((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr);
+ row = -1; // row zero is first row of text
+ col = 0;
+ grid = &wp->w_grid;
+ grid_adjust(&grid, &row, &col);
+
+ if (row < 0) {
+ return;
+ }
+
+ fillchar = wp->w_p_fcs_chars.wbr;
+ attr = (wp == curwin) ? HL_ATTR(HLF_WBR) : HL_ATTR(HLF_WBRNC);
+ maxwidth = wp->w_width_inner;
+ use_sandbox = was_set_insecurely(wp, "winbar", 0);
+
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ // Allocate / resize the click definitions array for winbar if needed.
+ if (wp->w_winbar_height && wp->w_winbar_click_defs_size < (size_t)maxwidth) {
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = (size_t)maxwidth;
+ wp->w_winbar_click_defs = xcalloc(wp->w_winbar_click_defs_size, sizeof(StlClickRecord));
+ }
} else {
row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
fillchar = fillchar_status(&attr, wp);
maxwidth = is_stl_global ? Columns : wp->w_width;
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ // Allocate / resize the click definitions array for statusline if needed.
+ if (wp->w_status_click_defs_size < (size_t)maxwidth) {
+ xfree(wp->w_status_click_defs);
+ wp->w_status_click_defs_size = maxwidth;
+ wp->w_status_click_defs = xcalloc(wp->w_status_click_defs_size, sizeof(StlClickRecord));
+ }
+
if (draw_ruler) {
stl = p_ruf;
// advance past any leading group spec - implicit in ru_col
@@ -5377,26 +5419,38 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
grid_puts_line_flush(false);
- if (wp == NULL) {
- // Fill the tab_page_click_defs array for clicking in the tab pages line.
- col = 0;
- len = 0;
- p = buf;
- StlClickDefinition cur_click_def = {
- .type = kStlClickDisabled,
- };
- for (n = 0; tabtab[n].start != NULL; n++) {
- len += vim_strnsize(p, (int)(tabtab[n].start - (char *)p));
- while (col < len) {
- tab_page_click_defs[col++] = cur_click_def;
- }
- p = (char_u *)tabtab[n].start;
- cur_click_def = tabtab[n].def;
+ // Fill the tab_page_click_defs, w_status_click_defs or w_winbar_click_defs array for clicking
+ // in the tab page line, status line or window bar
+ StlClickDefinition *click_defs = (wp == NULL) ? tab_page_click_defs
+ : draw_winbar ? wp->w_winbar_click_defs
+ : wp->w_status_click_defs;
+
+ if (click_defs == NULL) {
+ goto theend;
+ }
+
+ col = 0;
+ len = 0;
+ p = buf;
+ StlClickDefinition cur_click_def = {
+ .type = kStlClickDisabled,
+ };
+ for (n = 0; tabtab[n].start != NULL; n++) {
+ len += vim_strnsize(p, (int)(tabtab[n].start - (char *)p));
+ while (col < len) {
+ click_defs[col++] = cur_click_def;
}
- while (col < Columns) {
- tab_page_click_defs[col++] = cur_click_def;
+ p = (char_u *)tabtab[n].start;
+ cur_click_def = tabtab[n].def;
+ if ((wp != NULL) && !(cur_click_def.type == kStlClickDisabled
+ || cur_click_def.type == kStlClickFuncRun)) {
+ // window bar and status line only support click functions
+ cur_click_def.type = kStlClickDisabled;
}
}
+ while (col < maxwidth) {
+ click_defs[col++] = cur_click_def;
+ }
theend:
entered = false;
@@ -5504,93 +5558,13 @@ void check_for_delay(bool check_msg_scroll)
}
}
-/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
-/// Updates size, offsets and handle for the grid regardless.
-///
-/// If "doclear" is true, don't try to copy from the old grid rather clear the
-/// resized grid.
-void win_grid_alloc(win_T *wp)
-{
- ScreenGrid *grid = &wp->w_grid;
- ScreenGrid *grid_allocated = &wp->w_grid_alloc;
-
- int rows = wp->w_height_inner;
- int cols = wp->w_width_inner;
- int total_rows = wp->w_height_outer;
- int total_cols = wp->w_width_outer;
-
- bool want_allocation = ui_has(kUIMultigrid) || wp->w_floating;
- bool has_allocation = (grid_allocated->chars != NULL);
-
- if (grid->Rows != rows) {
- wp->w_lines_valid = 0;
- xfree(wp->w_lines);
- wp->w_lines = xcalloc(rows + 1, sizeof(wline_T));
- }
-
- int was_resized = false;
- if (want_allocation && (!has_allocation
- || grid_allocated->Rows != total_rows
- || grid_allocated->Columns != total_cols)) {
- grid_alloc(grid_allocated, total_rows, total_cols,
- wp->w_grid_alloc.valid, false);
- grid_allocated->valid = true;
- if (wp->w_floating && wp->w_float_config.border) {
- wp->w_redr_border = true;
- }
- was_resized = true;
- } else if (!want_allocation && has_allocation) {
- // Single grid mode, all rendering will be redirected to default_grid.
- // Only keep track of the size and offset of the window.
- grid_free(grid_allocated);
- grid_allocated->valid = false;
- was_resized = true;
- } else if (want_allocation && has_allocation && !wp->w_grid_alloc.valid) {
- grid_invalidate(grid_allocated);
- grid_allocated->valid = true;
- }
-
- grid->Rows = rows;
- grid->Columns = cols;
-
- if (want_allocation) {
- grid->target = grid_allocated;
- grid->row_offset = wp->w_border_adj[0];
- grid->col_offset = wp->w_border_adj[3];
- } else {
- grid->target = &default_grid;
- grid->row_offset = wp->w_winrow;
- grid->col_offset = wp->w_wincol;
- }
-
- // send grid resize event if:
- // - a grid was just resized
- // - screen_resize was called and all grid sizes must be sent
- // - the UI wants multigrid event (necessary)
- if ((send_grid_resize || was_resized) && want_allocation) {
- ui_call_grid_resize(grid_allocated->handle,
- grid_allocated->Columns, grid_allocated->Rows);
- }
-}
-
-/// assign a handle to the grid. The grid need not be allocated.
-void grid_assign_handle(ScreenGrid *grid)
-{
- static int last_grid_handle = DEFAULT_GRID_HANDLE;
-
- // only assign a grid handle if not already
- if (grid->handle == 0) {
- grid->handle = ++last_grid_handle;
- }
-}
-
/// Resize the screen to Rows and Columns.
///
/// Allocate default_grid.chars[] and other grid arrays.
///
/// There may be some time between setting Rows and Columns and (re)allocating
/// default_grid arrays. This happens when starting up and when
-/// (manually) changing the shell size. Always use default_grid.Rows and
+/// (manually) changing the shell size. Always use default_grid.rows and
/// default_grid.Columns to access items in default_grid.chars[]. Use Rows
/// and Columns for positioning text etc. where the final size of the shell is
/// needed.
@@ -5611,8 +5585,8 @@ retry:
// when Rows and Columns have been set and we have started doing full
// screen stuff.
if ((default_grid.chars != NULL
- && Rows == default_grid.Rows
- && Columns == default_grid.Columns
+ && Rows == default_grid.rows
+ && Columns == default_grid.cols
)
|| Rows == 0
|| Columns == 0
@@ -5652,7 +5626,7 @@ retry:
StlClickDefinition *new_tab_page_click_defs =
xcalloc((size_t)Columns, sizeof(*new_tab_page_click_defs));
- clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
xfree(tab_page_click_defs);
tab_page_click_defs = new_tab_page_click_defs;
@@ -5683,19 +5657,19 @@ retry:
resizing = false;
}
-/// Clear tab_page_click_defs table
+/// Clear status line, window bar or tab page line click definition table
///
/// @param[out] tpcd Table to clear.
/// @param[in] tpcd_size Size of the table.
-void clear_tab_page_click_defs(StlClickDefinition *const tpcd, const long tpcd_size)
+void stl_clear_click_defs(StlClickDefinition *const click_defs, const long click_defs_size)
{
- if (tpcd != NULL) {
- for (long i = 0; i < tpcd_size; i++) {
- if (i == 0 || tpcd[i].func != tpcd[i - 1].func) {
- xfree(tpcd[i].func);
+ if (click_defs != NULL) {
+ for (long i = 0; i < click_defs_size; i++) {
+ if (i == 0 || click_defs[i].func != click_defs[i - 1].func) {
+ xfree(click_defs[i].func);
}
}
- memset(tpcd, 0, (size_t)tpcd_size * sizeof(tpcd[0]));
+ memset(click_defs, 0, (size_t)click_defs_size * sizeof(click_defs[0]));
}
}
@@ -5711,9 +5685,9 @@ void screenclear(void)
}
// blank out the default grid
- for (i = 0; i < default_grid.Rows; i++) {
+ for (i = 0; i < default_grid.rows; i++) {
grid_clear_line(&default_grid, default_grid.line_offset[i],
- default_grid.Columns, true);
+ default_grid.cols, true);
default_grid.line_wraps[i] = false;
}
@@ -5797,16 +5771,16 @@ void win_scroll_lines(win_T *wp, int row, int line_count)
}
// No lines are being moved, just draw over the entire area
- if (row + abs(line_count) >= wp->w_grid.Rows) {
+ if (row + abs(line_count) >= wp->w_grid.rows) {
return;
}
if (line_count < 0) {
grid_del_lines(&wp->w_grid, row, -line_count,
- wp->w_grid.Rows, 0, wp->w_grid.Columns);
+ wp->w_grid.rows, 0, wp->w_grid.cols);
} else {
grid_ins_lines(&wp->w_grid, row, line_count,
- wp->w_grid.Rows, 0, wp->w_grid.Columns);
+ wp->w_grid.rows, 0, wp->w_grid.cols);
}
}
@@ -5845,7 +5819,7 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
// Shift line_offset[] line_count down to reflect the inserted lines.
// Clear the inserted lines.
for (i = 0; i < line_count; i++) {
- if (width != grid->Columns) {
+ if (width != grid->cols) {
// need to copy part of a line
j = end - 1 - i;
while ((j -= line_count) >= row) {
@@ -5863,7 +5837,7 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
}
grid->line_offset[j + line_count] = temp;
grid->line_wraps[j + line_count] = false;
- grid_clear_line(grid, temp, grid->Columns, false);
+ grid_clear_line(grid, temp, grid->cols, false);
}
}
@@ -5894,7 +5868,7 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
// Now shift line_offset[] line_count up to reflect the deleted lines.
// Clear the inserted lines.
for (i = 0; i < line_count; i++) {
- if (width != grid->Columns) {
+ if (width != grid->cols) {
// need to copy part of a line
j = row + i;
while ((j += line_count) <= end - 1) {
@@ -5913,7 +5887,7 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
}
grid->line_offset[j - line_count] = temp;
grid->line_wraps[j - line_count] = false;
- grid_clear_line(grid, temp, grid->Columns, false);
+ grid_clear_line(grid, temp, grid->cols, false);
}
}
@@ -6211,7 +6185,7 @@ void draw_tabline(void)
// Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
assert(Columns == tab_page_click_defs_size);
- clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
// Use the 'tabline' option if it's set.
if (*p_tal != NUL) {
@@ -6220,7 +6194,7 @@ void draw_tabline(void)
// Check for an error. If there is one we would loop in redrawing the
// screen. Avoid that by making 'tabline' empty.
did_emsg = false;
- win_redr_custom(NULL, false);
+ win_redr_custom(NULL, false, false);
if (did_emsg) {
set_string_option_direct("tabline", -1,
(char_u *)"", OPT_FREE, SID_ERROR);
@@ -6474,6 +6448,9 @@ void showruler(bool always)
} else {
win_redr_ruler(curwin, always);
}
+ if (*p_wbr != NUL || *curwin->w_p_wbr != NUL) {
+ win_redr_winbar(curwin);
+ }
if (need_maketitle
|| (p_icon && (stl_syntax & STL_IN_ICON))
@@ -6516,7 +6493,7 @@ static void win_redr_ruler(win_T *wp, bool always)
int save_called_emsg = called_emsg;
called_emsg = false;
- win_redr_custom(wp, true);
+ win_redr_custom(wp, false, true);
if (called_emsg) {
set_string_option_direct("rulerformat", -1, (char_u *)"",
OPT_FREE, SID_ERROR);
@@ -6754,11 +6731,9 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col)
/// Set dimensions of the Nvim application "shell".
void screen_resize(int width, int height)
{
- static bool recursive = false;
-
// Avoid recursiveness, can happen when setting the window size causes
// another window-changed signal.
- if (updating_screen || recursive) {
+ if (updating_screen || resizing_screen) {
return;
}
@@ -6780,7 +6755,7 @@ void screen_resize(int width, int height)
return;
}
- recursive = true;
+ resizing_screen = true;
Rows = height;
Columns = width;
@@ -6797,9 +6772,9 @@ void screen_resize(int width, int height)
send_grid_resize = true;
- /* The window layout used to be adjusted here, but it now happens in
- * screenalloc() (also invoked from screenclear()). That is because the
- * "recursive" check above may skip this, but not screenalloc(). */
+ /// The window layout used to be adjusted here, but it now happens in
+ /// screenalloc() (also invoked from screenclear()). That is because the
+ /// recursize "resizing_screen" check above may skip this, but not screenalloc().
if (State != MODE_ASKMORE && State != MODE_EXTERNCMD && State != MODE_CONFIRM) {
screenclear();
@@ -6858,7 +6833,7 @@ void screen_resize(int width, int height)
}
ui_flush();
}
- recursive = false;
+ resizing_screen = false;
}
/// Check if the new Nvim application "shell" dimensions are valid.
diff --git a/src/nvim/screen.h b/src/nvim/screen.h
index 3afbaa5eb6..0afbc24538 100644
--- a/src/nvim/screen.h
+++ b/src/nvim/screen.h
@@ -30,33 +30,23 @@ typedef enum {
// Maximum columns for terminal highlight attributes
#define TERM_ATTRS_MAX 1024
-/// Status line click definition
-typedef struct {
- enum {
- kStlClickDisabled = 0, ///< Clicks to this area are ignored.
- kStlClickTabSwitch, ///< Switch to the given tab.
- kStlClickTabClose, ///< Close given tab.
- kStlClickFuncRun, ///< Run user function.
- } type; ///< Type of the click.
- int tabnr; ///< Tab page number.
- char *func; ///< Function to run.
-} StlClickDefinition;
-
-/// Used for tabline clicks
-typedef struct {
- StlClickDefinition def; ///< Click definition.
- const char *start; ///< Location where region starts.
-} StlClickRecord;
-
/// Array defining what should be done when tabline is clicked
-extern StlClickDefinition *tab_page_click_defs;
+EXTERN StlClickDefinition *tab_page_click_defs INIT(= NULL);
/// Size of the tab_page_click_defs array
-extern long tab_page_click_defs_size;
+EXTERN long tab_page_click_defs_size INIT(= 0);
#define W_ENDCOL(wp) ((wp)->w_wincol + (wp)->w_width)
#define W_ENDROW(wp) ((wp)->w_winrow + (wp)->w_height)
+// While redrawing the screen this flag is set. It means the screen size
+// ('lines' and 'rows') must not be changed.
+EXTERN bool updating_screen INIT(= 0);
+
+// While resizing the screen this flag is set.
+EXTERN bool resizing_screen INIT(= 0);
+
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.h.generated.h"
#endif
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 11d40c058c..40c64ce41d 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -204,31 +204,6 @@ char_u *get_search_pat(void)
return mr_pattern;
}
-/*
- * Reverse text into allocated memory.
- * Returns the allocated string.
- *
- * TODO(philix): move reverse_text() to strings.c
- */
-char_u *reverse_text(char_u *s) FUNC_ATTR_NONNULL_RET
-{
- /*
- * Reverse the pattern.
- */
- size_t len = STRLEN(s);
- char_u *rev = xmalloc(len + 1);
- size_t rev_i = len;
- for (size_t s_i = 0; s_i < len; s_i++) {
- const int mb_len = utfc_ptr2len((char *)s + s_i);
- rev_i -= mb_len;
- memmove(rev + rev_i, s + s_i, mb_len);
- s_i += mb_len - 1;
- }
- rev[len] = NUL;
-
- return rev;
-}
-
void save_re_pat(int idx, char_u *pat, int magic)
{
if (spats[idx].pat != pat) {
@@ -1990,13 +1965,13 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
clearpos(&match_pos);
// backward search: Check if this line contains a single-line comment
- if ((backwards && comment_dir)
- || lisp) {
+ if ((backwards && comment_dir) || lisp) {
comment_col = check_linecomment(linep);
}
if (lisp && comment_col != MAXCOL && pos.col > (colnr_T)comment_col) {
lispcomm = true; // find match inside this comment
}
+
while (!got_int) {
/*
* Go to the next position, forward or backward. We could use
@@ -2023,8 +1998,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
line_breakcheck();
// Check if this line contains a single-line comment
- if (comment_dir
- || lisp) {
+ if (comment_dir || lisp) {
comment_col = check_linecomment(linep);
}
// skip comment
@@ -2038,7 +2012,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
} else { // forward search
if (linep[pos.col] == NUL
// at end of line, go to next one
- // don't search for match in comment
+ // For lisp don't search for match in comment
|| (lisp && comment_col != MAXCOL
&& pos.col == (colnr_T)comment_col)) {
if (pos.lnum == curbuf->b_ml.ml_line_count // end of file
@@ -2348,8 +2322,8 @@ int check_linecomment(const char_u *line)
} else {
while ((p = (char_u *)vim_strchr((char *)p, '/')) != NULL) {
// Accept a double /, unless it's preceded with * and followed by *,
- // because * / / * is an end and start of a C comment.
- // Only accept the position if it is not inside a string.
+ // because * / / * is an end and start of a C comment. Only
+ // accept the position if it is not inside a string.
if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*')
&& !is_pos_in_string(line, (colnr_T)(p - line))) {
break;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 1ba29e3fc1..df3ee73a28 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -443,7 +443,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou
MAXWLEN + 1);
mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
- if (camel_case) {
+ if (camel_case && mi.mi_fwordlen > 0) {
// introduce a fake word end space into the folded word.
mi.mi_fword[mi.mi_fwordlen - 1] = ' ';
}
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index c0c942ffd2..999e6801fb 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -634,12 +634,12 @@ static const void *tv_ptr(const typval_T *const tvs, int *const idxp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
#define OFF(attr) offsetof(union typval_vval_union, attr)
- STATIC_ASSERT(OFF(v_string) == OFF(v_list)
+ STATIC_ASSERT(OFF(v_string) == OFF(v_list) // -V568
&& OFF(v_string) == OFF(v_dict)
&& OFF(v_string) == OFF(v_partial)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list) // -V568
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict) // -V568
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial), // -V568
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial),
"Strings, dictionaries, lists and partials are expected to be pointers, "
"so that all three of them can be accessed via v_string");
#undef OFF
@@ -1496,6 +1496,7 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...)
// printed string didn't fit, resize and try again
if ((size_t)printed >= remaining) {
kv_ensure_space(*str, (size_t)printed + 1); // include space for NUL terminator at the end
+ assert(str->items != NULL);
va_start(ap, fmt);
printed = vsnprintf(str->items + str->size, str->capacity - str->size, fmt, ap);
va_end(ap);
@@ -1507,3 +1508,24 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...)
str->size += (size_t)printed;
return printed;
}
+
+/// Reverse text into allocated memory.
+///
+/// @return the allocated string.
+char_u *reverse_text(char_u *s)
+ FUNC_ATTR_NONNULL_RET
+{
+ // Reverse the pattern.
+ size_t len = STRLEN(s);
+ char_u *rev = xmalloc(len + 1);
+ size_t rev_i = len;
+ for (size_t s_i = 0; s_i < len; s_i++) {
+ const int mb_len = utfc_ptr2len((char *)s + s_i);
+ rev_i -= (size_t)mb_len;
+ memmove(rev + rev_i, s + s_i, (size_t)mb_len);
+ s_i += (size_t)mb_len - 1;
+ }
+ rev[len] = NUL;
+
+ return rev;
+}
diff --git a/src/nvim/strings.h b/src/nvim/strings.h
index 0503cecc8a..9ef1eb5816 100644
--- a/src/nvim/strings.h
+++ b/src/nvim/strings.h
@@ -6,8 +6,8 @@
#include <string.h>
#include "nvim/eval/typval.h"
-#include "nvim/types.h"
#include "nvim/lib/kvec.h"
+#include "nvim/types.h"
/// Append string to string and return pointer to the next byte
///
diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim
index 765ae17736..ffb8e3facd 100644
--- a/src/nvim/testdir/test_bufline.vim
+++ b/src/nvim/testdir/test_bufline.vim
@@ -153,3 +153,38 @@ func Test_appendbufline_redraw()
call StopVimInTerminal(buf)
call delete('XscriptMatchCommon')
endfunc
+
+func Test_setbufline_select_mode()
+ new
+ call setline(1, ['foo', 'bar'])
+ call feedkeys("j^v2l\<C-G>", 'nx')
+
+ let bufnr = bufadd('Xdummy')
+ call bufload(bufnr)
+ call setbufline(bufnr, 1, ['abc'])
+
+ call feedkeys("x", 'nx')
+ call assert_equal(['foo', 'x'], getline(1, 2))
+
+ exe "bwipe! " .. bufnr
+ bwipe!
+endfunc
+
+func Test_deletebufline_select_mode()
+ new
+ call setline(1, ['foo', 'bar'])
+ call feedkeys("j^v2l\<C-G>", 'nx')
+
+ let bufnr = bufadd('Xdummy')
+ call bufload(bufnr)
+ call setbufline(bufnr, 1, ['abc', 'def'])
+ call deletebufline(bufnr, 1)
+
+ call feedkeys("x", 'nx')
+ call assert_equal(['foo', 'x'], getline(1, 2))
+
+ exe "bwipe! " .. bufnr
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 759caac878..b2c752376f 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -1224,4 +1224,16 @@ func Test_screenpos_and_completion()
call feedkeys(":let a\<C-R>=Check_completion()\<CR>\<Esc>", "xt")
endfunc
+func Test_recursive_register()
+ let @= = ''
+ silent! ?e/
+ let caught = 'no'
+ try
+ normal //
+ catch /E169:/
+ let caught = 'yes'
+ endtry
+ call assert_equal('yes', caught)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index 9ba82e3b70..6c6a6290cb 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -102,10 +102,11 @@ func Test_screenpos()
bwipe!
call assert_equal({'col': 1, 'row': 1, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
- " Needs WinBar
" nmenu WinBar.TEST :
- " call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+ setlocal winbar=TEST
+ call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
" nunmenu WinBar.TEST
+ setlocal winbar&
endfunc
func Test_screenpos_number()
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 848666727f..275c8f7a15 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -16,8 +16,9 @@ func Test_edit_00b()
call setline(1, ['abc '])
inoreabbr <buffer> h here some more
call cursor(1, 4)
- " <c-l> expands the abbreviation and ends insertmode
- call feedkeys(":set im\<cr> h\<c-l>:set noim\<cr>", 'tix')
+ " <esc> expands the abbreviation and ends insert mode
+ " call feedkeys(":set im\<cr> h\<c-l>:set noim\<cr>", 'tix')
+ call feedkeys("i h\<esc>", 'tix')
call assert_equal(['abc here some more '], getline(1,'$'))
iunabbr <buffer> h
bw!
@@ -234,15 +235,18 @@ func Test_edit_09()
call setline(1, ['abc', 'def', 'ghi'])
call cursor(1, 1)
" 1) CTRL-\ CTLR-N
- call feedkeys(":set im\<cr>\<c-\>\<c-n>ccABC\<c-l>", 'txin')
+ " call feedkeys(":set im\<cr>\<c-\>\<c-n>ccABC\<c-l>", 'txin')
+ call feedkeys("i\<c-\>\<c-n>ccABC\<esc>", 'txin')
call assert_equal(['ABC', 'def', 'ghi'], getline(1,'$'))
call setline(1, ['ABC', 'def', 'ghi'])
" 2) CTRL-\ CTLR-G
- call feedkeys("j0\<c-\>\<c-g>ZZZ\<cr>\<c-l>", 'txin')
- call assert_equal(['ABC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
- call feedkeys("I\<c-\>\<c-g>YYY\<c-l>", 'txin')
- call assert_equal(['ABC', 'ZZZ', 'YYYdef', 'ghi'], getline(1,'$'))
- set noinsertmode
+ " CTRL-\ CTRL-G goes to Insert mode when 'insertmode' is set, but
+ " 'insertmode' is now removed so skip this test
+ " call feedkeys("j0\<c-\>\<c-g>ZZZ\<cr>\<esc>", 'txin')
+ " call assert_equal(['ABC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ " call feedkeys("I\<c-\>\<c-g>YYY\<c-l>", 'txin')
+ " call assert_equal(['ABC', 'ZZZ', 'YYYdef', 'ghi'], getline(1,'$'))
+ " set noinsertmode
" 3) CTRL-\ CTRL-O
call setline(1, ['ABC', 'ZZZ', 'def', 'ghi'])
call cursor(1, 1)
@@ -395,15 +399,13 @@ endfunc
func Test_edit_13()
" Test smartindenting
- if exists("+smartindent")
- new
- set smartindent autoindent
- call setline(1, ["\tabc"])
- call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
- call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
- set smartindent& autoindent&
- bwipe!
- endif
+ new
+ set smartindent autoindent
+ call setline(1, ["\tabc"])
+ call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
+ call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
+ set smartindent& autoindent&
+ bwipe!
" Test autoindent removing indent of blank line.
new
@@ -1045,7 +1047,8 @@ endfunc
func Test_edit_F1()
" Pressing <f1>
new
- call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix')
+ " call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix')
+ call feedkeys("i\<f1>\<esc>", 'tnix')
set noinsertmode
call assert_equal('help', &buftype)
bw
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index c0c35b89cb..9eccb4babd 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -77,16 +77,16 @@ let s:filename_checks = {
\ 'awk': ['file.awk', 'file.gawk'],
\ 'b': ['file.mch', 'file.ref', 'file.imp'],
\ 'basic': ['file.bas', 'file.bi', 'file.bm'],
- \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
\ 'bc': ['file.bc'],
\ 'bdf': ['file.bdf'],
+ \ 'beancount': ['file.beancount'],
\ 'bib': ['file.bib'],
\ 'bicep': ['file.bicep'],
- \ 'beancount': ['file.beancount'],
\ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'],
\ 'blank': ['file.bl'],
\ 'bsdl': ['file.bsd', 'file.bsdl', 'bsd', 'some-bsd'],
\ 'bst': ['file.bst'],
+ \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
\ 'bzr': ['bzr_log.any', 'bzr_log.file'],
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c', 'some-enlightenment/file.cfg'],
\ 'cabal': ['file.cabal'],
@@ -109,6 +109,7 @@ let s:filename_checks = {
\ 'clean': ['file.dcl', 'file.icl'],
\ 'clojure': ['file.clj', 'file.cljs', 'file.cljx', 'file.cljc'],
\ 'cmake': ['CMakeLists.txt', 'file.cmake', 'file.cmake.in'],
+ \ 'cmod': ['file.cmod'],
\ 'cmusrc': ['any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme', '/.cmus/autosave', '/.cmus/command-history', '/.cmus/file.theme', '/.cmus/rc', '/cmus/file.theme', '/cmus/rc'],
\ 'cobol': ['file.cbl', 'file.cob', 'file.lib'],
\ 'coco': ['file.atg'],
@@ -164,9 +165,9 @@ let s:filename_checks = {
\ 'dylanlid': ['file.lid'],
\ 'ecd': ['file.ecd'],
\ 'edif': ['file.edf', 'file.edif', 'file.edo'],
+ \ 'eelixir': ['file.eex', 'file.leex'],
\ 'elinks': ['elinks.conf'],
\ 'elixir': ['file.ex', 'file.exs', 'mix.lock'],
- \ 'eelixir': ['file.eex', 'file.leex'],
\ 'elm': ['file.elm'],
\ 'elmfilt': ['filter-rules'],
\ 'elvish': ['file.elv'],
@@ -199,9 +200,9 @@ let s:filename_checks = {
\ 'fusion': ['file.fusion'],
\ 'fvwm': ['/.fvwm/file', 'any/.fvwm/file'],
\ 'gdb': ['.gdbinit', 'gdbinit', 'file.gdb', '.config/gdbearlyinit', '.gdbearlyinit'],
+ \ 'gdmo': ['file.mo', 'file.gdmo'],
\ 'gdresource': ['file.tscn', 'file.tres'],
\ 'gdscript': ['file.gd'],
- \ 'gdmo': ['file.mo', 'file.gdmo'],
\ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'],
\ 'gemtext': ['file.gmi', 'file.gemini'],
\ 'gift': ['file.gift'],
@@ -237,8 +238,8 @@ let s:filename_checks = {
\ 'hastepreproc': ['file.htpp'],
\ 'hb': ['file.hb'],
\ 'hcl': ['file.hcl'],
- \ 'hercules': ['file.vc', 'file.ev', 'file.sum', 'file.errsum'],
\ 'heex': ['file.heex'],
+ \ 'hercules': ['file.vc', 'file.ev', 'file.sum', 'file.errsum'],
\ 'hex': ['file.hex', 'file.h32'],
\ 'hgcommit': ['hg-editor-file.txt'],
\ 'hjson': ['file.hjson'],
@@ -246,22 +247,10 @@ let s:filename_checks = {
\ 'hollywood': ['file.hws'],
\ 'hostconf': ['/etc/host.conf', 'any/etc/host.conf'],
\ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'],
- \ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
- \ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
- \ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig'],
- \ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
- \ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'],
- \ 'opl': ['file.OPL', 'file.OPl', 'file.OpL', 'file.Opl', 'file.oPL', 'file.oPl', 'file.opL', 'file.opl'],
- \ 'pcmk': ['file.pcmk'],
- \ 'r': ['file.r'],
- \ 'rhelp': ['file.rd'],
- \ 'rmd': ['file.rmd', 'file.smd'],
- \ 'rnoweb': ['file.rnw', 'file.snw'],
- \ 'rrst': ['file.rrst', 'file.srst'],
- \ 'template': ['file.tmpl'],
\ 'html': ['file.html', 'file.htm', 'file.cshtml'],
\ 'htmlm4': ['file.html.m4'],
\ 'httest': ['file.htt', 'file.htb'],
+ \ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
\ 'ibasic': ['file.iba', 'file.ibi'],
\ 'icemenu': ['/.icewm/menu', 'any/.icewm/menu'],
\ 'icon': ['file.icn'],
@@ -314,17 +303,18 @@ let s:filename_checks = {
\ 'lisp': ['file.lsp', 'file.lisp', 'file.asd', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'],
\ 'lite': ['file.lite', 'file.lt'],
\ 'litestep': ['/LiteStep/any/file.rc', 'any/LiteStep/any/file.rc'],
+ \ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
\ 'loginaccess': ['/etc/login.access', 'any/etc/login.access'],
\ 'logindefs': ['/etc/login.defs', 'any/etc/login.defs'],
\ 'logtalk': ['file.lgt'],
\ 'lotos': ['file.lot', 'file.lotos'],
\ 'lout': ['file.lou', 'file.lout'],
+ \ 'lpc': ['file.lpc', 'file.ulpc'],
\ 'lprolog': ['file.sig'],
\ 'lsl': ['file.lsl'],
\ 'lss': ['file.lss'],
\ 'lua': ['file.lua', 'file.rockspec', 'file.nse'],
\ 'lynx': ['lynx.cfg'],
- \ 'matlab': ['file.m'],
\ 'm3build': ['m3makefile', 'm3overrides'],
\ 'm3quake': ['file.quake', 'cm3.cfg'],
\ 'm4': ['file.at'],
@@ -339,6 +329,7 @@ let s:filename_checks = {
\ 'markdown': ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'],
\ 'mason': ['file.mason', 'file.mhtml', 'file.comp'],
\ 'master': ['file.mas', 'file.master'],
+ \ 'matlab': ['file.m'],
\ 'maxima': ['file.demo', 'file.dmt', 'file.dm1', 'file.dm2', 'file.dm3',
\ 'file.wxm', 'maxima-init.mac'],
\ 'mel': ['file.mel'],
@@ -359,6 +350,7 @@ let s:filename_checks = {
\ 'mmp': ['file.mmp'],
\ 'modconf': ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'],
\ 'modula2': ['file.m2', 'file.mi'],
+ \ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig'],
\ 'monk': ['file.isc', 'file.monk', 'file.ssc', 'file.tsc'],
\ 'moo': ['file.moo'],
\ 'mp': ['file.mp'],
@@ -373,7 +365,9 @@ let s:filename_checks = {
\ 'n1ql': ['file.n1ql', 'file.nql'],
\ 'named': ['namedfile.conf', 'rndcfile.conf', 'named-file.conf', 'named.conf', 'rndc-file.conf', 'rndc-file.key', 'rndc.conf', 'rndc.key'],
\ 'nanorc': ['/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'],
+ \ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
\ 'ncf': ['file.ncf'],
+ \ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'],
\ 'netrc': ['.netrc'],
\ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'],
\ 'ninja': ['file.ninja'],
@@ -389,6 +383,7 @@ let s:filename_checks = {
\ 'opam': ['opam', 'file.opam', 'file.opam.template'],
\ 'openroad': ['file.or'],
\ 'openscad': ['file.scad'],
+ \ 'opl': ['file.OPL', 'file.OPl', 'file.OpL', 'file.Opl', 'file.oPL', 'file.oPl', 'file.opL', 'file.opl'],
\ 'ora': ['file.ora'],
\ 'org': ['file.org', 'file.org_archive'],
\ 'pamconf': ['/etc/pam.conf', '/etc/pam.d/file', 'any/etc/pam.conf', 'any/etc/pam.d/file'],
@@ -398,14 +393,13 @@ let s:filename_checks = {
\ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak', '/etc/passwd', '/etc/passwd-', '/etc/passwd.edit', '/etc/shadow', '/etc/shadow-', '/etc/shadow.edit', '/var/backups/passwd.bak', '/var/backups/shadow.bak'],
\ 'pbtxt': ['file.pbtxt'],
\ 'pccts': ['file.g'],
+ \ 'pcmk': ['file.pcmk'],
\ 'pdf': ['file.pdf'],
\ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'],
\ 'pf': ['pf.conf'],
\ 'pfmain': ['main.cf'],
\ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt'],
- \ 'lpc': ['file.lpc', 'file.ulpc'],
\ 'pike': ['file.pike', 'file.pmod'],
- \ 'cmod': ['file.cmod'],
\ 'pilrc': ['file.rcp'],
\ 'pine': ['.pinerc', 'pinerc', '.pinercex', 'pinercex'],
\ 'pinfo': ['/etc/pinforc', '/.pinforc', 'any/.pinforc', 'any/etc/pinforc'],
@@ -421,8 +415,8 @@ let s:filename_checks = {
\ 'povini': ['.povrayrc'],
\ 'ppd': ['file.ppd'],
\ 'ppwiz': ['file.it', 'file.ih'],
- \ 'privoxy': ['file.action'],
\ 'prisma': ['file.prisma'],
+ \ 'privoxy': ['file.action'],
\ 'proc': ['file.pc'],
\ 'procmail': ['.procmail', '.procmailrc'],
\ 'prolog': ['file.pdb'],
@@ -440,27 +434,33 @@ let s:filename_checks = {
\ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'],
\ 'ql': ['file.ql', 'file.qll'],
\ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg', 'baseq2/file.cfg', 'id1/file.cfg', 'quake1/file.cfg', 'some-baseq2/file.cfg', 'some-id1/file.cfg', 'some-quake1/file.cfg'],
+ \ 'r': ['file.r'],
\ 'radiance': ['file.rad', 'file.mat'],
\ 'raku': ['file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'],
+ \ 'raml': ['file.raml'],
\ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'],
\ 'rbs': ['file.rbs'],
\ 'rc': ['file.rc', 'file.rch'],
\ 'rcs': ['file,v'],
\ 'readline': ['.inputrc', 'inputrc'],
- \ 'remind': ['.reminders', 'file.remind', 'file.rem', '.reminders-file'],
\ 'rego': ['file.rego'],
+ \ 'remind': ['.reminders', 'file.remind', 'file.rem', '.reminders-file'],
\ 'rescript': ['file.res', 'file.resi'],
\ 'resolv': ['resolv.conf'],
\ 'reva': ['file.frt'],
\ 'rexx': ['file.rex', 'file.orx', 'file.rxo', 'file.rxj', 'file.jrexx', 'file.rexxj', 'file.rexx', 'file.testGroup', 'file.testUnit'],
+ \ 'rhelp': ['file.rd'],
\ 'rib': ['file.rib'],
+ \ 'rmd': ['file.rmd', 'file.smd'],
\ 'rnc': ['file.rnc'],
\ 'rng': ['file.rng'],
+ \ 'rnoweb': ['file.rnw', 'file.snw'],
\ 'robot': ['file.robot', 'file.resource'],
\ 'robots': ['robots.txt'],
\ 'routeros': ['file.rsc'],
\ 'rpcgen': ['file.x'],
\ 'rpl': ['file.rpl'],
+ \ 'rrst': ['file.rrst', 'file.srst'],
\ 'rst': ['file.rst'],
\ 'rtf': ['file.rtf'],
\ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile', 'Vagrantfile'],
@@ -474,7 +474,6 @@ let s:filename_checks = {
\ 'scheme': ['file.scm', 'file.ss', 'file.sld', 'file.rkt', 'file.rktd', 'file.rktl'],
\ 'scilab': ['file.sci', 'file.sce'],
\ 'screen': ['.screenrc', 'screenrc'],
- \ 'sexplib': ['file.sexp'],
\ 'scss': ['file.scss'],
\ 'sd': ['file.sd'],
\ 'sdc': ['file.sdc'],
@@ -483,28 +482,29 @@ let s:filename_checks = {
\ 'sensors': ['/etc/sensors.conf', '/etc/sensors3.conf', '/etc/sensors.d/file', 'any/etc/sensors.conf', 'any/etc/sensors3.conf', 'any/etc/sensors.d/file'],
\ 'services': ['/etc/services', 'any/etc/services'],
\ 'setserial': ['/etc/serial.conf', 'any/etc/serial.conf'],
+ \ 'sexplib': ['file.sexp'],
\ 'sh': ['.bashrc', 'file.bash', '/usr/share/doc/bash-completion/filter.sh','/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf'],
\ 'sieve': ['file.siv', 'file.sieve'],
+ \ 'sil': ['file.sil'],
\ 'simula': ['file.sim'],
\ 'sinda': ['file.sin', 'file.s85'],
\ 'sisu': ['file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'],
\ 'skill': ['file.il', 'file.ils', 'file.cdf'],
\ 'slang': ['file.sl'],
\ 'slice': ['file.ice'],
- \ 'solidity': ['file.sol'],
- \ 'solution': ['file.sln'],
\ 'slpconf': ['/etc/slp.conf', 'any/etc/slp.conf'],
\ 'slpreg': ['/etc/slp.reg', 'any/etc/slp.reg'],
\ 'slpspi': ['/etc/slp.spi', 'any/etc/slp.spi'],
\ 'slrnrc': ['.slrnrc'],
\ 'slrnsc': ['file.score'],
\ 'sm': ['sendmail.cf'],
- \ 'svelte': ['file.svelte'],
\ 'smarty': ['file.tpl'],
\ 'smcl': ['file.hlp', 'file.ihlp', 'file.smcl'],
\ 'smith': ['file.smt', 'file.smith'],
\ 'sml': ['file.sml'],
\ 'snobol4': ['file.sno', 'file.spt'],
+ \ 'solidity': ['file.sol'],
+ \ 'solution': ['file.sln'],
\ 'sparql': ['file.rq', 'file.sparql'],
\ 'spec': ['file.spec'],
\ 'spice': ['file.sp', 'file.spice'],
@@ -524,11 +524,11 @@ let s:filename_checks = {
\ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'],
\ 'supercollider': ['file.quark'],
\ 'surface': ['file.sface'],
+ \ 'svelte': ['file.svelte'],
\ 'svg': ['file.svg'],
\ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'],
\ 'swift': ['file.swift'],
\ 'swiftgyb': ['file.swift.gyb'],
- \ 'sil': ['file.sil'],
\ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf', 'any/etc/sysctl.conf', 'any/etc/sysctl.d/file.conf'],
\ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.dnssd', 'any/systemd/file.link', 'any/systemd/file.mount', 'any/systemd/file.netdev', 'any/systemd/file.network', 'any/systemd/file.nspawn', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.slice', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/some.conf.d/file.conf', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/etc/systemd/system/.#otherfile', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file', '/home/user/.config/systemd/user/.#otherfile', '/.config/systemd/user/.#', '/.config/systemd/user/.#-file', '/.config/systemd/user/file.d/.#', '/.config/systemd/user/file.d/.#-file', '/.config/systemd/user/file.d/file.conf', '/etc/systemd/file.conf.d/file.conf', '/etc/systemd/system/.#', '/etc/systemd/system/.#-file', '/etc/systemd/system/file.d/.#', '/etc/systemd/system/file.d/.#-file', '/etc/systemd/system/file.d/file.conf', '/systemd/file.automount', '/systemd/file.dnssd', '/systemd/file.link', '/systemd/file.mount', '/systemd/file.netdev', '/systemd/file.network', '/systemd/file.nspawn', '/systemd/file.path', '/systemd/file.service', '/systemd/file.slice', '/systemd/file.socket', '/systemd/file.swap', '/systemd/file.target', '/systemd/file.timer', 'any/.config/systemd/user/.#', 'any/.config/systemd/user/.#-file', 'any/.config/systemd/user/file.d/.#', 'any/.config/systemd/user/file.d/.#-file', 'any/.config/systemd/user/file.d/file.conf', 'any/etc/systemd/file.conf.d/file.conf', 'any/etc/systemd/system/.#', 'any/etc/systemd/system/.#-file', 'any/etc/systemd/system/file.d/.#', 'any/etc/systemd/system/file.d/.#-file', 'any/etc/systemd/system/file.d/file.conf'],
\ 'systemverilog': ['file.sv', 'file.svh'],
@@ -538,6 +538,7 @@ let s:filename_checks = {
\ 'taskedit': ['file.task'],
\ 'tcl': ['file.tcl', 'file.tm', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl', '.tclshrc', 'tclsh.rc', '.wishrc'],
\ 'teal': ['file.tl'],
+ \ 'template': ['file.tmpl'],
\ 'teraterm': ['file.ttl'],
\ 'terminfo': ['file.ti'],
\ 'terraform': ['file.tfvars'],
@@ -574,8 +575,8 @@ let s:filename_checks = {
\ 'upstreamlog': ['fdrupstream.log', 'upstream.log', 'UPSTREAM.LOG', 'upstream.file.log', 'UPSTREAM.FILE.LOG', 'file.upstream.log', 'FILE.UPSTREAM.LOG', 'UPSTREAM-file.log', 'UPSTREAM-FILE.LOG'],
\ 'usserverlog': ['usserver.log', 'USSERVER.LOG', 'usserver.file.log', 'USSERVER.FILE.LOG', 'file.usserver.log', 'FILE.USSERVER.LOG'],
\ 'usw2kagtlog': ['usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'],
- \ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'],
\ 'vala': ['file.vala'],
+ \ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'],
\ 'vera': ['file.vr', 'file.vri', 'file.vrh'],
\ 'verilog': ['file.v'],
\ 'verilogams': ['file.va', 'file.vams'],
@@ -598,12 +599,12 @@ let s:filename_checks = {
\ 'wsml': ['file.wsml'],
\ 'wvdial': ['wvdial.conf', '.wvdialrc'],
\ 'xdefaults': ['.Xdefaults', '.Xpdefaults', '.Xresources', 'xdm-config', 'file.ad', '/Xresources/file', '/app-defaults/file', 'Xresources', 'Xresources-file', 'any/Xresources/file', 'any/app-defaults/file'],
+ \ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
\ 'xhtml': ['file.xhtml', 'file.xht'],
\ 'xinetd': ['/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'],
\ 'xmath': ['file.msc', 'file.msf'],
\ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd'],
\ 'xmodmap': ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'],
- \ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
\ 'xpm': ['file.xpm'],
\ 'xpm2': ['file.xpm2'],
\ 'xquery': ['file.xq', 'file.xql', 'file.xqm', 'file.xquery', 'file.xqy'],
@@ -613,7 +614,6 @@ let s:filename_checks = {
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
\ 'yaml': ['file.yaml', 'file.yml'],
\ 'yang': ['file.yang'],
- \ 'raml': ['file.raml'],
\ 'z8a': ['file.z8a'],
\ 'zig': ['file.zig'],
\ 'zimbu': ['file.zu'],
@@ -843,6 +843,7 @@ func Test_cfg_file()
let ext = substitute(ext, '\(\l\)', '\u\1', '')
endfor
+ " clean up
filetype off
endfunc
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 9f5ad53adb..327f0f73f2 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -217,6 +217,26 @@ func Test_update_folds_expr_read()
set foldmethod& foldexpr&
endfunc
+" Test for what patch 8.1.0535 fixes.
+func Test_foldexpr_no_interrupt_addsub()
+ new
+ func! FoldFunc()
+ call setpos('.', getcurpos())
+ return '='
+ endfunc
+
+ set foldmethod=expr
+ set foldexpr=FoldFunc()
+ call setline(1, '1.2')
+
+ exe "norm! $\<C-A>"
+ call assert_equal('1.3', getline(1))
+
+ bwipe!
+ delfunc FoldFunc
+ set foldmethod& foldexpr&
+endfunc
+
func Check_foldlevels(expected)
call assert_equal(a:expected, map(range(1, line('$')), 'foldlevel(v:val)'))
endfunc
@@ -901,4 +921,72 @@ func Test_fold_split()
bw!
endfunc
+" Make sure that when you append under a blank line that is under a fold with
+" the same indent level as your appended line, the fold expands across the
+" blank line
+func Test_indent_append_under_blank_line()
+ new
+ let lines =<< trim END
+ line 1
+ line 2
+ line 3
+ END
+ call setline(1, lines)
+ setlocal sw=2
+ setlocal foldmethod=indent foldenable
+ call assert_equal([0, 1, 1], range(1, 3)->map('foldlevel(v:val)'))
+ call append(3, '')
+ call append(4, ' line 5')
+ call assert_equal([0, 1, 1, 1, 1], range(1, 5)->map('foldlevel(v:val)'))
+ bw!
+endfunc
+
+" Make sure that when you delete 1 line of a fold whose length is 2 lines, the
+" fold can't be closed since its length (1) is now less than foldminlines.
+func Test_indent_one_line_fold_close()
+ let lines =<< trim END
+ line 1
+ line 2
+ line 3
+ END
+
+ new
+ setlocal sw=2 foldmethod=indent
+ call setline(1, lines)
+ " open all folds, delete line, then close all folds
+ normal zR
+ 3delete
+ normal zM
+ call assert_equal(-1, foldclosed(2)) " the fold should not be closed
+
+ " Now do the same, but delete line 2 this time; this covers different code.
+ " (Combining this code with the above code doesn't expose both bugs.)
+ 1,$delete
+ call setline(1, lines)
+ normal zR
+ 2delete
+ normal zM
+ call assert_equal(-1, foldclosed(2))
+ bw!
+endfunc
+
+" Make sure that when appending [an indented line then a blank line] right
+" before a single indented line, the resulting extended fold can be closed
+func Test_indent_append_blank_small_fold_close()
+ new
+ setlocal sw=2 foldmethod=indent
+ " at first, the fold at the second line can't be closed since it's smaller
+ " than foldminlines
+ let lines =<< trim END
+ line 1
+ line 4
+ END
+ call setline(1, lines)
+ call append(1, [' line 2', ''])
+ " close all folds
+ normal zM
+ call assert_notequal(-1, foldclosed(2)) " the fold should be closed now
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 5dbe2cd366..c55ba391a5 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -838,6 +838,30 @@ func Test_mksession_shortmess()
set sessionoptions&
endfunc
+" Test that when Vim loading session has 'A' in 'shortmess' it does not
+" complain about an existing swapfile.
+func Test_mksession_shortmess_with_A()
+ edit Xtestfile
+ write
+ let fname = swapname('%')
+ " readblob() needs patch 8.2.2343
+ " let cont = readblob(fname)
+ let cont = readfile(fname, 'B')
+ set sessionoptions-=options
+ mksession Xtestsession
+ bwipe!
+
+ " Recreate the swap file to pretend the file is being edited
+ call writefile(cont, fname)
+ set shortmess+=A
+ source Xtestsession
+
+ set shortmess&
+ set sessionoptions&
+ call delete('Xtestsession')
+ call delete(fname)
+endfunc
+
" Test for mksession with 'compatible' option
func Test_mksession_compatible()
throw 'skipped: Nvim does not support "compatible" option'
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 1feffe1f8c..d1cb89bbd4 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -133,7 +133,8 @@ func Test_normal02_selectmode2()
" some basic select mode tests
call Setup_NewWindow()
50
- call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
+ " call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
+ call feedkeys("i\<c-o>gHc\<esc>", 'tx')
call assert_equal('c51', getline('.'))
" clean up
bw!
@@ -2113,11 +2114,11 @@ fun! Test_normal40_ctrl_bsl()
call assert_equal('n', mode())
call assert_equal(1, col('.'))
"imap <buffer> , <c-\><c-n>
- set im
+ " set im
exe ":norm! \<c-\>\<c-n>dw"
- set noim
+ " set noim
call assert_equal('are some words', getline(1))
- call assert_false(&insertmode)
+ " call assert_false(&insertmode)
" clean up
bw!
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index e0b05edf15..2fe3c448d6 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -1077,6 +1077,15 @@ Type number and <Enter> (q or empty cancels):
%bwipe
endfunc
+func Test_define_search()
+ " this was accessing freed memory
+ new
+ call setline(1, ['first line', '', '#define something 0'])
+ sil norm o0
+ sil! norm 
+ bwipe!
+endfunc
+
" Test for the 'taglength' option
func Test_tag_length()
set tags=Xtags
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index 92705cb69f..748af199b2 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -289,11 +289,28 @@ func Test_format_c_comment()
x
END
call assert_equal(expected, getline(1, '$'))
+
+ " Comment is formatted when it wraps
+ normal 2GA with some more text added
+ let expected =<< trim END
+ nop;
+ val = val; // This is a comment
+ // with some more text
+ // added
+ x
+ END
+ call assert_equal(expected, getline(1, '$'))
+
set fo-=/
" using 'indentexpr' instead of 'cindent' does not repeat a comment
setl nocindent indentexpr=2
- 3delete
+ %del
+ let text =<< trim END
+ nop;
+ val = val; // This is a comment
+ END
+ call setline(1, text)
normal 2Gox
let expected =<< trim END
nop;
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 9e2d1f8e68..01583c032f 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -436,7 +436,7 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active)
void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, int clearattr,
bool wrap)
{
- assert(0 <= row && row < grid->Rows);
+ assert(0 <= row && row < grid->rows);
LineFlags flags = wrap ? kLineFlagWrap : 0;
if (startcol == -1) {
startcol = 0;
@@ -453,7 +453,7 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
if (p_wd && !(rdb_flags & RDB_COMPOSITOR)) {
// If 'writedelay' is active, set the cursor to indicate what was drawn.
ui_call_grid_cursor_goto(grid->handle, row,
- MIN(clearcol, (int)grid->Columns - 1));
+ MIN(clearcol, (int)grid->cols - 1));
ui_call_flush();
uint64_t wd = (uint64_t)labs(p_wd);
os_microdelay(wd * 1000u, true);
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index f76158ff12..1dce84a1de 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -138,19 +138,19 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
// use it.
grid->comp_disabled = true;
compose_area(grid->comp_row, row,
- grid->comp_col, grid->comp_col + grid->Columns);
+ grid->comp_col, grid->comp_col + grid->cols);
if (grid->comp_col < col) {
compose_area(MAX(row, grid->comp_row),
- MIN(row + height, grid->comp_row + grid->Rows),
+ MIN(row + height, grid->comp_row + grid->rows),
grid->comp_col, col);
}
- if (col + width < grid->comp_col + grid->Columns) {
+ if (col + width < grid->comp_col + grid->cols) {
compose_area(MAX(row, grid->comp_row),
- MIN(row + height, grid->comp_row + grid->Rows),
- col + width, grid->comp_col + grid->Columns);
+ MIN(row + height, grid->comp_row + grid->rows),
+ col + width, grid->comp_col + grid->cols);
}
- compose_area(row + height, grid->comp_row + grid->Rows,
- grid->comp_col, grid->comp_col + grid->Columns);
+ compose_area(row + height, grid->comp_row + grid->rows,
+ grid->comp_col, grid->comp_col + grid->cols);
grid->comp_disabled = false;
}
grid->comp_row = row;
@@ -188,8 +188,8 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
grid->comp_index = insert_at;
}
if (moved && valid && ui_comp_should_draw()) {
- compose_area(grid->comp_row, grid->comp_row + grid->Rows,
- grid->comp_col, grid->comp_col + grid->Columns);
+ compose_area(grid->comp_row, grid->comp_row + grid->rows,
+ grid->comp_col, grid->comp_col + grid->cols);
}
return moved;
}
@@ -249,10 +249,10 @@ static void ui_comp_raise_grid(ScreenGrid *grid, size_t new_index)
for (size_t i = old_index; i < new_index; i++) {
ScreenGrid *grid2 = kv_A(layers, i);
int startcol = MAX(grid->comp_col, grid2->comp_col);
- int endcol = MIN(grid->comp_col + grid->Columns,
- grid2->comp_col + grid2->Columns);
+ int endcol = MIN(grid->comp_col + grid->cols,
+ grid2->comp_col + grid2->cols);
compose_area(MAX(grid->comp_row, grid2->comp_row),
- MIN(grid->comp_row + grid->Rows, grid2->comp_row + grid2->Rows),
+ MIN(grid->comp_row + grid->rows, grid2->comp_row + grid2->rows),
startcol, endcol);
}
}
@@ -279,7 +279,7 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle, Integer r, Int
}
}
- if (cursor_col >= default_grid.Columns || cursor_row >= default_grid.Rows) {
+ if (cursor_col >= default_grid.cols || cursor_row >= default_grid.rows) {
// TODO(bfredl): this happens with 'writedelay', refactor?
// abort();
return;
@@ -292,8 +292,8 @@ ScreenGrid *ui_comp_mouse_focus(int row, int col)
for (ssize_t i = (ssize_t)kv_size(layers) - 1; i > 0; i--) {
ScreenGrid *grid = kv_A(layers, i);
if (grid->focusable
- && row >= grid->comp_row && row < grid->comp_row + grid->Rows
- && col >= grid->comp_col && col < grid->comp_col + grid->Columns) {
+ && row >= grid->comp_row && row < grid->comp_row + grid->rows
+ && col >= grid->comp_col && col < grid->comp_col + grid->cols) {
return grid;
}
}
@@ -315,7 +315,7 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlag
startcol--;
skipstart = 1;
}
- if (endcol < default_grid.Columns && (flags & kLineFlagInvalid)) {
+ if (endcol < default_grid.cols && (flags & kLineFlagInvalid)) {
endcol++;
skipend = 1;
}
@@ -337,8 +337,8 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlag
// first check to see if any grids have pending updates to width/height,
// to ensure that we don't accidentally put any characters into `linebuf`
// that have been invalidated.
- grid_width = MIN(g->Columns, g->comp_width);
- grid_height = MIN(g->Rows, g->comp_height);
+ grid_width = MIN(g->cols, g->comp_width);
+ grid_height = MIN(g->rows, g->comp_height);
if (g->comp_row > row || row >= g->comp_row + grid_height
|| g->comp_disabled) {
continue;
@@ -354,7 +354,7 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlag
assert(grid != NULL);
assert(until > col);
- assert(until <= default_grid.Columns);
+ assert(until <= default_grid.cols);
size_t n = (size_t)(until - col);
if (row == msg_sep_row && grid->comp_index <= msg_grid.comp_index) {
@@ -371,7 +371,7 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlag
+ (size_t)(col - grid->comp_col);
memcpy(linebuf + (col - startcol), grid->chars + off, n * sizeof(*linebuf));
memcpy(attrbuf + (col - startcol), grid->attrs + off, n * sizeof(*attrbuf));
- if (grid->comp_col + grid->Columns > until
+ if (grid->comp_col + grid->cols > until
&& grid->chars[off + n][0] == NUL) {
linebuf[until - 1 - startcol][0] = ' ';
linebuf[until - 1 - startcol][1] = '\0';
@@ -452,8 +452,8 @@ static void compose_debug(Integer startrow, Integer endrow, Integer startcol, In
return;
}
- endrow = MIN(endrow, default_grid.Rows);
- endcol = MIN(endcol, default_grid.Columns);
+ endrow = MIN(endrow, default_grid.rows);
+ endcol = MIN(endcol, default_grid.cols);
int attr = syn_id2attr(syn_id);
for (int row = (int)startrow; row < endrow; row++) {
@@ -480,8 +480,8 @@ static void debug_delay(Integer lines)
static void compose_area(Integer startrow, Integer endrow, Integer startcol, Integer endcol)
{
compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true);
- endrow = MIN(endrow, default_grid.Rows);
- endcol = MIN(endcol, default_grid.Columns);
+ endrow = MIN(endrow, default_grid.rows);
+ endcol = MIN(endcol, default_grid.cols);
if (endcol <= startcol) {
return;
}
@@ -497,8 +497,8 @@ static void compose_area(Integer startrow, Integer endrow, Integer startcol, Int
void ui_comp_compose_grid(ScreenGrid *grid)
{
if (ui_comp_should_draw()) {
- compose_area(grid->comp_row, grid->comp_row + grid->Rows,
- grid->comp_col, grid->comp_col + grid->Columns);
+ compose_area(grid->comp_row, grid->comp_row + grid->rows,
+ grid->comp_col, grid->comp_col + grid->cols);
}
}
@@ -523,17 +523,17 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, Integer startcol
// TODO(bfredl): this should not really be necessary. But on some condition
// when resizing nvim, a window will be attempted to be drawn on the older
// and possibly larger global screen size.
- if (row >= default_grid.Rows) {
+ if (row >= default_grid.rows) {
DLOG("compositor: invalid row %" PRId64 " on grid %" PRId64, row, grid);
return;
}
- if (clearcol > default_grid.Columns) {
+ if (clearcol > default_grid.cols) {
DLOG("compositor: invalid last column %" PRId64 " on grid %" PRId64,
clearcol, grid);
- if (startcol >= default_grid.Columns) {
+ if (startcol >= default_grid.cols) {
return;
}
- clearcol = default_grid.Columns;
+ clearcol = default_grid.cols;
endcol = MIN(endcol, clearcol);
}
@@ -581,7 +581,7 @@ static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, Boolean scrol
}
if (row > msg_current_row && ui_comp_should_draw()) {
- compose_area(MAX(msg_current_row - 1, 0), row, 0, default_grid.Columns);
+ compose_area(MAX(msg_current_row - 1, 0), row, 0, default_grid.cols);
} else if (row < msg_current_row && ui_comp_should_draw()
&& msg_current_row < Rows) {
int delta = msg_current_row - (int)row;
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index 41b4a7edd6..fd7dc17ee3 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -2646,6 +2646,7 @@ viml_pexpr_parse_figure_brace_closing_error:
kvi_push(pt_stack, kEPTLambdaArguments);
lambda_node = cur_node;
} else {
+ // uncrustify:off
ADD_IDENT(do {
NEW_NODE_WITH_CUR_POS(cur_node,
kExprNodeCurlyBracesIdentifier);
@@ -2660,6 +2661,7 @@ viml_pexpr_parse_figure_brace_closing_error:
want_node = kENodeValue;
} while (0),
Curly);
+ // uncrustify:on
}
if (pt_is_assignment(cur_pt)
&& !pt_is_assignment(kv_last(pt_stack))) {
@@ -2737,6 +2739,7 @@ viml_pexpr_parse_figure_brace_closing_error:
: HL(IdentifierName)));
} else {
if (scope == kExprVarScopeMissing) {
+ // uncrustify:off
ADD_IDENT(do {
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainIdentifier);
cur_node->data.var.scope = scope;
@@ -2745,6 +2748,7 @@ viml_pexpr_parse_figure_brace_closing_error:
want_node = kENodeOperator;
} while (0),
IdentifierName);
+ // uncrustify:on
} else {
OP_MISSING;
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 2c27a5d6a5..0ba5bb1889 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -515,9 +515,14 @@ wingotofile:
if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) {
break;
}
+
+ // Make a copy, if the line was changed it will be freed.
+ ptr = vim_strnsave(ptr, len);
+
find_pattern_in_path(ptr, 0, len, true, Prenum == 0,
type, Prenum1, ACTION_SPLIT, 1, MAXLNUM);
- curwin->w_set_curswant = TRUE;
+ xfree(ptr);
+ curwin->w_set_curswant = true;
break;
// Quickfix window only: view the result under the cursor in a new split.
@@ -695,6 +700,7 @@ win_T *win_new_float(win_T *wp, bool last, FloatConfig fconfig, Error *err)
}
wp->w_floating = 1;
wp->w_status_height = 0;
+ wp->w_winbar_height = 0;
wp->w_hsep_height = 0;
wp->w_vsep_width = 0;
@@ -780,10 +786,8 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
}
if (!ui_has(kUIMultigrid)) {
- wp->w_height = MIN(wp->w_height,
- Rows - 1 - (wp->w_border_adj[0] + wp->w_border_adj[2]));
- wp->w_width = MIN(wp->w_width,
- Columns - (wp->w_border_adj[1] + wp->w_border_adj[3]));
+ wp->w_height = MIN(wp->w_height, Rows - 1 - win_extra_height(wp));
+ wp->w_width = MIN(wp->w_width, Columns - win_extra_width(wp));
}
win_set_inner_size(wp);
@@ -1138,15 +1142,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
} else {
layout = FR_COL;
- /*
- * Check if we are able to split the current window and compute its
- * height.
- */
- // Current window requires at least 1 space.
- wmh1 = p_wmh == 0 ? 1 : p_wmh;
+ // Check if we are able to split the current window and compute its height.
+ // Current window requires at least 1 space plus space for the window bar.
+ wmh1 = MAX(p_wmh, 1) + oldwin->w_winbar_height;
needed = wmh1 + STATUS_HEIGHT;
if (flags & WSP_ROOM) {
- needed += p_wh - wmh1;
+ needed += p_wh - wmh1 + oldwin->w_winbar_height;
}
if (flags & (WSP_BOT | WSP_TOP)) {
minheight = frame_minheight(topframe, NOWIN) + need_status;
@@ -1155,8 +1156,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
} else if (p_ea) {
minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
prevfrp = oldwin->w_frame;
- for (frp = oldwin->w_frame->fr_parent; frp != NULL;
- frp = frp->fr_parent) {
+ for (frp = oldwin->w_frame->fr_parent; frp != NULL; frp = frp->fr_parent) {
if (frp->fr_layout == FR_COL) {
FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
@@ -1339,6 +1339,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
set_fraction(oldwin);
}
wp->w_fraction = oldwin->w_fraction;
+ wp->w_winbar_height = oldwin->w_winbar_height;
if (flags & WSP_VERT) {
wp->w_p_scr = curwin->w_p_scr;
@@ -1416,9 +1417,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (flags & (WSP_TOP | WSP_BOT)) {
int new_fr_height = curfrp->fr_height - new_size;
- if (!((flags & WSP_BOT) && p_ls == 0) && global_stl_height() == 0) {
+ if (!((flags & WSP_BOT) && p_ls == 0) && !is_stl_global) {
new_fr_height -= STATUS_HEIGHT;
- } else if (global_stl_height() > 0) {
+ } else if (is_stl_global) {
if (flags & WSP_BOT) {
frame_add_hsep(curfrp);
} else {
@@ -1452,7 +1453,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
}
}
}
- if ((flags & WSP_BOT) && global_stl_height() == 0) {
+ if ((flags & WSP_BOT) && !is_stl_global) {
frame_add_statusline(curfrp);
}
frame_fix_height(wp);
@@ -1482,10 +1483,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
* equalize the window sizes.
*/
if (do_equal || dir != 0) {
- win_equal(wp, true,
- (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
- : dir == 'h' ? 'b' :
- 'v');
+ win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
}
// Don't change the window height/width to 'winheight' / 'winwidth' if a
@@ -1675,10 +1673,10 @@ int win_count(void)
}
/// Make "count" windows on the screen.
-/// Must be called when there is just one window, filling the whole screen
+/// Must be called when there is just one window, filling the whole screen.
/// (excluding the command line).
///
-/// @param vertical split windows vertically if true
+/// @param vertical split windows vertically if true.
///
/// @return actual number of windows on the screen.
int make_windows(int count, bool vertical)
@@ -1687,15 +1685,15 @@ int make_windows(int count, bool vertical)
int todo;
if (vertical) {
- // Each window needs at least 'winminwidth' lines and a separator
- // column.
+ // Each window needs at least 'winminwidth' lines and a separator column.
maxcount = (curwin->w_width + curwin->w_vsep_width
- (p_wiw - p_wmw)) / (p_wmw + 1);
} else {
- // Each window needs at least 'winminheight' lines
- // If statusline isn't global, each window also needs a statusline
+ // Each window needs at least 'winminheight' lines.
+ // If statusline isn't global, each window also needs a statusline.
+ // If 'winbar' is set, each window also needs a winbar.
maxcount = (curwin->w_height + curwin->w_hsep_height + curwin->w_status_height
- - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
+ - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT + global_winbar_height());
}
if (maxcount < 2) {
@@ -1705,17 +1703,13 @@ int make_windows(int count, bool vertical)
count = maxcount;
}
- /*
- * add status line now, otherwise first window will be too big
- */
+ // add status line now, otherwise first window will be too big
if (count > 1) {
last_status(true);
}
- /*
- * Don't execute autocommands while creating the windows. Must do that
- * when putting the buffers in the windows.
- */
+ // Don't execute autocommands while creating the windows. Must do that
+ // when putting the buffers in the windows.
block_autocmds();
// todo is number of windows left to create
@@ -1790,7 +1784,7 @@ static void win_exchange(long Prenum)
* if wp != wp2
* 3. remove wp from the list
* 4. insert wp after wp2
- * 5. exchange the status line height, hsep height and vsep width.
+ * 5. exchange the status line height, winbar height, hsep height and vsep width.
*/
wp2 = curwin->w_prev;
frp2 = curwin->w_frame->fr_prev;
@@ -1897,7 +1891,7 @@ static void win_rotate(bool upwards, int count)
frame_insert(frp->fr_parent->fr_child, frp);
}
- // exchange status height, hsep height and vsep width of old and new last window
+ // exchange status height, winbar height, hsep height and vsep width of old and new last window
n = wp2->w_status_height;
wp2->w_status_height = wp1->w_status_height;
wp1->w_status_height = n;
@@ -1988,7 +1982,8 @@ void win_move_after(win_T *win1, win_T *win2)
return;
}
- // may need move the status line, horizontal or vertical separator of the last window
+ // may need move the status line, window bar, horizontal or vertical separator of the last
+ // window
if (win1 == lastwin) {
height = win1->w_prev->w_status_height;
win1->w_prev->w_status_height = win1->w_status_height;
@@ -2038,6 +2033,37 @@ void win_move_after(win_T *win1, win_T *win2)
win2->w_pos_changed = true;
}
+/// Compute maximum number of windows that can fit within "height" in frame "fr".
+static int get_maximum_wincount(frame_T *fr, int height)
+{
+ if (fr->fr_layout != FR_COL) {
+ return (height / (p_wmh + STATUS_HEIGHT + frame2win(fr)->w_winbar_height));
+ } else if (global_winbar_height()) {
+ // If winbar is globally enabled, no need to check each window for it.
+ return (height / (p_wmh + STATUS_HEIGHT + 1));
+ }
+
+ frame_T *frp;
+ int total_wincount = 0;
+
+ // First, try to fit all child frames of "fr" into "height"
+ FOR_ALL_FRAMES(frp, fr->fr_child) {
+ win_T *wp = frame2win(frp);
+
+ if (height < (p_wmh + STATUS_HEIGHT + wp->w_winbar_height)) {
+ break;
+ }
+ height -= p_wmh + STATUS_HEIGHT + wp->w_winbar_height;
+ total_wincount += 1;
+ }
+
+ // If we still have enough room for more windows, just use the default winbar height (which is 0)
+ // in order to get the amount of windows that'd fit in the remaining space
+ total_wincount += height / (p_wmh + STATUS_HEIGHT);
+
+ return total_wincount;
+}
+
/// Make all windows the same height.
///'next_curwin' will soon be the current window, make sure it has enough rows.
///
@@ -2237,7 +2263,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
extra_sep = 0;
}
- totwincount = (n + extra_sep) / (p_wmh + STATUS_HEIGHT);
+ totwincount = get_maximum_wincount(topfr, n + extra_sep);
has_next_curwin = frame_has_win(topfr, next_curwin);
/*
@@ -2271,8 +2297,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
}
} else {
// These windows don't use up room.
- totwincount -= (n + (fr->fr_next == NULL
- ? extra_sep : 0)) / (p_wmh + STATUS_HEIGHT);
+ totwincount -= get_maximum_wincount(fr, (n + (fr->fr_next == NULL ? extra_sep : 0)));
}
room -= new_size - n;
if (room < 0) {
@@ -2317,8 +2342,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
// Compute the maximum number of windows vert. in "fr".
n = frame_minheight(fr, NOWIN);
- wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
- / (p_wmh + STATUS_HEIGHT);
+ wincount = get_maximum_wincount(fr, (n + (fr->fr_next == NULL ? extra_sep : 0)));
m = frame_minheight(fr, next_curwin);
if (has_next_curwin) {
hnc = frame_has_win(fr, next_curwin);
@@ -3732,13 +3756,9 @@ static void frame_fix_height(win_T *wp)
wp->w_frame->fr_height = wp->w_height + wp->w_hsep_height + wp->w_status_height;
}
-/*
- * Compute the minimal height for frame "topfrp".
- * Uses the 'winminheight' option.
- * When "next_curwin" isn't NULL, use p_wh for this window.
- * When "next_curwin" is NOWIN, don't use at least one line for the current
- * window.
- */
+/// Compute the minimal height for frame "topfrp". Uses the 'winminheight' option.
+/// When "next_curwin" isn't NULL, use p_wh for this window.
+/// When "next_curwin" is NOWIN, don't use at least one line for the current window.
static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
{
frame_T *frp;
@@ -3746,12 +3766,14 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
int n;
if (topfrp->fr_win != NULL) {
+ // Combined height of window bar and separator column or status line.
+ int extra_height = topfrp->fr_win->w_winbar_height + topfrp->fr_win->w_hsep_height
+ + topfrp->fr_win->w_status_height;
+
if (topfrp->fr_win == next_curwin) {
- m = p_wh + topfrp->fr_win->w_hsep_height + topfrp->fr_win->w_status_height;
+ m = p_wh + extra_height;
} else {
- // window: minimal height of the window plus separator column or status line
- // depending on whether global statusline is enabled
- m = p_wmh + topfrp->fr_win->w_hsep_height + topfrp->fr_win->w_status_height;
+ m = p_wmh + extra_height;
if (topfrp->fr_win == curwin && next_curwin == NULL) {
// Current window is minimal one line high.
if (p_wmh == 0) {
@@ -3976,7 +3998,7 @@ static void new_frame(win_T *wp)
void win_init_size(void)
{
firstwin->w_height = ROWS_AVAIL;
- firstwin->w_height_inner = firstwin->w_height;
+ firstwin->w_height_inner = firstwin->w_height - firstwin->w_winbar_height;
firstwin->w_height_outer = firstwin->w_height;
topframe->fr_height = ROWS_AVAIL;
firstwin->w_width = Columns;
@@ -4087,6 +4109,7 @@ int win_new_tabpage(int after, char_u *filename)
newtp->tp_topframe = topframe;
last_status(false);
+ set_winbar();
redraw_all_later(NOT_VALID);
@@ -5096,6 +5119,12 @@ static void win_free(win_T *wp, tabpage_T *tp)
xfree(wp->w_localdir);
xfree(wp->w_prevdir);
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ xfree(wp->w_status_click_defs);
+
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+
// Remove the window from the b_wininfo lists, it may happen that the
// freed memory is re-used for another window.
FOR_ALL_BUFFERS(buf) {
@@ -5460,16 +5489,9 @@ void win_setheight(int height)
*/
void win_setheight_win(int height, win_T *win)
{
- if (win == curwin) {
- // Always keep current window at least one line high, even when
- // 'winminheight' is zero.
- if (height < p_wmh) {
- height = p_wmh;
- }
- if (height == 0) {
- height = 1;
- }
- }
+ // Always keep current window at least one line high, even when 'winminheight' is zero.
+ // Keep window at least two lines high if 'winbar' is enabled.
+ height = MAX(height, (win == curwin ? MAX(p_wmh, 1) : p_wmh) + win->w_winbar_height);
if (win->w_floating) {
win->w_float_config.height = height;
@@ -6262,7 +6284,7 @@ void win_set_inner_size(win_T *wp)
int prev_height = wp->w_height_inner;
int height = wp->w_height_request;
if (height == 0) {
- height = wp->w_height;
+ height = wp->w_height - wp->w_winbar_height;
}
if (height != prev_height) {
@@ -6279,8 +6301,8 @@ void win_set_inner_size(win_T *wp)
set_fraction(wp);
}
}
- wp->w_height_inner = height;
wp->w_skipcol = 0;
+ wp->w_height_inner = height;
// There is no point in adjusting the scroll position when exiting. Some
// values might be invalid.
@@ -6306,10 +6328,20 @@ void win_set_inner_size(win_T *wp)
terminal_check_size(wp->w_buffer->terminal);
}
- wp->w_height_outer = (wp->w_height_inner
- + wp->w_border_adj[0] + wp->w_border_adj[2]);
- wp->w_width_outer = (wp->w_width_inner
- + wp->w_border_adj[1] + wp->w_border_adj[3]);
+ wp->w_height_outer = (wp->w_height_inner + win_extra_height(wp));
+ wp->w_width_outer = (wp->w_width_inner + win_extra_width(wp));
+ wp->w_winrow_off = wp->w_border_adj[0] + wp->w_winbar_height;
+ wp->w_wincol_off = wp->w_border_adj[3];
+}
+
+static int win_extra_height(win_T *wp)
+{
+ return wp->w_border_adj[0] + wp->w_border_adj[2] + wp->w_winbar_height;
+}
+
+static int win_extra_width(win_T *wp)
+{
+ return wp->w_border_adj[1] + wp->w_border_adj[3];
}
/// Set the width of a window.
@@ -6586,6 +6618,23 @@ void last_status(bool morewin)
global_stl_height() > 0);
}
+// Remove status line from window, replacing it with a horizontal separator if needed.
+static void win_remove_status_line(win_T *wp, bool add_hsep)
+{
+ wp->w_status_height = 0;
+ if (add_hsep) {
+ wp->w_hsep_height = 1;
+ } else {
+ win_new_height(wp, wp->w_height + STATUS_HEIGHT);
+ }
+ comp_col();
+
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ xfree(wp->w_status_click_defs);
+ wp->w_status_click_defs_size = 0;
+ wp->w_status_click_defs = NULL;
+}
+
// Look for resizable frames and take lines from them to make room for the statusline
static void resize_frame_for_status(frame_T *fr)
{
@@ -6626,10 +6675,7 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
if (is_last) {
if (wp->w_status_height != 0 && (!statusline || is_stl_global)) {
- // Remove status line
- wp->w_status_height = 0;
- win_new_height(wp, wp->w_height + STATUS_HEIGHT);
- comp_col();
+ win_remove_status_line(wp, false);
} else if (wp->w_status_height == 0 && !is_stl_global && statusline) {
// Add statusline to window if needed
wp->w_status_height = STATUS_HEIGHT;
@@ -6639,9 +6685,7 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
} else if (wp->w_status_height != 0 && is_stl_global) {
// If statusline is global and the window has a statusline, replace it with a horizontal
// separator
- wp->w_status_height = 0;
- wp->w_hsep_height = 1;
- comp_col();
+ win_remove_status_line(wp, true);
} else if (wp->w_status_height == 0 && !is_stl_global) {
// If statusline isn't global and the window doesn't have a statusline, re-add it
wp->w_status_height = STATUS_HEIGHT;
@@ -6649,19 +6693,35 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
comp_col();
}
redraw_all_later(SOME_VALID);
- } else if (fr->fr_layout == FR_COL) {
- // For a column frame, recursively call this function for all child frames
- FOR_ALL_FRAMES(fp, fr->fr_child) {
- last_status_rec(fp, statusline, is_stl_global);
- }
} else {
- // For a row frame, recursively call this function for all child frames
+ // For a column or row frame, recursively call this function for all child frames
FOR_ALL_FRAMES(fp, fr->fr_child) {
last_status_rec(fp, statusline, is_stl_global);
}
}
}
+// Add or remove window bars from windows depending on the value of 'winbar'.
+void set_winbar(void)
+{
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ int winbar_height = (*p_wbr != NUL || *wp->w_p_wbr != NUL) ? 1 : 0;
+ if (wp->w_winbar_height != winbar_height) {
+ wp->w_winbar_height = winbar_height;
+ win_set_inner_size(wp);
+ wp->w_redr_status = wp->w_redr_status || winbar_height;
+
+ if (winbar_height == 0) {
+ // When removing winbar, deallocate the w_winbar_click_defs array
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = 0;
+ wp->w_winbar_click_defs = NULL;
+ }
+ }
+ }
+}
+
/// Return the number of lines used by the tab page line.
int tabline_height(void)
{
@@ -6678,6 +6738,12 @@ int tabline_height(void)
return 1;
}
+/// Return the number of lines used by default by the window bar.
+int global_winbar_height(void)
+{
+ return *p_wbr != NUL ? 1 : 0;
+}
+
/// Return the number of lines used by the global statusline
int global_stl_height(void)
{
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index 41de308a2c..491dac9f35 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -119,13 +119,45 @@ describe('autocmd api', function()
describe('desc', function()
it('can add description to one autocmd', function()
+ local cmd = "echo 'Should Not Have Errored'"
+ local desc = "Can show description"
meths.create_autocmd("BufReadPost", {
pattern = "*.py",
- command = "echo 'Should Not Have Errored'",
- desc = "Can show description",
+ command = cmd,
+ desc = desc,
})
- eq("Can show description", meths.get_autocmds { event = "BufReadPost" }[1].desc)
+ eq(desc, meths.get_autocmds { event = "BufReadPost" }[1].desc)
+ eq(cmd, meths.get_autocmds { event = "BufReadPost" }[1].command)
+ end)
+
+ it('can add description to one autocmd that uses a callback', function()
+ local desc = 'Can show description'
+ meths.set_var('desc', desc)
+
+ exec_lua([[
+ local callback = function() print 'Should Not Have Errored' end
+ vim.api.nvim_create_autocmd("BufReadPost", {
+ pattern = "*.py",
+ callback = callback,
+ desc = vim.g.desc,
+ })
+ ]])
+
+ eq(desc, meths.get_autocmds({ event = 'BufReadPost' })[1].desc)
+ matches('<lua: %d+>', meths.get_autocmds({ event = 'BufReadPost' })[1].command)
+ end)
+
+ it('will not add a description unless it was provided', function()
+ exec_lua([[
+ local callback = function() print 'Should Not Have Errored' end
+ vim.api.nvim_create_autocmd("BufReadPost", {
+ pattern = "*.py",
+ callback = callback,
+ })
+ ]])
+
+ eq(nil, meths.get_autocmds({ event = 'BufReadPost' })[1].desc)
end)
it('can add description to multiple autocmd', function()
@@ -169,15 +201,11 @@ describe('autocmd api', function()
]]
meths.exec_autocmds("User", {pattern = "Test"})
- eq({{
- buflocal = false,
- command = 'A test autocommand',
- desc = 'A test autocommand',
- event = 'User',
- id = 1,
- once = false,
- pattern = 'Test',
- }}, meths.get_autocmds({event = "User", pattern = "Test"}))
+
+ local aus = meths.get_autocmds({ event = 'User', pattern = 'Test' })
+ local first = aus[1]
+ eq(first.id, 1)
+
meths.set_var("some_condition", true)
meths.exec_autocmds("User", {pattern = "Test"})
eq({}, meths.get_autocmds({event = "User", pattern = "Test"}))
@@ -230,6 +258,34 @@ describe('autocmd api', function()
}, meths.get_var("autocmd_args"))
end)
+
+ it('can receive arbitrary data', function()
+ local function test(data)
+ eq(data, exec_lua([[
+ local input = ...
+ local output
+ vim.api.nvim_create_autocmd("User", {
+ pattern = "Test",
+ callback = function(args)
+ output = args.data
+ end,
+ })
+
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "Test",
+ data = input,
+ })
+
+ return output
+ ]], data))
+ end
+
+ test("Hello")
+ test(42)
+ test(true)
+ test({ "list" })
+ test({ foo = "bar" })
+ end)
end)
describe('nvim_get_autocmds', function()
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index 097757f53d..2728dcf74c 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -828,7 +828,6 @@ describe('API: buffer events:', function()
end
it('when :terminal lines change', function()
- if helpers.pending_win32(pending) then return end
local buffer_lines = {}
local expected_lines = {}
command('terminal "'..nvim_prog..'" -u NONE -i NONE -n -c "set shortmess+=A"')
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index ba170ba8c5..c5e8cfee23 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -3102,6 +3102,19 @@ describe('API', function()
'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
{ use_tabline = true, highlights = true }))
end)
+ it('works with winbar', function()
+ eq({
+ str = 'TextWithNoHighlightTextWithWarningHighlight',
+ width = 43,
+ highlights = {
+ { start = 0, group = 'WinBar' },
+ { start = 19, group = 'WarningMsg' }
+ }
+ },
+ meths.eval_statusline(
+ 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
+ { use_winbar = true, highlights = true }))
+ end)
end)
end)
describe('nvim_parse_cmd', function()
@@ -3623,5 +3636,13 @@ describe('API', function()
meths.cmd({ cmd = "update" }, {})
meths.cmd({ cmd = "buffer", count = 0 }, {})
end)
+ it('doesn\'t suppress errors when used in keymapping', function()
+ meths.exec_lua([[
+ vim.keymap.set("n", "[l",
+ function() vim.api.nvim_cmd({ cmd = "echo", args = {"foo"} }, {}) end)
+ ]], {})
+ feed("[l")
+ neq(nil, string.find(eval("v:errmsg"), "E5108:"))
+ end)
end)
end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 9741497b0a..f87fd8e951 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -53,7 +53,6 @@ describe('startup', function()
]])
end)
it('in a TTY: has("ttyin")==1 has("ttyout")==1', function()
- if helpers.pending_win32(pending) then return end
local screen = Screen.new(25, 4)
screen:attach()
if iswin() then
@@ -105,7 +104,6 @@ describe('startup', function()
end)
end)
it('input from pipe (implicit) #7679', function()
- if helpers.pending_win32(pending) then return end
local screen = Screen.new(25, 4)
screen:attach()
if iswin() then
@@ -261,7 +259,6 @@ describe('startup', function()
end)
it('ENTER dismisses early message #7967', function()
- if helpers.pending_win32(pending) then return end
local screen
screen = Screen.new(60, 6)
screen:attach()
@@ -494,7 +491,6 @@ describe('sysinit', function()
end)
it('fixed hang issue with -D (#12647)', function()
- if helpers.pending_win32(pending) then return end
local screen
screen = Screen.new(60, 7)
screen:attach()
diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
index 684dee69db..e3d3cdbd85 100644
--- a/test/functional/editor/mode_insert_spec.lua
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -6,8 +6,6 @@ local expect = helpers.expect
local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
-local meths = helpers.meths
-local poke_eventloop = helpers.poke_eventloop
describe('insert-mode', function()
before_each(function()
@@ -135,26 +133,4 @@ describe('insert-mode', function()
feed('i<C-S-V><C-J><C-S-V><C-@><C-S-V><C-[><C-S-V><C-S-M><C-S-V><M-C-I><C-S-V><C-D-J><Esc>')
expect('<C-J><C-@><C-[><C-S-M><M-C-I><C-D-J>')
end)
-
- describe([[With 'insertmode', Insert mode is not re-entered immediately after <C-L>]], function()
- before_each(function()
- command('set insertmode')
- poke_eventloop()
- eq({mode = 'i', blocking = false}, meths.get_mode())
- end)
-
- it('after calling :edit from <Cmd> mapping', function()
- command('inoremap <C-B> <Cmd>edit Xfoo<CR>')
- feed('<C-B><C-L>')
- poke_eventloop()
- eq({mode = 'n', blocking = false}, meths.get_mode())
- end)
-
- it('after calling :edit from RPC #16823', function()
- command('edit Xfoo')
- feed('<C-L>')
- poke_eventloop()
- eq({mode = 'n', blocking = false}, meths.get_mode())
- end)
- end)
end)
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index 2702fb196f..8323d40e10 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -1,20 +1,23 @@
local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local get_pathsep = helpers.get_pathsep
+local iswin = helpers.iswin
local eq = helpers.eq
local neq = helpers.neq
local funcs = helpers.funcs
local matches = helpers.matches
local pesc = helpers.pesc
local rmdir = helpers.rmdir
+local sleep = helpers.sleep
+local meths = helpers.meths
local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec'
describe(':mksession', function()
- if helpers.pending_win32(pending) then return end
local session_file = file_prefix .. '.vim'
local tab_dir = file_prefix .. '.d'
@@ -103,9 +106,13 @@ describe(':mksession', function()
local session_path = cwd_dir..'/'..session_file
command('cd '..tab_dir)
- command('terminal echo $PWD')
+ command('terminal')
command('cd '..cwd_dir)
command('mksession '..session_path)
+ command('bdelete!')
+ if iswin() then
+ sleep(100) -- Make sure all child processes have exited.
+ end
command('qall!')
-- Create a new test instance of Nvim.
@@ -114,6 +121,83 @@ describe(':mksession', function()
local expected_cwd = cwd_dir..'/'..tab_dir
matches('^term://'..pesc(expected_cwd)..'//%d+:', funcs.expand('%'))
+ command('bdelete!')
+ if iswin() then
+ sleep(100) -- Make sure all child processes have exited.
+ end
+ end)
+
+ it('restores CWD for :terminal buffer at root directory #16988', function()
+ if iswin() then
+ pending('N/A for Windows')
+ return
+ end
+
+ local screen
+ local cwd_dir = funcs.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '')
+ local session_path = cwd_dir..'/'..session_file
+
+ screen = Screen.new(50, 6)
+ screen:attach({rgb=false})
+ local expected_screen = [[
+ ^/ |
+ |
+ [Process exited 0] |
+ |
+ |
+ |
+ ]]
+
+ command('cd /')
+ command('terminal echo $PWD')
+
+ -- Verify that the terminal's working directory is "/".
+ screen:expect(expected_screen)
+
+ command('cd '..cwd_dir)
+ command('mksession '..session_path)
command('qall!')
+
+ -- Create a new test instance of Nvim.
+ clear()
+ screen = Screen.new(50, 6)
+ screen:attach({rgb=false})
+ command('silent source '..session_path)
+
+ -- Verify that the terminal's working directory is "/".
+ screen:expect(expected_screen)
+ end)
+
+ it('restores a session when there is a float #18432', function()
+ local tmpfile = file_prefix .. '-tmpfile-float'
+
+ command('edit ' .. tmpfile)
+ local buf = meths.create_buf(false, true)
+ local config = {
+ relative = 'editor',
+ focusable = false,
+ width = 10,
+ height = 3,
+ row = 0,
+ col = 1,
+ style = 'minimal'
+ }
+ meths.open_win(buf, false, config)
+ local cmdheight = meths.get_option('cmdheight')
+ command('mksession ' .. session_file)
+
+ -- Create a new test instance of Nvim.
+ clear()
+
+ command('source ' .. session_file)
+
+ eq(tmpfile, funcs.expand('%'))
+ -- Check that there is only a single window, which indicates the floating
+ -- window was not restored.
+ eq(1, funcs.winnr('$'))
+ -- The command-line height should remain the same as it was.
+ eq(cmdheight, meths.get_option('cmdheight'))
+
+ os.remove(tmpfile)
end)
end)
diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua
deleted file mode 100644
index 91d602924c..0000000000
--- a/test/functional/legacy/edit_spec.lua
+++ /dev/null
@@ -1,25 +0,0 @@
--- Test for edit functions
--- See also: src/nvim/testdir/test_edit.vim
-
-local helpers = require('test.functional.helpers')(after_each)
-local source = helpers.source
-local eq, eval = helpers.eq, helpers.eval
-local funcs = helpers.funcs
-local clear = helpers.clear
-
-describe('edit', function()
- before_each(clear)
-
- it('reset insertmode from i_ctrl-r_=', function()
- source([=[
- call setline(1, ['abc'])
- call cursor(1, 4)
- call feedkeys(":set im\<cr>ZZZ\<c-r>=setbufvar(1,'&im', 0)\<cr>",'tnix')
- ]=])
- eq({'abZZZc'}, funcs.getline(1,'$'))
- eq({0, 1, 1, 0}, funcs.getpos('.'))
- eq(0, eval('&im'))
- end)
-
-end)
-
diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua
index 47eca19de3..63338b8dba 100644
--- a/test/functional/legacy/prompt_buffer_spec.lua
+++ b/test/functional/legacy/prompt_buffer_spec.lua
@@ -23,7 +23,7 @@ describe('prompt buffer', function()
close
else
call append(line("$") - 1, 'Command: "' . a:text . '"')
- set nomodfied
+ set nomodified
call timer_start(20, {id -> TimerFunc(a:text)})
endif
endfunc
@@ -33,7 +33,7 @@ describe('prompt buffer', function()
endfunc
func SwitchWindows()
- call timer_start(0, {-> execute("wincmd p|wincmd p", "")})
+ call timer_start(0, {-> execute("wincmd p", "")})
endfunc
]])
feed_command("set noshowmode | set laststatus=0")
@@ -187,7 +187,19 @@ describe('prompt buffer', function()
-- INSERT -- |
]])
feed("<C-O>:call SwitchWindows()<CR>")
- poke_eventloop()
+ screen:expect{grid=[[
+ cmd: |
+ ~ |
+ ~ |
+ ~ |
+ [Prompt] [+] |
+ ^other buffer |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]]}
+ feed("<C-O>:call SwitchWindows()<CR>")
screen:expect([[
cmd: ^ |
~ |
@@ -201,7 +213,6 @@ describe('prompt buffer', function()
-- INSERT -- |
]])
feed("<Esc>")
- poke_eventloop()
screen:expect([[
cmd:^ |
~ |
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 4cb7636825..f8d4552330 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -18,6 +18,7 @@ local NIL = helpers.NIL
local read_file = require('test.helpers').read_file
local write_file = require('test.helpers').write_file
local isCI = helpers.isCI
+local meths = helpers.meths
-- Use these to get access to a coroutine so that I can run async tests and use
-- yield.
@@ -221,10 +222,32 @@ describe('LSP', function()
end)
end)
+ describe('lsp._cmd_parts test', function()
+ local function _cmd_parts(input)
+ return exec_lua([[
+ lsp = require('vim.lsp')
+ return lsp._cmd_parts(...)
+ ]], input)
+ end
+ it('should valid cmd argument', function()
+ eq(true, pcall(_cmd_parts, {"nvim"}))
+ eq(true, pcall(_cmd_parts, {"nvim", "--head"}))
+ end)
+
+ it('should invalid cmd argument', function()
+ eq('Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim',
+ pcall_err(_cmd_parts, 'nvim'))
+ eq('Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number',
+ pcall_err(_cmd_parts, {'nvim', 1}))
+ end)
+ end)
+end)
+
+describe('LSP', function()
describe('basic_init test', function()
after_each(function()
stop()
- exec_lua("lsp.stop_client(lsp.get_active_clients())")
+ exec_lua("lsp.stop_client(lsp.get_active_clients(), true)")
exec_lua("lsp._vim_exit_handler()")
end)
@@ -341,6 +364,43 @@ describe('LSP', function()
}
end)
+ it('should fire autocommands on attach and detach', function()
+ local client
+ test_rpc_server {
+ test_name = "basic_init";
+ on_setup = function()
+ exec_lua [[
+ BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_create_autocmd('LspAttach', {
+ callback = function(args)
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+ vim.g.lsp_attached = client.name
+ end,
+ })
+ vim.api.nvim_create_autocmd('LspDetach', {
+ callback = function(args)
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+ vim.g.lsp_detached = client.name
+ end,
+ })
+ ]]
+ end;
+ on_init = function(_client)
+ client = _client
+ eq(true, exec_lua("return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)"))
+ client.notify('finish')
+ end;
+ on_handler = function(_, _, ctx)
+ if ctx.method == 'finish' then
+ eq('basic_init', meths.get_var('lsp_attached'))
+ exec_lua("return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)")
+ eq('basic_init', meths.get_var('lsp_detached'))
+ client.stop()
+ end
+ end;
+ }
+ end)
+
it('client should return settings via workspace/configuration handler', function()
local expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
@@ -386,16 +446,23 @@ describe('LSP', function()
}
end)
it('workspace/configuration returns NIL per section if client was started without config.settings', function()
- fake_lsp_server_setup('workspace/configuration no settings')
- eq({ NIL, NIL, }, exec_lua [[
- local result = {
- items = {
- {section = 'foo'},
- {section = 'bar'},
- }
- }
- return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
- ]])
+ local result = nil
+ test_rpc_server {
+ test_name = 'basic_init';
+ on_init = function(c) c.stop() end,
+ on_setup = function()
+ result = exec_lua [[
+ local result = {
+ items = {
+ {section = 'foo'},
+ {section = 'bar'},
+ }
+ }
+ return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
+ ]]
+ end
+ }
+ eq({ NIL, NIL }, result)
end)
it('should verify capabilities sent', function()
@@ -1307,25 +1374,6 @@ describe('LSP', function()
}
end)
end)
- describe('lsp._cmd_parts test', function()
- local function _cmd_parts(input)
- return exec_lua([[
- lsp = require('vim.lsp')
- return lsp._cmd_parts(...)
- ]], input)
- end
- it('should valid cmd argument', function()
- eq(true, pcall(_cmd_parts, {"nvim"}))
- eq(true, pcall(_cmd_parts, {"nvim", "--head"}))
- end)
-
- it('should invalid cmd argument', function()
- eq('Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim',
- pcall_err(_cmd_parts, 'nvim'))
- eq('Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number',
- pcall_err(_cmd_parts, {'nvim', 1}))
- end)
- end)
end)
describe('LSP', function()
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index c9087d734b..6e06304acd 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -538,7 +538,7 @@ describe('buffer cursor position is correct in terminal without number column',
:aaaaaaaa {1: } |
{3:-- TERMINAL --} |
]])
- matches('^:aaaaaaaa ', eval('nvim_get_current_line()'))
+ matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
eq({6, 13}, eval('nvim_win_get_cursor(0)'))
feed([[<C-\><C-N>]])
screen:expect([[
@@ -918,7 +918,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 6 }:aaaaaaaa {1: } |
{3:-- TERMINAL --} |
]])
- matches('^:aaaaaaaa ', eval('nvim_get_current_line()'))
+ matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
eq({6, 13}, eval('nvim_win_get_cursor(0)'))
feed([[<C-\><C-N>]])
screen:expect([[
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 32c911a5e8..2a63971d48 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -117,7 +117,6 @@ describe(':terminal highlight', function()
end)
it(':terminal highlight has lower precedence than editor #9964', function()
- if helpers.pending_win32(pending) then return end
clear()
local screen = Screen.new(30, 4)
screen:set_default_attr_ids({
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index d1cfc7e91b..34fcb6cab9 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -6,6 +6,7 @@ local feed, nvim_dir, feed_command = helpers.feed, helpers.nvim_dir, helpers.fee
local iswin = helpers.iswin
local eval = helpers.eval
local command = helpers.command
+local matches = helpers.matches
local poke_eventloop = helpers.poke_eventloop
local retry = helpers.retry
local curbufmeths = helpers.curbufmeths
@@ -460,8 +461,8 @@ describe("'scrollback' option", function()
expect_lines(58)
-- Verify off-screen state
- eq((iswin() and '36: line' or '35: line'), eval("getline(line('w0') - 1)"))
- eq((iswin() and '27: line' or '26: line'), eval("getline(line('w0') - 10)"))
+ matches((iswin() and '^36: line[ ]*$' or '^35: line[ ]*$'), eval("getline(line('w0') - 1)"))
+ matches((iswin() and '^27: line[ ]*$' or '^26: line[ ]*$'), eval("getline(line('w0') - 10)"))
end)
it('defaults to 10000 in :terminal buffers', function()
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 9f84b71ece..7c0831bd09 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -564,6 +564,16 @@ describe('Buffer highlighting', function()
]]
clear_namespace(id, 0, -1)
+ screen:expect{grid=[[
+ fooba^r |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
set_extmark(id, 0, 0, {
end_line = 0,
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 92300a8fa2..d61eebe3ea 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -212,10 +212,10 @@ describe('ui/cursor', function()
if m.blinkwait then m.blinkwait = 700 end
end
if m.hl_id then
- m.hl_id = 62
+ m.hl_id = 64
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 63 end
+ if m.id_lm then m.id_lm = 65 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 7ab00e74d9..ca5e269f92 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -6627,7 +6627,7 @@ describe('float window', function()
it("left drag changes visual selection in float window", function()
local buf = meths.create_buf(false,false)
- meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar'})
+ meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'})
meths.open_win(buf, false, {relative='editor', width=20, height=3, row=2, col=5})
if multigrid then
screen:expect{grid=[[
@@ -6651,12 +6651,12 @@ describe('float window', function()
## grid 5
{1:foo }|
{1:bar }|
- {2:~ }|
+ {1:baz }|
]], float_pos={
[5] = {{id = 1002}, "NW", 1, 2, 5, true, 50};
}, win_viewport={
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
- [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
}}
meths.input_mouse('left', 'press', '', 5, 0, 0)
screen:expect{grid=[[
@@ -6680,12 +6680,12 @@ describe('float window', function()
## grid 5
{1:^foo }|
{1:bar }|
- {2:~ }|
+ {1:baz }|
]], float_pos={
[5] = {{id = 1002}, "NW", 1, 2, 5, true, 50};
}, win_viewport={
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
- [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
}}
meths.input_mouse('left', 'drag', '', 5, 1, 2)
screen:expect{grid=[[
@@ -6709,12 +6709,12 @@ describe('float window', function()
## grid 5
{27:foo}{1: }|
{27:ba}{1:^r }|
- {2:~ }|
+ {1:baz }|
]], float_pos={
[5] = {{id = 1002}, "NW", 1, 2, 5, true, 50};
}, win_viewport={
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
- [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 2};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3};
}}
else
screen:expect{grid=[[
@@ -6722,7 +6722,7 @@ describe('float window', function()
{0:~ }|
{0:~ }{1:foo }{0: }|
{0:~ }{1:bar }{0: }|
- {0:~ }{2:~ }{0: }|
+ {0:~ }{1:baz }{0: }|
{0:~ }|
|
]]}
@@ -6733,7 +6733,7 @@ describe('float window', function()
{0:~ }|
{0:~ }{1:^foo }{0: }|
{0:~ }{1:bar }{0: }|
- {0:~ }{2:~ }{0: }|
+ {0:~ }{1:baz }{0: }|
{0:~ }|
|
]]}
@@ -6744,7 +6744,269 @@ describe('float window', function()
{0:~ }|
{0:~ }{27:foo}{1: }{0: }|
{0:~ }{27:ba}{1:^r }{0: }|
- {0:~ }{2:~ }{0: }|
+ {0:~ }{1:baz }{0: }|
+ {0:~ }|
+ {3:-- VISUAL --} |
+ ]]}
+ end
+ end)
+
+ it("left drag changes visual selection in float window with border", function()
+ local buf = meths.create_buf(false,false)
+ meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'})
+ meths.open_win(buf, false, {relative='editor', width=20, height=3, row=0, col=5, border='single'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:┌────────────────────┐}|
+ {5:│}{1:foo }{5:│}|
+ {5:│}{1:bar }{5:│}|
+ {5:│}{1:baz }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
+ }}
+ meths.input_mouse('left', 'press', '', 5, 1, 1)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:┌────────────────────┐}|
+ {5:│}{1:^foo }{5:│}|
+ {5:│}{1:bar }{5:│}|
+ {5:│}{1:baz }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
+ }}
+ meths.input_mouse('left', 'drag', '', 5, 2, 3)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {3:-- VISUAL --} |
+ ## grid 5
+ {5:┌────────────────────┐}|
+ {5:│}{27:foo}{1: }{5:│}|
+ {5:│}{27:ba}{1:^r }{5:│}|
+ {5:│}{1:baz }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{1:foo }{5:│}{0: }|
+ {0:~ }{5:│}{1:bar }{5:│}{0: }|
+ {0:~ }{5:│}{1:baz }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ |
+ ]]}
+
+ meths.input_mouse('left', 'press', '', 0, 1, 6)
+ screen:expect{grid=[[
+ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{1:^foo }{5:│}{0: }|
+ {0:~ }{5:│}{1:bar }{5:│}{0: }|
+ {0:~ }{5:│}{1:baz }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ |
+ ]]}
+
+ meths.input_mouse('left', 'drag', '', 0, 2, 8)
+ screen:expect{grid=[[
+ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{27:foo}{1: }{5:│}{0: }|
+ {0:~ }{5:│}{27:ba}{1:^r }{5:│}{0: }|
+ {0:~ }{5:│}{1:baz }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ {3:-- VISUAL --} |
+ ]]}
+ end
+ end)
+
+ it("left drag changes visual selection in float window with winbar", function()
+ local buf = meths.create_buf(false,false)
+ meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'})
+ local float_win = meths.open_win(buf, false, {relative='editor', width=20, height=4, row=1, col=5})
+ meths.win_set_option(float_win, 'winbar', 'floaty bar')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {3:floaty bar }|
+ {1:foo }|
+ {1:bar }|
+ {1:baz }|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
+ }}
+ meths.input_mouse('left', 'press', '', 5, 1, 0)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {3:floaty bar }|
+ {1:^foo }|
+ {1:bar }|
+ {1:baz }|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
+ }}
+ meths.input_mouse('left', 'drag', '', 5, 2, 2)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {3:-- VISUAL --} |
+ ## grid 5
+ {3:floaty bar }|
+ {27:foo}{1: }|
+ {27:ba}{1:^r }|
+ {1:baz }|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }{3:floaty bar }{0: }|
+ {0:~ }{1:foo }{0: }|
+ {0:~ }{1:bar }{0: }|
+ {0:~ }{1:baz }{0: }|
+ {0:~ }|
+ |
+ ]]}
+
+ meths.input_mouse('left', 'press', '', 0, 2, 5)
+ screen:expect{grid=[[
+ |
+ {0:~ }{3:floaty bar }{0: }|
+ {0:~ }{1:^foo }{0: }|
+ {0:~ }{1:bar }{0: }|
+ {0:~ }{1:baz }{0: }|
+ {0:~ }|
+ |
+ ]]}
+
+ meths.input_mouse('left', 'drag', '', 0, 3, 7)
+ screen:expect{grid=[[
+ |
+ {0:~ }{3:floaty bar }{0: }|
+ {0:~ }{27:foo}{1: }{0: }|
+ {0:~ }{27:ba}{1:^r }{0: }|
+ {0:~ }{1:baz }{0: }|
{0:~ }|
{3:-- VISUAL --} |
]]}
@@ -7591,6 +7853,53 @@ describe('float window', function()
]]}
end
end)
+
+ it('can use winbar', function()
+ local buf = meths.create_buf(false,false)
+ local win1 = meths.open_win(buf, false, {relative='editor', width=15, height=3, row=1, col=5})
+ meths.win_set_option(win1, 'winbar', 'floaty bar')
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {3:floaty bar }|
+ {1: }|
+ {2:~ }|
+ ]], float_pos={
+ [4] = {{id = 1001}, "NW", 1, 1, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }{3:floaty bar }{0: }|
+ {0:~ }{1: }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+ end)
end
describe('with ext_multigrid', function()
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 9762805dee..394f2f5f49 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -1757,6 +1757,67 @@ describe("folded lines", function()
end
assert_alive()
end)
+
+ it('work correctly with :move #18668', function()
+ screen:try_resize(45, 12)
+ source([[
+ set foldmethod=expr foldexpr=indent(v:lnum)
+ let content = ['', '', 'Line1', ' Line2', ' Line3',
+ \ 'Line4', ' Line5', ' Line6',
+ \ 'Line7', ' Line8', ' Line9']
+ call append(0, content)
+ normal! zM
+ call cursor(4, 1)
+ move 2
+ move 1
+ ]])
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ |
+ {5:^+-- 2 lines: Line2··························}|
+ |
+ Line1 |
+ Line4 |
+ {5:+-- 2 lines: Line5··························}|
+ Line7 |
+ {5:+-- 2 lines: Line8··························}|
+ |
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]])
+ else
+ screen:expect([[
+ |
+ {5:^+-- 2 lines: Line2··························}|
+ |
+ Line1 |
+ Line4 |
+ {5:+-- 2 lines: Line5··························}|
+ Line7 |
+ {5:+-- 2 lines: Line8··························}|
+ |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end
+ end)
end
describe("with ext_multigrid", function()
diff --git a/test/functional/ui/global_statusline_spec.lua b/test/functional/ui/global_statusline_spec.lua
deleted file mode 100644
index 369c4a31f1..0000000000
--- a/test/functional/ui/global_statusline_spec.lua
+++ /dev/null
@@ -1,260 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local Screen = require('test.functional.ui.screen')
-local clear, command, feed = helpers.clear, helpers.command, helpers.feed
-local eq, funcs, meths = helpers.eq, helpers.funcs, helpers.meths
-
-describe('global statusline', function()
- local screen
-
- before_each(function()
- clear()
- screen = Screen.new(60, 16)
- screen:attach()
- command('set laststatus=3')
- command('set ruler')
- end)
-
- it('works', function()
- screen:expect{grid=[[
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {bold = true, foreground = Screen.colors.Blue1};
- [2] = {bold = true, reverse = true};
- }}
-
- feed('i<CR><CR>')
- screen:expect{grid=[[
- |
- |
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:[No Name] [+] 3,1 All}|
- {3:-- INSERT --} |
- ]], attr_ids={
- [1] = {bold = true, foreground = Screen.colors.Blue};
- [2] = {bold = true, reverse = true};
- [3] = {bold = true};
- }}
- end)
-
- it('works with splits', function()
- command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }├────────────────┤{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}├────────────────────|
- {2:~ }│{2:~ }│{2:~}│ |
- ────────────────────┴────────────────┴─┤{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {3:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {bold = true, foreground = Screen.colors.Blue1};
- [3] = {bold = true, reverse = true};
- }}
- end)
-
- it('works when switching between values of laststatus', function()
- command('set laststatus=1')
- screen:expect{grid=[[
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- 0,0-1 All |
- ]], attr_ids={
- [1] = {foreground = Screen.colors.Blue, bold = true};
- }}
-
- command('set laststatus=3')
- screen:expect{grid=[[
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {foreground = Screen.colors.Blue, bold = true};
- [2] = {reverse = true, bold = true};
- }}
-
- command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
- command('set laststatus=2')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{1:< Name] 0,0-1 }│{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{3:<No Name] 0,0-1 All}|
- {2:~ }│{2:~ }│{2:~}│ |
- {1:<No Name] 0,0-1 All < Name] 0,0-1 <}│{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {1:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {foreground = Screen.colors.Blue, bold = true};
- [3] = {reverse = true, bold = true};
- }}
-
- command('set laststatus=3')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }├────────────────┤{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}├────────────────────|
- {2:~ }│{2:~ }│{2:~}│ |
- ────────────────────┴────────────────┴─┤{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {3:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {foreground = Screen.colors.Blue, bold = true};
- [3] = {reverse = true, bold = true};
- }}
-
- command('set laststatus=0')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{1:< Name] 0,0-1 }│{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{3:<No Name] 0,0-1 All}|
- {2:~ }│{2:~ }│{2:~}│ |
- {1:<No Name] 0,0-1 All < Name] 0,0-1 <}│{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- 0,0-1 All |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {foreground = Screen.colors.Blue, bold = true};
- [3] = {reverse = true, bold = true};
- }}
-
- command('set laststatus=3')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }├────────────────┤{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}├────────────────────|
- {2:~ }│{2:~ }│{2:~}│ |
- ────────────────────┴────────────────┴─┤{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {3:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {foreground = Screen.colors.Blue, bold = true};
- [3] = {reverse = true, bold = true};
- }}
- end)
-
- it('win_move_statusline() can reduce cmdheight to 1', function()
- eq(1, meths.get_option('cmdheight'))
- funcs.win_move_statusline(0, -1)
- eq(2, meths.get_option('cmdheight'))
- funcs.win_move_statusline(0, -1)
- eq(3, meths.get_option('cmdheight'))
- funcs.win_move_statusline(0, 1)
- eq(2, meths.get_option('cmdheight'))
- funcs.win_move_statusline(0, 1)
- eq(1, meths.get_option('cmdheight'))
- end)
-
- it('mouse dragging can reduce cmdheight to 1', function()
- command('set mouse=a')
- meths.input_mouse('left', 'press', '', 0, 14, 10)
- eq(1, meths.get_option('cmdheight'))
- meths.input_mouse('left', 'drag', '', 0, 13, 10)
- eq(2, meths.get_option('cmdheight'))
- meths.input_mouse('left', 'drag', '', 0, 12, 10)
- eq(3, meths.get_option('cmdheight'))
- meths.input_mouse('left', 'drag', '', 0, 13, 10)
- eq(2, meths.get_option('cmdheight'))
- meths.input_mouse('left', 'drag', '', 0, 14, 10)
- eq(1, meths.get_option('cmdheight'))
- end)
-end)
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 879c44773a..fb80444430 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -123,13 +123,11 @@ describe(":substitute, inccommand=split interactivity", function()
it("no preview if invoked by feedkeys()", function()
-- in a script...
source([[:call feedkeys(":%s/tw/MO/g\<CR>")]])
- poke_eventloop()
-- or interactively...
- feed([[:call feedkeys(":%s/tw/MO/g\<CR>")<CR>]])
- poke_eventloop()
+ feed([[:call feedkeys(":%s/bs/BUU/g\<lt>CR>")<CR>]])
eq(1, eval("bufnr('$')"))
-- sanity check: assert the buffer state
- expect(default_text:gsub("tw", "MO"))
+ expect(default_text:gsub("tw", "MO"):gsub("bs", "BUU"))
end)
end)
@@ -381,7 +379,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
}
local function test_sub(substring, split, redoable)
- clear()
+ command('bwipe!')
feed_command("set inccommand=" .. split)
insert("1")
@@ -407,7 +405,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
end
local function test_notsub(substring, split, redoable)
- clear()
+ command('bwipe!')
feed_command("set inccommand=" .. split)
insert("1")
@@ -441,7 +439,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
local function test_threetree(substring, split)
- clear()
+ command('bwipe!')
feed_command("set inccommand=" .. split)
insert("1")
@@ -493,6 +491,8 @@ describe(":substitute, 'inccommand' preserves undo", function()
2]])
end
+ before_each(clear)
+
it("at a non-leaf of the undo tree", function()
for _, case in pairs(cases) do
for _, str in pairs(substrings) do
@@ -1646,10 +1646,12 @@ end)
describe("'inccommand' and :cnoremap", function()
local cases = { "", "split", "nosplit" }
+ local screen
- local function refresh(case)
+ local function refresh(case, visual)
clear()
- common_setup(nil, case, default_text)
+ screen = visual and Screen.new(50,10) or nil
+ common_setup(screen, case, default_text)
end
it('work with remapped characters', function()
@@ -1706,10 +1708,12 @@ describe("'inccommand' and :cnoremap", function()
it('still works with a broken mapping', function()
for _, case in pairs(cases) do
- refresh(case)
+ refresh(case, true)
feed_command("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
feed(":%s/tw/tox<enter>")
+ screen:expect{any=[[{14:^E523:]]}
+ feed('<c-c>')
-- error thrown b/c of the mapping
neq(nil, eval('v:errmsg'):find('^E523:'))
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 041337df8a..ee49ae7a09 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -304,13 +304,25 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ]], messages={
+ ]], msg_history={
{kind="echoerr", content={{"raa", 2}}},
{kind="echoerr", content={{"bork", 2}}},
{kind="echoerr", content={{"fail", 2}}},
{kind="echoerr", content={{"extrafail", 2}}},
{kind="echoerr", content={{"problem", 2}}}
- }}
+ }, messages={{
+ content = {{ "Press ENTER or type command to continue", 4 }},
+ kind = "return_prompt"
+ }}}
+
+ feed '<cr>'
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
end)
it('shortmess-=S', function()
@@ -455,11 +467,14 @@ describe('ui/ext_messages', function()
alphpabe^t |
{1:~ }|
{1:~ }|
- ]], messages={
- {kind="echomsg", content={{"stuff"}}},
- }, showmode={
- { "-- INSERT --", 3 }
- }}
+ ]], msg_history={{
+ content = {{ "stuff" }},
+ kind = "echomsg",
+ }}, showmode={{ "-- INSERT --", 3 }},
+ messages={{
+ content = {{ "Press ENTER or type command to continue", 4}},
+ kind = "return_prompt"
+ }}}
end)
it('&showmode with macro-recording message', function()
@@ -685,12 +700,15 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ]], messages={
+ ]], msg_history={
{kind="echomsg", content={{"howdy"}}},
{kind="", content={{"Type :qa and press <Enter> to exit Nvim"}}},
{kind="echoerr", content={{"bork", 2}}},
{kind="emsg", content={{"E117: Unknown function: nosuchfunction", 2}}}
- }}
+ }, messages={{
+ content = {{ "Press ENTER or type command to continue", 4}},
+ kind = "return_prompt"
+ }}}
end)
it('implies ext_cmdline and ignores cmdheight', function()
@@ -1209,7 +1227,6 @@ describe('ui/ext_messages', function()
it('supports global statusline', function()
feed(":set laststatus=3<cr>")
feed(":sp<cr>")
- feed("<c-l>")
feed(":set cmdheight<cr>")
screen:expect({grid=[[
^ |
@@ -1241,8 +1258,7 @@ describe('ui/ext_messages', function()
}})
feed("<c-w>+")
- feed("<c-l>")
- feed(":set cmdheight<cr>")
+ feed(":set laststatus<cr>")
screen:expect({grid=[[
^ |
{1:~ }|
@@ -1269,7 +1285,7 @@ describe('ui/ext_messages', function()
{1:~ }|
{7:[No Name] }|
]], messages={
- {content = { { " cmdheight=0" } }, kind = "" }
+ {content = { { " laststatus=3" } }, kind = "" }
}})
feed(":set mouse=a<cr>")
@@ -1312,7 +1328,6 @@ end)
describe('ui/msg_puts_printf', function()
it('output multibyte characters correctly', function()
- if helpers.pending_win32(pending) then return end
local screen
local cmd = ''
local locale_dir = test_build_dir..'/share/locale/ja/LC_MESSAGES'
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 20e8821009..b30aa67fd3 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -1915,7 +1915,7 @@ describe('ext_multigrid', function()
{1:~ }|
]]}
- meths.input_mouse('left', 'press', '', 1,6, 20)
+ meths.input_mouse('left', 'press', '', 1, 6, 20)
-- TODO(bfredl): "batching" input_mouse is formally not supported yet.
-- Normally it should work fine in async context when nvim is not blocked,
-- but add a poke_eventloop be sure.
@@ -2092,7 +2092,6 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
]]}
-
end)
it('has viewport information', function()
@@ -2369,4 +2368,223 @@ describe('ext_multigrid', function()
[2] = {win = {id = 1000}, topline = 6, botline = 12, curline = 10, curcol = 1, linecount = 11},
}}
end)
+
+ it('with winbar', function()
+ command 'split'
+ command 'setlocal winbar=very\\ bar'
+ screen:expect{grid=[[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:very bar }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ end)
+
+ it('with winbar dragging statusline with mouse works correctly', function()
+ meths.set_option('winbar', 'Set Up The Bars')
+ command('split')
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+
+ meths.input_mouse('left', 'press', '', 1, 6, 20)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 7, 20)
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+
+ meths.input_mouse('left', 'drag', '', 1, 4, 20)
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ ]])
+
+ meths.input_mouse('left', 'press', '', 1, 12, 10)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 10, 10)
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ [3:-----------------------------------------------------]|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ |
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ ]])
+ eq(3, meths.get_option('cmdheight'))
+
+ meths.input_mouse('left', 'drag', '', 1, 12, 10)
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ ]])
+ eq(1, meths.get_option('cmdheight'))
+ end)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 7305baa761..50e5dfac84 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -14,7 +14,6 @@ local has_powershell = helpers.has_powershell
local set_shell_powershell = helpers.set_shell_powershell
describe("shell command :!", function()
- if helpers.pending_win32(pending) then return end
local screen
before_each(function()
clear()
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 06daabad1a..d6de1fa8a9 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -242,7 +242,7 @@ end
-- canonical order of ext keys, used to generate asserts
local ext_keys = {
'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos',
- 'messages', 'showmode', 'showcmd', 'ruler', 'float_pos', 'win_viewport'
+ 'messages', 'msg_history', 'showmode', 'showcmd', 'ruler', 'float_pos', 'win_viewport'
}
-- Asserts that the screen state eventually matches an expected state.
@@ -1083,6 +1083,10 @@ function Screen:_handle_msg_history_show(entries)
self.msg_history = entries
end
+function Screen:_handle_msg_history_clear()
+ self.msg_history = {}
+end
+
function Screen:_clear_block(grid, top, bot, left, right)
for i = top, bot do
self:_clear_row_section(grid, i, left, right)
@@ -1171,7 +1175,7 @@ function Screen:_extstate_repr(attr_state)
local msg_history = {}
for i, entry in ipairs(self.msg_history) do
- messages[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)}
+ msg_history[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)}
end
local win_viewport = (next(self.win_viewport) and self.win_viewport) or nil
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 56ff8a4101..cdb6256f77 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -43,7 +43,7 @@ describe('search highlighting', function()
insert("some text\nmore text")
feed_command('1,2fold')
feed("gg/text")
- screen:expect([[
+ screen:expect{grid=[[
{6:+-- 2 lines: some text·················}|
{1:~ }|
{1:~ }|
@@ -51,7 +51,9 @@ describe('search highlighting', function()
{1:~ }|
{1:~ }|
/text^ |
- ]])
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 9, linecount = 2};
+ }}
end)
it('works', function()
@@ -579,19 +581,20 @@ describe('search highlighting', function()
end)
it('works with matchadd and syntax', function()
- screen:set_default_attr_ids( {
- [1] = {bold=true, foreground=Screen.colors.Blue},
- [2] = {background = colors.Yellow},
- [3] = {reverse = true},
- [4] = {foreground = colors.Red},
- [5] = {bold = true, background = colors.Green},
- [6] = {italic = true, background = colors.Magenta},
- [7] = {bold = true, background = colors.Yellow},
- } )
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {background = colors.Yellow};
+ [3] = {reverse = true};
+ [4] = {foreground = colors.Red};
+ [5] = {bold = true, background = colors.Green};
+ [6] = {italic = true, background = colors.Magenta};
+ [7] = {bold = true, background = colors.Yellow};
+ [8] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGray};
+ }
feed_command('set hlsearch')
- insert([[
+ insert [[
very special text
- ]])
+ ]]
feed_command("syntax on")
feed_command("highlight MyGroup guibg=Green gui=bold")
feed_command("highlight MyGroup2 guibg=Magenta gui=italic")
@@ -601,7 +604,7 @@ describe('search highlighting', function()
-- searchhl and matchadd matches are exclusive, only the highest priority
-- is used (and matches with lower priorities are not combined)
feed_command("/ial te")
- screen:expect([[
+ screen:expect{grid=[[
very {5:spec^ial}{2: te}{6:xt} |
|
{1:~ }|
@@ -609,10 +612,21 @@ describe('search highlighting', function()
{1:~ }|
{1:~ }|
{4:search hit BOTTOM, continuing at TOP} |
- ]])
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 11, linecount = 2};
+ }}
-- check highlights work also in folds
feed("zf4j")
+ screen:expect{grid=[[
+ {8:^+-- 2 lines: very special text·········}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {4:search hit BOTTOM, continuing at TOP} |
+ ]]}
command("%foldopen")
screen:expect([[
very {5:spec^ial}{2: te}{6:xt} |
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
new file mode 100644
index 0000000000..3e1b284856
--- /dev/null
+++ b/test/functional/ui/statusline_spec.lua
@@ -0,0 +1,317 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local feed = helpers.feed
+local eq = helpers.eq
+local funcs = helpers.funcs
+local meths = helpers.meths
+local exec = helpers.exec
+local exec_lua = helpers.exec_lua
+local eval = helpers.eval
+
+describe('statusline clicks', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 8)
+ screen:attach()
+ command('set laststatus=2')
+ exec([=[
+ function! MyClickFunc(minwid, clicks, button, mods)
+ let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button)
+ endfunction
+ ]=])
+ end)
+
+ it('works', function()
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 6, 17)
+ eq('0 1 r', eval("g:testvar"))
+ end)
+
+ it('works for winbar', function()
+ meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 0, 17)
+ eq('0 1 l', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 6, 17)
+ eq('0 1 r', eval("g:testvar"))
+ end)
+
+ it('works for winbar in floating window', function()
+ meths.open_win(0, true, { width=30, height=4, relative='editor', row=1, col=5,
+ border = "single" })
+ meths.set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T',
+ { scope = 'local' })
+ meths.input_mouse('left', 'press', '', 0, 2, 23)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('works when there are multiple windows', function()
+ command('split')
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 0, 17)
+ eq('0 1 l', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 4, 17)
+ eq('0 1 r', eval("g:testvar"))
+ meths.input_mouse('middle', 'press', '', 0, 3, 17)
+ eq('0 1 m', eval("g:testvar"))
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('works with Lua function', function()
+ exec_lua([[
+ function clicky_func(minwid, clicks, button, mods)
+ vim.g.testvar = string.format("%d %d %s", minwid, clicks, button)
+ end
+ ]])
+ meths.set_option('statusline', 'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('ignores unsupported click items', function()
+ command('tabnew | tabprevious')
+ meths.set_option('statusline', '%2TNot clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 0)
+ eq(1, meths.get_current_tabpage().id)
+ meths.set_option('statusline', '%2XNot clicky stuff%X')
+ meths.input_mouse('left', 'press', '', 0, 6, 0)
+ eq(2, #meths.list_tabpages())
+ end)
+end)
+
+describe('global statusline', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 16)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue};
+ [2] = {bold = true, reverse = true};
+ [3] = {bold = true};
+ [4] = {reverse = true};
+ })
+ command('set laststatus=3')
+ command('set ruler')
+ end)
+
+ it('works', function()
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ feed('i<CR><CR>')
+ screen:expect([[
+ |
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] [+] 3,1 All}|
+ {3:-- INSERT --} |
+ ]])
+ end)
+
+ it('works with splits', function()
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+ end)
+
+ it('works when switching between values of laststatus', function()
+ command('set laststatus=1')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ 0,0-1 All |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ command('set laststatus=2')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}|
+ {1:~ }│{1:~ }│{1:~}│ |
+ {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {4:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('set laststatus=0')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}|
+ {1:~ }│{1:~ }│{1:~}│ |
+ {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ 0,0-1 All |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+ end)
+
+ it('win_move_statusline() can reduce cmdheight to 1', function()
+ eq(1, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, -1)
+ eq(2, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, -1)
+ eq(3, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, 1)
+ eq(2, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, 1)
+ eq(1, meths.get_option('cmdheight'))
+ end)
+
+ it('mouse dragging can reduce cmdheight to 1', function()
+ command('set mouse=a')
+ meths.input_mouse('left', 'press', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 13, 10)
+ eq(2, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 12, 10)
+ eq(3, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 13, 10)
+ eq(2, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ end)
+end)
diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua
new file mode 100644
index 0000000000..83bc61bc4e
--- /dev/null
+++ b/test/functional/ui/winbar_spec.lua
@@ -0,0 +1,422 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local insert = helpers.insert
+local meths = helpers.meths
+local eq = helpers.eq
+local poke_eventloop = helpers.poke_eventloop
+local feed = helpers.feed
+
+describe('winbar', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 13)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true},
+ [2] = {reverse = true},
+ [3] = {bold = true, foreground = Screen.colors.Blue},
+ [4] = {bold = true, reverse = true},
+ [5] = {bold = true, foreground = Screen.colors.Red},
+ [6] = {foreground = Screen.colors.Blue},
+ [7] = {background = Screen.colors.LightGrey},
+ })
+ meths.set_option('winbar', 'Set Up The Bars')
+ end)
+ it('works', function()
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+ it('works with custom \'fillchars\' value', function()
+ command('set fillchars=wbr:+')
+ screen:expect([[
+ {1:Set Up The Bars+++++++++++++++++++++++++++++++++++++++++++++}|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+ it('works with custom highlight', function()
+ command('hi WinBar guifg=red')
+ screen:expect([[
+ {5:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+ it('works with splits', function()
+ command('hi WinBar guifg=red')
+ command('hi WinBarNC guifg=blue')
+ command('belowright vsplit | split | split')
+ screen:expect([[
+ {6:Set Up The Bars }│{5:Set Up The Bars }|
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{4:[No Name] }|
+ {3:~ }│{6:Set Up The Bars }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{2:[No Name] }|
+ {3:~ }│{6:Set Up The Bars }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {2:[No Name] [No Name] }|
+ |
+ ]])
+ end)
+ it('works when switching value of \'winbar\'', function()
+ command('belowright vsplit | split | split | set winbar=')
+ screen:expect([[
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {3:~ }│{4:[No Name] }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {3:~ }│{2:[No Name] }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {2:[No Name] [No Name] }|
+ |
+ ]])
+ command('set winbar=All\\ Your\\ Bar\\ Are\\ Belong\\ To\\ Us')
+ screen:expect([[
+ {1:All Your Bar Are Belong To Us}│{1:All Your Bar Are Belong To Us }|
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{4:[No Name] }|
+ {3:~ }│{1:All Your Bar Are Belong To Us }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{2:[No Name] }|
+ {3:~ }│{1:All Your Bar Are Belong To Us }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {2:[No Name] [No Name] }|
+ |
+ ]])
+ command('set winbar=Changed\\ winbar')
+ screen:expect([[
+ {1:Changed winbar }│{1:Changed winbar }|
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{4:[No Name] }|
+ {3:~ }│{1:Changed winbar }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{2:[No Name] }|
+ {3:~ }│{1:Changed winbar }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {2:[No Name] [No Name] }|
+ |
+ ]])
+ end)
+ it('can be ruler', function()
+ insert [[
+ just some
+ random text]]
+ meths.set_option('winbar', 'Hello, I am a ruler: %l,%c')
+ screen:expect{grid=[[
+ {1:Hello, I am a ruler: 2,11 }|
+ just some |
+ random tex^t |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ feed 'b'
+ screen:expect{grid=[[
+ {1:Hello, I am a ruler: 2,8 }|
+ just some |
+ random ^text |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ feed 'k'
+ screen:expect{grid=[[
+ {1:Hello, I am a ruler: 1,8 }|
+ just so^me |
+ random text |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ end)
+ it('works with laststatus=3', function()
+ command('set laststatus=3')
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+ command('belowright vsplit | split | split')
+ screen:expect([[
+ {1:Set Up The Bars }│{1:Set Up The Bars }|
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }├──────────────────────────────|
+ {3:~ }│{1:Set Up The Bars }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }├──────────────────────────────|
+ {3:~ }│{1:Set Up The Bars }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+ end)
+
+ it('mouse click and drag work correctly in buffer', function()
+ insert([[
+ line 1
+ line 2
+ line 3
+ line 4
+ line -42
+ line i
+ line sin(theta)
+ line 8]])
+
+ meths.input_mouse('left', 'press', '', 0, 5, 1)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ line 1 |
+ line 2 |
+ line 3 |
+ line 4 |
+ l^ine -42 |
+ line i |
+ line sin(theta) |
+ line 8 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ eq({5, 1}, meths.win_get_cursor(0))
+
+ meths.input_mouse('left', 'drag', '', 0, 6, 2)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ line 1 |
+ line 2 |
+ line 3 |
+ line 4 |
+ l{7:ine -42} |
+ {7:li}^ne i |
+ line sin(theta) |
+ line 8 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {1:-- VISUAL --} |
+ ]])
+ eq({6, 2}, meths.win_get_cursor(0))
+
+ meths.input_mouse('left', 'drag', '', 0, 1, 2)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ li^n{7:e 1} |
+ {7:line 2} |
+ {7:line 3} |
+ {7:line 4} |
+ {7:li}ne -42 |
+ line i |
+ line sin(theta) |
+ line 8 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {1:-- VISUAL --} |
+ ]])
+ eq({1, 2}, meths.win_get_cursor(0))
+
+ meths.input_mouse('left', 'drag', '', 0, 0, 2)
+ screen:expect_unchanged()
+ eq({1, 2}, meths.win_get_cursor(0))
+ end)
+
+ it('dragging statusline with mouse works correctly', function()
+ command('split')
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+
+ meths.input_mouse('left', 'press', '', 1, 5, 10)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 6, 10)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+
+ meths.input_mouse('left', 'drag', '', 1, 4, 10)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+
+ meths.input_mouse('left', 'press', '', 1, 11, 10)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 9, 10)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ |
+ |
+ ]])
+ eq(3, meths.get_option('cmdheight'))
+
+ meths.input_mouse('left', 'drag', '', 1, 11, 10)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+ eq(1, meths.get_option('cmdheight'))
+ end)
+ it('properly equalizes window height for window-local value', function()
+ command('set equalalways | set winbar= | setlocal winbar=a | split')
+ command('setlocal winbar= | split')
+ command('setlocal winbar=b | split')
+ screen:expect([[
+ {1:b }|
+ ^ |
+ {4:[No Name] }|
+ {1:b }|
+ |
+ {2:[No Name] }|
+ |
+ {3:~ }|
+ {2:[No Name] }|
+ {1:a }|
+ |
+ {2:[No Name] }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index e21c71dc7f..a733b098f5 100644
--- a/test/functional/vimscript/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -153,7 +153,7 @@ describe('execute()', function()
function! Test3()
echo 1234
let x = execute('echoerr "abcdef"', 'silent!')
- echon 'ABCD'
+ echon 'ABCDXZYZ'
endfunction
" test 4: silenced echoerr goes as usual
@@ -214,7 +214,7 @@ describe('execute()', function()
~ |
~ |
~ |
- 1234ABCD |
+ 1234ABCDXZYZ |
]])
feed([[:call Test4()<cr>]])
diff --git a/test/unit/fixtures/rbuffer.c b/test/unit/fixtures/rbuffer.c
index 3f4062fa18..efa7ab1986 100644
--- a/test/unit/fixtures/rbuffer.c
+++ b/test/unit/fixtures/rbuffer.c
@@ -15,7 +15,7 @@ void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb)
void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb)
{
- RBUFFER_UNTIL_FULL(buf, wptr, wcnt) {
+ RBUFFER_UNTIL_FULL(buf, wptr, wcnt) { // -V1044
cb(wptr, wcnt);
rbuffer_produced(buf, wcnt);
}
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index 465b553693..4dbcaa5347 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -96,6 +96,7 @@ local init = only_separate(function()
c.func(unpack(c.args))
end
libnvim.time_init()
+ libnvim.fs_init()
libnvim.event_init()
libnvim.early_init(nil)
if child_calls_mod then
@@ -778,7 +779,8 @@ local function cppimport(path)
return cimport(Paths.test_source_path .. '/test/includes/pre/' .. path)
end
-cimport('./src/nvim/types.h', './src/nvim/main.h', './src/nvim/os/time.h')
+cimport('./src/nvim/types.h', './src/nvim/main.h', './src/nvim/os/time.h',
+ './src/nvim/os/fs.h')
local function conv_enum(etab, eval)
local n = tonumber(eval)
diff --git a/test/unit/search_spec.lua b/test/unit/search_spec.lua
index 3c2d485e0e..ef5a0cb831 100644
--- a/test/unit/search_spec.lua
+++ b/test/unit/search_spec.lua
@@ -5,6 +5,8 @@ local to_cstr = helpers.to_cstr
local eq = helpers.eq
local search = helpers.cimport("./src/nvim/search.h")
+local globals = helpers.cimport('./src/nvim/globals.h')
+local ffi = helpers.ffi
itp('pat_has_uppercase', function()
-- works on empty string
@@ -31,3 +33,25 @@ itp('pat_has_uppercase', function()
eq(false, search.pat_has_uppercase(to_cstr("aa\\%Ab")))
eq(true, search.pat_has_uppercase(to_cstr("aab\\%AU")))
end)
+
+describe('search_regcomp', function()
+ local search_regcomp = function(pat, pat_save, pat_use, options )
+ local regmatch = ffi.new("regmmatch_T")
+ local fail = search.search_regcomp(to_cstr(pat), pat_save, pat_use, options, regmatch)
+ return fail, regmatch
+ end
+
+ local get_search_pat = function()
+ return helpers.internalize(search.get_search_pat())
+ end
+
+ itp("accepts regexp pattern with invalid utf", function()
+ --crafted to call reverse_text with invalid utf
+ globals.curwin.w_onebuf_opt.wo_rl = 1
+ globals.curwin.w_onebuf_opt.wo_rlc = to_cstr('s')
+ globals.cmdmod.keeppatterns = 1
+ local fail = search_regcomp("a\192", 0,0,0)
+ eq(1, fail)
+ eq("\192a", get_search_pat())
+ end)
+end)
diff --git a/test/unit/strings_spec.lua b/test/unit/strings_spec.lua
index e085ac749d..b2c839f25c 100644
--- a/test/unit/strings_spec.lua
+++ b/test/unit/strings_spec.lua
@@ -150,3 +150,38 @@ describe('strcase_save()' , function()
eq("a", strcase_save("\xc1\x81", false))
end)
end)
+
+describe("reverse_text", function()
+ local reverse_text = function(str)
+ return helpers.internalize(strings.reverse_text(to_cstr(str)))
+ end
+
+ itp("handles empty string", function()
+ eq("", reverse_text(""))
+ end)
+
+ itp("handles simple cases", function()
+ eq("a", reverse_text("a"))
+ eq("ba", reverse_text("ab"))
+ end)
+
+ itp("handles multibyte characters", function()
+ eq("bα", reverse_text("αb"))
+ eq("Yötön yö", reverse_text("öy nötöY"))
+ end)
+
+ itp("handles combining chars", function()
+ local utf8_COMBINING_RING_ABOVE = "\204\138"
+ local utf8_COMBINING_RING_BELOW = "\204\165"
+ eq("bba" .. utf8_COMBINING_RING_ABOVE .. utf8_COMBINING_RING_BELOW .. "aa",
+ reverse_text("aaa" .. utf8_COMBINING_RING_ABOVE .. utf8_COMBINING_RING_BELOW .. "bb"))
+ end)
+
+ itp("treats invalid utf as separate characters", function()
+ eq("\192ba", reverse_text("ab\192"))
+ end)
+
+ itp("treats an incomplete utf continuation sequence as valid", function()
+ eq("\194ba", reverse_text("ab\194"))
+ end)
+end)
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 21d1f7906a..06c3d47104 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -139,15 +139,15 @@ endif()
include(ExternalProject)
-set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.44.1.tar.gz)
-set(LIBUV_SHA256 e91614e6dc2dd0bfdd140ceace49438882206b7a6fb00b8750914e67a9ed6d6b)
+set(LIBUV_URL https://github.com/libuv/libuv/archive/730e07e2f77a4001bdf6894112271c926399f5a8.tar.gz)
+set(LIBUV_SHA256 271869759a7dbdaf1d1bf75f1ec388a7307592153b34ebb52d3934715cbaac8a)
set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/c-4.0.0/msgpack-c-4.0.0.tar.gz)
set(MSGPACK_SHA256 420fe35e7572f2a168d17e660ef981a589c9cbe77faa25eb34a520e1fcc032c8)
# https://github.com/LuaJIT/LuaJIT/tree/v2.1
-set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/91bc6b8ad1f373c1ce9003dc024b2e21fad0e444.tar.gz)
-set(LUAJIT_SHA256 81895031fdb87602c7dde52280259c60b1ffd1b5a8a3c2792d3e2390481163fa)
+set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/4ef96cff887c268cc676f9b4b1dc9c54a693efd5.tar.gz)
+set(LUAJIT_SHA256 ae913e33be80dded08a2fc368787f168305c22808519c962553bf4c8668e9856)
set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz)
set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333)