diff options
270 files changed, 5184 insertions, 3281 deletions
diff --git a/.clang-format b/.clang-format index a37e2fdbd1..afb0df2e25 100644 --- a/.clang-format +++ b/.clang-format @@ -45,6 +45,7 @@ IncludeCategories: Priority: 1 SortPriority: 1 CaseSensitive: false +AlignConsecutiveMacros: AcrossEmptyLines IndentPPDirectives: AfterHash SpaceBeforeParens: ControlStatementsExceptControlMacros ForEachMacros: @@ -62,4 +63,4 @@ ForEachMacros: - RBUFFER_EACH_REVERSE - RBUFFER_UNTIL_EMPTY - RBUFFER_UNTIL_FULL - - kl_iter
\ No newline at end of file + - kl_iter diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml index ce8ed7996a..52f312c75f 100644 --- a/.github/workflows/api-docs.yml +++ b/.github/workflows/api-docs.yml @@ -21,23 +21,24 @@ on: jobs: regen-api-docs: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 permissions: contents: write pull-requests: write env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: + # Fetch depth 0 is required if called through workflow_call. In order + # to create a PR we need to access other branches, which requires a + # full clone. fetch-depth: 0 - name: Install dependencies run: | sudo apt-get update - sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y python3 luajit - conda install -c conda-forge doxygen=1.9.2 msgpack-python - echo "$CONDA/bin" >> $GITHUB_PATH + sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y doxygen python3 python3-msgpack luajit - name: Setup git config run: | 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 }} @@ -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/CMakeLists.txt b/CMakeLists.txt index 19c81ffcbe..d75c1a4a6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,7 +108,14 @@ endif() option(ENABLE_LIBINTL "enable libintl" ON) option(ENABLE_LIBICONV "enable libiconv" ON) -option(ENABLE_LTO "enable link time optimization" ON) +if (MINGW) + # Disable LTO by default as it may not compile + # See https://github.com/Alexpux/MINGW-packages/issues/3516 + # and https://github.com/neovim/neovim/pull/8654#issuecomment-402316672 + option(ENABLE_LTO "enable link time optimization" OFF) +else() + option(ENABLE_LTO "enable link time optimization" ON) +endif() message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") @@ -315,6 +322,10 @@ else() endif() endif() +if(MINGW) + # Use POSIX compatible stdio in Mingw + add_definitions(-D__USE_MINGW_ANSI_STDIO) +endif() if(WIN32) # Windows Vista is the minimum supported version add_definitions(-D_WIN32_WINNT=0x0600) @@ -442,7 +453,7 @@ endif() option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF) if(PREFER_LUA) - find_package(Lua 5.1 REQUIRED) + find_package(Lua 5.1 EXACT REQUIRED) set(LUA_PREFERRED_INCLUDE_DIRS ${LUA_INCLUDE_DIR}) set(LUA_PREFERRED_LIBRARIES ${LUA_LIBRARIES}) # Passive (not REQUIRED): if LUAJIT_FOUND is not set, nvim-test is skipped. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 078377dcc2..e26d0d63c5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -92,7 +92,7 @@ the VCS/git logs more valuable. The general structure of a commit message is: ``` - Prefix the commit subject with one of these [_types_](https://github.com/commitizen/conventional-commit-types/blob/master/index.json): - - `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `test`, `vim-patch`, `chore` + - `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `test`, `vim-patch`, `dist` - You can **ignore this for "fixup" commits** or any commits you expect to be squashed. - Append optional scope to _type_ such as `(lsp)`, `(treesitter)`, `(float)`, … - _Description_ shouldn't start with a capital letter or end in a period. diff --git a/cmake/FindLuaJit.cmake b/cmake/FindLuaJit.cmake index c904347f6a..72795afefd 100644 --- a/cmake/FindLuaJit.cmake +++ b/cmake/FindLuaJit.cmake @@ -17,6 +17,8 @@ find_path(LUAJIT_INCLUDE_DIR luajit.h if(MSVC) list(APPEND LUAJIT_NAMES lua51) +elseif(MINGW) + list(APPEND LUAJIT_NAMES libluajit libluajit-5.1) else() list(APPEND LUAJIT_NAMES luajit-5.1) endif() diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim index f3732e012f..9b387095ee 100644 --- a/runtime/autoload/health/nvim.vim +++ b/runtime/autoload/health/nvim.vim @@ -45,7 +45,7 @@ function! s:check_config() abort let shadafile = empty(&shada) ? &shada : substitute(matchstr( \ split(&shada, ',')[-1], '^n.\+'), '^n', '', '') let shadafile = empty(&shadafile) ? empty(shadafile) ? - \ stdpath('data').'/shada/main.shada' : expand(shadafile) + \ stdpath('state').'/shada/main.shada' : expand(shadafile) \ : &shadafile ==# 'NONE' ? '' : &shadafile if !empty(shadafile) && empty(glob(shadafile)) " Since this may be the first time neovim has been run, we will try to 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 812208ca31..3ab7c77056 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -442,6 +442,9 @@ to disable various visual features such as the 'number' column. Currently, floating windows don't support some widgets like scrollbar. +The output of |:mksession| does not include commands for restoring floating +windows. + Example: create a float with scratch buffer: > let buf = nvim_create_buf(v:false, v:true) @@ -844,8 +847,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 @@ -1668,12 +1674,18 @@ nvim_set_option_value({name}, {value}, {*opts}) global and local value are set unless otherwise specified with {scope}. + Note the options {win} and {buf} cannot be used together. + Parameters: ~ {name} Option name {value} New option value {opts} Optional parameters • scope: One of 'global' or 'local'. Analogous to |:setglobal| and |:setlocal|, respectively. + • win: |window-ID|. Used for setting window local + option. + • buf: Buffer number. Used for setting buffer + local option. nvim_set_var({name}, {value}) *nvim_set_var()* Sets a global (g:) variable. @@ -1725,8 +1737,7 @@ Vimscript Functions *api-vimscript* nvim_call_dict_function({dict}, {fn}, {args}) Calls a VimL |Dictionary-function| with the given arguments. - On execution error: fails with VimL error, does not update - v:errmsg. + On execution error: fails with VimL error, updates v:errmsg. Parameters: ~ {dict} Dictionary, or String evaluating to a VimL |self| @@ -1740,8 +1751,7 @@ nvim_call_dict_function({dict}, {fn}, {args}) nvim_call_function({fn}, {args}) *nvim_call_function()* Calls a VimL function with the given arguments. - On execution error: fails with VimL error, does not update - v:errmsg. + On execution error: fails with VimL error, updates v:errmsg. Parameters: ~ {fn} Function to call @@ -1760,6 +1770,8 @@ nvim_cmd({*cmd}, {*opts}) *nvim_cmd()* argument, expanding filenames in a command that otherwise doesn't expand filenames, etc. + On execution error: fails with VimL error, updates v:errmsg. + Parameters: ~ {cmd} Command to execute. Must be a Dictionary that can contain the same values as the return value of @@ -1781,8 +1793,7 @@ nvim_cmd({*cmd}, {*opts}) *nvim_cmd()* nvim_command({command}) *nvim_command()* Executes an Ex command. - On execution error: fails with VimL error, does not update - v:errmsg. + On execution error: fails with VimL error, updates v:errmsg. Prefer using |nvim_cmd()| or |nvim_exec()| over this. To evaluate multiple lines of Vim script or an Ex command @@ -1798,8 +1809,7 @@ nvim_eval({expr}) *nvim_eval()* Evaluates a VimL |expression|. Dictionaries and Lists are recursively expanded. - On execution error: fails with VimL error, does not update - v:errmsg. + On execution error: fails with VimL error, updates v:errmsg. Parameters: ~ {expr} VimL expression string @@ -1814,8 +1824,7 @@ nvim_exec({src}, {output}) *nvim_exec()* Unlike |nvim_command()| this function supports heredocs, script-scope (s:), etc. - On execution error: fails with VimL error, does not update - v:errmsg. + On execution error: fails with VimL error, updates v:errmsg. Parameters: ~ {src} Vimscript code @@ -2656,13 +2665,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 @@ -3469,6 +3477,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 @@ -3544,6 +3554,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..41f083687d 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 @@ -1074,19 +1120,13 @@ format({options}) *vim.lsp.buf.format()* • bufnr (number|nil): Restrict formatting to the clients attached to the given buffer, defaults to the current buffer (0). - • filter (function|nil): Predicate to filter clients used - for formatting. Receives the list of clients attached to - bufnr as the argument and must return the list of - clients on which to request formatting. Example: • > + • filter (function|nil): Predicate used to filter clients. + Receives a client as argument and must return a boolean. + Clients matching the predicate are included. Example: • > -- Never request typescript-language-server for formatting vim.lsp.buf.format { - filter = function(clients) - return vim.tbl_filter( - function(client) return client.name ~= "tsserver" end, - clients - ) - end + filter = function(client) return client.name ~= "tsserver" end } < • async boolean|nil If true the method won't block. @@ -1231,10 +1271,10 @@ rename({new_name}, {options}) *vim.lsp.buf.rename()* prompted for a new name using |vim.ui.input()|. {options} (table|nil) additional options - • filter (function|nil): Predicate to filter - clients used for rename. Receives the - attached clients as argument and must return - a list of clients. + • filter (function|nil): Predicate used to + filter clients. Receives a client as + argument and must return a boolean. Clients + matching the predicate are included. • name (string|nil): Restrict clients used for rename to ones where client.name matches this field. @@ -1250,10 +1290,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 +1584,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/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index 49e29111c6..b19343e7ef 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -304,7 +304,7 @@ breakpoint, or use the "Clear breakpoint" right-click menu entry. Inspecting variables ~ *termdebug-variables* *:Evaluate* `:Evaluate` evaluate the expression under the cursor - `K` same + `K` same (see |termdebug_map_K| to disable) `:Evaluate` {expr} evaluate {expr} `:'<,'>Evaluate` evaluate the Visually selected text @@ -333,7 +333,7 @@ Four autocommands can be used: > *TermdebugStartPre* TermdebugStartPre Before starting debugging. Not triggered if the debugger is already - running or |g:termdebugger| cannot be + running or the debugger command cannot be executed. *TermdebugStartPost* TermdebugStartPost After debugging has initialized. @@ -362,14 +362,24 @@ This works slightly differently: *termdebug_use_prompt* Prompt mode can be used with: > + let g:termdebug_config['use_prompt'] = 1 +Or if there is no g:termdebug_config: > let g:termdebug_use_prompt = 1 - +< + *termdebug_map_K* +The K key is normally mapped to :Evaluate. If you do not want this use: > + let g:termdebug_config['map_K'] = 0 +Or if there is no g:termdebug_config: > + let g:termdebug_map_K = 0 < *termdebug_disasm_window* -If you want the Asm window shown by default, set this to 1. Setting to -any value greater than 1 will set the Asm window height to that value: > +If you want the Asm window shown by default, set the flag to 1. +the "disasm_window_height" entry can be used to set the window height: > + let g:termdebug_config['disasm_window'] = 1 + let g:termdebug_config['disasm_window_height'] = 15 +or, if there is no g:termdebug_config: > let g:termdebug_disasm_window = 15 -< +Any value greater than 1 will set the Asm window height to that value: > Communication ~ *termdebug-communication* @@ -386,13 +396,24 @@ communication channel. Customizing ~ + *termdebug-customizing* *g:termdebug_config* +In the past several global variables were used for configuration. These are +deprecated, using the g:termdebug_config dictionary is preferred. When +g:termdebug_config exists the other global variables will not be used. -GDB command *termdebug-customizing* -To change the name of the gdb command, set the "termdebugger" variable before -invoking `:Termdebug`: > - let termdebugger = "mygdb" +GDB command ~ + *g:termdebugger* +To change the name of the gdb command, set "debugger" entry in +g:termdebug_config or the "g:termdebugger" variable before invoking +`:Termdebug`: > + let g:termdebug_config['command'] = "mygdb" +Or if there is no g:termdebug_config: > + let g:termdebugger = "mygdb" + If the command needs an argument use a List: > + let g:termdebug_config['command'] = ['rr', 'replay', '--'] +Or if there is no g:termdebug_config: > let g:termdebugger = ['rr', 'replay', '--'] To not use neovim floating windows for previewing variable evaluation, set the @@ -406,7 +427,17 @@ cursor: > or set/unset a breakpoint: > nnoremap <RightMouse> :Break<CR> -< *gdb-version* + +Several arguments will be added to make gdb work well for the debugger. +If you want to modify them, add a function to filter the argument list: > + let g:termdebug_config['command_filter'] = MyDebugFilter + +If you do not want the arguments to be added, but you do need to set the +"pty", use a function to add the necessary arguments: > + let g:termdebug_config['command_add_args'] = MyAddArguments +The function will be called with the list of arguments so far, and a second +argument that is the name of the pty. + *gdb-version* Only debuggers fully compatible with gdb will work. Vim uses the GDB/MI interface. The "new-ui" command requires gdb version 7.12 or later. if you get this error: @@ -414,8 +445,8 @@ get this error: Then your gdb is too old. -Colors *hl-debugPC* *hl-debugBreakpoint* - +Colors~ + *hl-debugPC* *hl-debugBreakpoint* The color of the signs can be adjusted with these highlight groups: - debugPC the current position - debugBreakpoint a breakpoint @@ -439,16 +470,20 @@ The argument is the gdb command. Vim window width *termdebug_wide* -To change the width of the Vim window when debugging starts, and use a -vertical split: > - let g:termdebug_wide = 163 -This will set &columns to 163 when `:Termdebug` is used. The value is restored -when quitting the debugger. -If g:termdebug_wide is set and &columns is already larger than -g:termdebug_wide then a vertical split will be used without changing &columns. -Set it to 1 to get a vertical split without every changing &columns (useful -for when the terminal can't be resized by Vim). +To change the width of the Vim window when debugging starts and use a vertical +split: > + let g:termdebug_config['wide'] = 163 +Or if there is no g:termdebug_config: > + let g:termdebug_wide = 163 + +This will set 'columns' to 163 when `:Termdebug` is used. The value is +restored when quitting the debugger. + +If the wide value is set and 'columns' is already a greater value, then a +vertical split will be used without modifying 'columns'. +Set the wide value to 1 to use a vertical split without ever changing +'columns'. This is useful when the terminal can't be resized by Vim. vim:tw=78:ts=8:noet:ft=help:norl: 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/filetype.vim b/runtime/filetype.vim index b8f40bbef0..c73f5f6cb7 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -405,7 +405,7 @@ au BufNewFile,BufRead *.cu,*.cuh setf cuda " Dockerfile; Podman uses the same syntax with name Containerfile " Also see Dockerfile.* below. -au BufNewFile,BufRead Containerfile,Dockerfile,*.Dockerfile setf dockerfile +au BufNewFile,BufRead Containerfile,Dockerfile,dockerfile,*.[dD]ockerfile setf dockerfile " WildPackets EtherPeek Decoder au BufNewFile,BufRead *.dcd setf dcd @@ -815,6 +815,9 @@ au BufNewFile,BufRead *.hjson setf hjson " Hollywood au BufRead,BufNewFile *.hws setf hollywood +" Hoon +au BufRead,BufNewFile *.hoon setf hoon + " Tilde (must be before HTML) au BufNewFile,BufRead *.t.html setf tilde @@ -1168,6 +1171,9 @@ au BufNewFile,BufRead *.isc,*.monk,*.ssc,*.tsc setf monk " MOO au BufNewFile,BufRead *.moo setf moo +" Moonscript +au BufNewFile,BufRead *.moon setf moonscript + " Modconf au BufNewFile,BufRead */etc/modules.conf,*/etc/modules,*/etc/conf.modules setf modconf 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..c26a43f776 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -283,6 +283,7 @@ local extension = { hjson = 'hjson', hog = 'hog', hws = 'hollywood', + hoon = 'hoon', htt = 'httest', htb = 'httest', iba = 'ibasic', @@ -418,6 +419,7 @@ local extension = { tsc = 'monk', isc = 'monk', moo = 'moo', + moon = 'moonscript', mp = 'mp', mof = 'msidl', odl = 'msidl', @@ -786,8 +788,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 +806,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 +885,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 +943,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 @@ -1058,6 +1060,7 @@ local filename = { ['.dircolors'] = 'dircolors', ['/etc/dnsmasq.conf'] = 'dnsmasq', Containerfile = 'dockerfile', + dockerfile = 'dockerfile', Dockerfile = 'dockerfile', npmrc = 'dosini', ['/etc/yum.conf'] = 'dosini', @@ -1075,16 +1078,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 +1303,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 +1531,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 +1564,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 +1578,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 +1595,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 +1624,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 +1653,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 +1683,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..dac2860690 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() @@ -1173,12 +1188,6 @@ function lsp.start_client(config) --- ---@param force (bool, optional) function client.stop(force) - 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 - local handle = rpc.handle if handle:is_closing() then return @@ -1213,6 +1222,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 +1375,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 +1457,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 +1854,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..bcfaecdfcc 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 @@ -158,20 +177,15 @@ end --- - bufnr (number|nil): --- Restrict formatting to the clients attached to the given buffer, defaults to the current --- buffer (0). +--- --- - filter (function|nil): ---- Predicate to filter clients used for formatting. Receives the list of clients attached ---- to bufnr as the argument and must return the list of clients on which to request ---- formatting. Example: +--- Predicate used to filter clients. Receives a client as argument and must return a +--- boolean. Clients matching the predicate are included. Example: --- --- <pre> --- -- Never request typescript-language-server for formatting --- vim.lsp.buf.format { ---- filter = function(clients) ---- return vim.tbl_filter( ---- function(client) return client.name ~= "tsserver" end, ---- clients ---- ) ---- end +--- filter = function(client) return client.name ~= "tsserver" end --- } --- </pre> --- @@ -188,18 +202,14 @@ end function M.format(options) options = options or {} local bufnr = options.bufnr or vim.api.nvim_get_current_buf() - local clients = vim.lsp.buf_get_clients(bufnr) + local clients = vim.lsp.get_active_clients({ + id = options.id, + bufnr = bufnr, + name = options.name, + }) if options.filter then - clients = options.filter(clients) - elseif options.id then - clients = vim.tbl_filter(function(client) - return client.id == options.id - end, clients) - elseif options.name then - clients = vim.tbl_filter(function(client) - return client.name == options.name - end, clients) + clients = vim.tbl_filter(options.filter, clients) end clients = vim.tbl_filter(function(client) @@ -367,23 +377,20 @@ end --- name using |vim.ui.input()|. ---@param options table|nil additional options --- - filter (function|nil): ---- Predicate to filter clients used for rename. ---- Receives the attached clients as argument and must return a list of ---- clients. +--- Predicate used to filter clients. Receives a client as argument and +--- must return a boolean. Clients matching the predicate are included. --- - name (string|nil): --- Restrict clients used for rename to ones where client.name matches --- this field. function M.rename(new_name, options) options = options or {} local bufnr = options.bufnr or vim.api.nvim_get_current_buf() - local clients = vim.lsp.buf_get_clients(bufnr) - + local clients = vim.lsp.get_active_clients({ + bufnr = bufnr, + name = options.name, + }) if options.filter then - clients = options.filter(clients) - elseif options.name then - clients = vim.tbl_filter(function(client) - return client.name == options.name - end, clients) + clients = vim.tbl_filter(options.filter, clients) end -- Clients must at least support rename, prepareRename is optional @@ -844,7 +851,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 +878,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..63e9342b1a 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) @@ -1462,7 +1477,7 @@ function M.open_floating_preview(contents, syntax, opts) }) opts = opts or {} opts.wrap = opts.wrap ~= false -- wrapping by default - opts.stylize_markdown = opts.stylize_markdown ~= false + opts.stylize_markdown = opts.stylize_markdown ~= false and vim.g.syntax_on ~= nil opts.focus = opts.focus ~= false opts.close_events = opts.close_events or { 'CursorMoved', 'CursorMovedI', 'InsertCharPre' } @@ -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/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index 4f2f7b942d..4cd4a200dd 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -2,7 +2,7 @@ " " Author: Bram Moolenaar " Copyright: Vim license applies, see ":help license" -" Last Change: 2022 May 09 +" Last Change: 2022 May 23 " " WORK IN PROGRESS - The basics works stable, more to come " Note: In general you need at least GDB 7.12 because this provides the @@ -71,11 +71,6 @@ set cpo&vim command -nargs=* -complete=file -bang Termdebug call s:StartDebug(<bang>0, <f-args>) command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>) -" Name of the gdb command, defaults to "gdb". -if !exists('g:termdebugger') - let g:termdebugger = 'gdb' -endif - let s:pc_id = 12 let s:asm_id = 13 let s:break_id = 14 " breakpoint number is added to this @@ -105,8 +100,17 @@ call s:Highlight(1, '', &background) hi default debugBreakpoint term=reverse ctermbg=red guibg=red hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray +" Get the command to execute the debugger as a list, defaults to ["gdb"]. func s:GetCommand() - return type(g:termdebugger) == v:t_list ? copy(g:termdebugger) : [g:termdebugger] + if exists('g:termdebug_config') + let cmd = get(g:termdebug_config, 'command', 'gdb') + elseif exists('g:termdebugger') + let cmd = g:termdebugger + else + let cmd = 'gdb' + endif + + return type(cmd) == v:t_list ? copy(cmd) : [cmd] endfunc func s:StartDebug(bang, ...) @@ -177,12 +181,10 @@ func s:StartDebug_internal(dict) call s:StartDebug_term(a:dict) endif - if exists('g:termdebug_disasm_window') - if g:termdebug_disasm_window - let curwinid = win_getid(winnr()) - call s:GotoAsmwinOrCreateIt() - call win_gotoid(curwinid) - endif + if s:GetDisasmWindow() + let curwinid = win_getid(winnr()) + call s:GotoAsmwinOrCreateIt() + call win_gotoid(curwinid) endif if exists('#User#TermdebugStartPost') @@ -252,18 +254,28 @@ func s:StartDebug_term(dict) let proc_args = get(a:dict, 'proc_args', []) let gdb_cmd = s:GetCommand() - " Add -quiet to avoid the intro message causing a hit-enter prompt. - let gdb_cmd += ['-quiet'] - " Disable pagination, it causes everything to stop at the gdb - let gdb_cmd += ['-iex', 'set pagination off'] - " Interpret commands while the target is running. This should usually only - " be exec-interrupt, since many commands don't work properly while the - " target is running (so execute during startup). - let gdb_cmd += ['-iex', 'set mi-async on'] - " Open a terminal window to run the debugger. - let gdb_cmd += ['-tty', pty] - " Command executed _after_ startup is done, provides us with the necessary feedback - let gdb_cmd += ['-ex', 'echo startupdone\n'] + + if exists('g:termdebug_config') && has_key(g:termdebug_config, 'command_add_args') + let gdb_cmd = g:termdebug_config.command_add_args(gdb_cmd, pty) + else + " Add -quiet to avoid the intro message causing a hit-enter prompt. + let gdb_cmd += ['-quiet'] + " Disable pagination, it causes everything to stop at the gdb + let gdb_cmd += ['-iex', 'set pagination off'] + " Interpret commands while the target is running. This should usually only + " be exec-interrupt, since many commands don't work properly while the + " target is running (so execute during startup). + let gdb_cmd += ['-iex', 'set mi-async on'] + " Open a terminal window to run the debugger. + let gdb_cmd += ['-tty', pty] + " Command executed _after_ startup is done, provides us with the necessary + " feedback + let gdb_cmd += ['-ex', 'echo startupdone\n'] + endif + + if exists('g:termdebug_config') && has_key(g:termdebug_config, 'command_filter') + let gdb_cmd = g:termdebug_config.command_filter(gdb_cmd) + endif " Adding arguments requested by the user let gdb_cmd += gdb_args @@ -871,7 +883,13 @@ func s:InstallCommands() command Asm call s:GotoAsmwinOrCreateIt() command Winbar call s:InstallWinbar() - if !exists('g:termdebug_map_K') || g:termdebug_map_K + let map = 1 + if exists('g:termdebug_config') + let map = get(g:termdebug_config, 'map_K', 1) + elseif exists('g:termdebug_map_K') + let map = g:termdebug_map_K + endif + if map " let s:k_map_saved = maparg('K', 'n', 0, 1) let s:k_map_saved = {} for map in nvim_get_keymap('n') @@ -1280,6 +1298,26 @@ func s:GotoSourcewinOrCreateIt() endif endfunc +func s:GetDisasmWindow() + if exists('g:termdebug_config') + return get(g:termdebug_config, 'disasm_window', 0) + endif + if exists('g:termdebug_disasm_window') + return g:termdebug_disasm_window + endif + return 0 +endfunc + +func s:GetDisasmWindowHeight() + if exists('g:termdebug_config') + return get(g:termdebug_config, 'disasm_window_height', 0) + endif + if exists('g:termdebug_disasm_window') && g:termdebug_disasm_window > 1 + return g:termdebug_disasm_window + endif + return 0 +endfunc + func s:GotoAsmwinOrCreateIt() if !win_gotoid(s:asmwin) if win_gotoid(s:sourcewin) @@ -1303,10 +1341,8 @@ func s:GotoAsmwinOrCreateIt() exe 'file Termdebug-asm-listing' endif - if exists('g:termdebug_disasm_window') - if g:termdebug_disasm_window > 1 - exe 'resize ' . g:termdebug_disasm_window - endif + if s:GetDisasmWindowHeight() > 0 + exe 'resize ' .. s:GetDisasmWindowHeight() endif endif diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua index 34d1263ff4..16326cfe66 100644 --- a/scripts/lintcommit.lua +++ b/scripts/lintcommit.lua @@ -78,7 +78,7 @@ local function validate_commit(commit_message) -- Check if type is correct local type = vim.split(before_colon, "%(")[1] - local allowed_types = {'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'chore', 'vim-patch'} + local allowed_types = {'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'dist', 'vim-patch'} if not vim.tbl_contains(allowed_types, type) then return string.format( 'Invalid commit type "%s". Allowed types are:\n %s', @@ -181,7 +181,7 @@ function M._test() ['refactor: normal message'] = true, ['revert: normal message'] = true, ['test: normal message'] = true, - ['chore: normal message'] = true, + ['dist: normal message'] = true, ['ci(window): message with scope'] = true, ['ci!: message with breaking change'] = true, ['ci(tui)!: message with scope and breaking change'] = true, @@ -205,10 +205,10 @@ function M._test() ['ci :extra space before colon'] = false, ['refactor(): empty scope'] = false, ['ci( ): whitespace as scope'] = false, - ['chore: period at end of sentence.'] = false, + ['ci: period at end of sentence.'] = false, ['ci: Starting sentence capitalized'] = false, ['unknown: using unknown type'] = false, - ['chore: you\'re saying this commit message just goes on and on and on and on and on and on for way too long?'] = false, + ['ci: you\'re saying this commit message just goes on and on and on and on and on and on for way too long?'] = false, } local failed = 0 diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index e7e8f0b274..8235949156 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -243,6 +243,10 @@ preprocess_patch() { LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/keymap\.h/\1\/keycodes.h/g' \ "$file" > "$file".tmp && mv "$file".tmp "$file" + # Rename terminal.txt to nvim_terminal_emulator.txt + LC_ALL=C sed -e 's/\( [ab]\/runtime\/doc\)\/terminal\.txt/\1\/nvim_terminal_emulator.txt/g' \ + "$file" > "$file".tmp && mv "$file".tmp "$file" + # Rename test_urls.vim to check_urls.vim LC_ALL=C sed -e 's@\( [ab]\)/runtime/doc/test\(_urls\.vim\)@\1/scripts/check\2@g' \ "$file" > "$file".tmp && mv "$file".tmp "$file" 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/CMakeLists.txt b/src/nvim/CMakeLists.txt index 38be5bfb1d..da74b4dc9d 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -13,8 +13,10 @@ if(USE_GCOV) endif() if(WIN32) - # tell MinGW compiler to enable wmain - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode") + if(MINGW) + # Enable wmain + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode") + endif() elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreServices") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -framework CoreServices") diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 76e531e7aa..19b4119344 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -31,7 +31,6 @@ goto goto_name; \ } - // ID for associating autocmds created via nvim_create_autocmd // Used to delete autocmds from nvim_del_autocmd static int64_t next_autocmd_id = 1; @@ -283,7 +282,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 +404,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 @@ -428,7 +428,6 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc AucmdExecutable aucmd = AUCMD_EXECUTABLE_INIT; Callback cb = CALLBACK_NONE; - if (!unpack_string_or_array(&event_array, &event, "event", true, err)) { goto cleanup; } @@ -549,7 +548,6 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc } }); - cleanup: aucmd_exec_free(&aucmd); api_free_array(event_array); @@ -749,6 +747,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 +760,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 +819,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 +834,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/buffer.c b/src/nvim/api/buffer.c index 9842975d62..4fa8b13c54 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -35,7 +35,6 @@ # include "api/buffer.c.generated.h" #endif - /// \defgroup api-buffer /// /// \brief For more information on buffers, see |buffers| @@ -51,7 +50,6 @@ /// You can use |nvim_buf_is_loaded()| or |nvim_buf_line_count()| to check /// whether a buffer is loaded. - /// Returns the number of lines in the given buffer. /// /// @param buffer Buffer handle, or 0 for current buffer @@ -737,7 +735,6 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In (int)new_len - 1, (colnr_T)last_item.size, new_byte, kExtmarkUndo); - changed_lines((linenr_T)start_row, 0, (linenr_T)end_row + 1, (long)extra, true); @@ -1039,7 +1036,6 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err) dict_set_var(buf->b_vars, name, NIL, true, false, err); } - /// Gets a buffer option value /// /// @param buffer Buffer handle, or 0 for current buffer @@ -1336,7 +1332,6 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) return rv; } - /// call a function with buffer as temporary current buffer /// /// This temporarily switches current buffer to "buffer". diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index f968593e47..abaac07755 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -78,7 +78,6 @@ void nvim_buf_clear_highlight(Buffer buffer, Integer ns_id, Integer line_start, nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end, err); } - /// Set the virtual text (annotation) for a buffer line. /// /// @deprecated use nvim_buf_set_extmark to use full virtual text @@ -137,7 +136,6 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A return 0; } - Decoration *existing = decor_find_virttext(buf, (int)line, ns_id); if (existing) { @@ -292,7 +290,6 @@ void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, Boolean in nvim_buf_set_lines(0, buffer, start, end, false, replacement, err); } - /// Sets a buffer-scoped (b:) variable /// /// @deprecated diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index e05d80812d..9d80a5be5f 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -94,28 +94,27 @@ static bool ns_initialized(uint32_t ns) return ns < (uint32_t)next_namespace_id; } - -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)); @@ -233,12 +232,11 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, } } - ExtmarkInfo extmark = extmark_from_id(buf, (uint32_t)ns_id, (uint32_t)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 @@ -333,7 +331,6 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e limit = INT64_MAX; } - bool reverse = false; int l_row; @@ -352,12 +349,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e reverse = true; } - ExtmarkInfoArray marks = extmark_get(buf, (uint32_t)ns_id, l_row, l_col, 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 +362,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. @@ -676,7 +671,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; } - OPTION_TO_BOOL(decor.virt_lines_above, virt_lines_above, false); if (opts->priority.type == kObjectTypeInteger) { @@ -778,7 +772,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer col2 = 0; } - // TODO(bfredl): synergize these two branches even more if (ephemeral && decor_state.buf == buf) { decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, (uint64_t)ns_id, id); diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 78f8ed3cca..d4882abffe 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -80,10 +80,13 @@ return { "maxwidth"; "fillchar"; "highlights"; + "use_winbar"; "use_tabline"; }; option = { "scope"; + "win"; + "buf"; }; highlight = { "bold"; @@ -145,6 +148,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..3cccbc3cdf 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -407,7 +407,6 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object }); } - buf_T *find_buffer_by_handle(Buffer buffer, Error *err) { if (buffer == 0) { @@ -1040,8 +1039,8 @@ Object copy_object(Object obj) } } -static void set_option_value_for(char *key, int numval, char *stringval, int opt_flags, - int opt_type, void *from, Error *err) +void set_option_value_for(char *key, long numval, char *stringval, int opt_flags, int opt_type, + void *from, Error *err) { switchwin_T switchwin; aco_save_T aco; @@ -1080,8 +1079,7 @@ static void set_option_value_for(char *key, int numval, char *stringval, int opt try_end(err); } - -static void set_option_value_err(char *key, int numval, char *stringval, int opt_flags, Error *err) +static void set_option_value_err(char *key, long numval, char *stringval, int opt_flags, Error *err) { char *errmsg; @@ -1418,14 +1416,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"; } } @@ -1562,7 +1560,6 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, goto err; } - if (api_object_to_bool(opts->register_, "register", false, err)) { argt |= EX_REGSTR; } else if (ERROR_SET(err)) { @@ -1616,7 +1613,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 +1621,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/private/helpers.h b/src/nvim/api/private/helpers.h index bbbc3de7d5..8423db4970 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -146,7 +146,6 @@ typedef struct { code; \ } - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/helpers.h.generated.h" # include "keysets.h.generated.h" @@ -163,5 +162,4 @@ typedef struct { current_sctx = save_current_sctx; \ } while (0); - #endif // NVIM_API_PRIVATE_HELPERS_H diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index b4d20ed975..dc04eedebc 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -196,7 +196,6 @@ void nvim_ui_detach(uint64_t channel_id, Error *err) remote_ui_disconnect(channel_id); } - void nvim_ui_try_resize(uint64_t channel_id, Integer width, Integer height, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { @@ -349,7 +348,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 @@ -567,7 +570,6 @@ static void remote_ui_highlight_set(UI *ui, int id) Array args = ARRAY_DICT_INIT; UIData *data = ui->data; - if (data->hl_id == id) { return; } @@ -790,7 +792,6 @@ static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed) } } - Array my_args = ARRAY_DICT_INIT; // Objects are currently single-reference // make a copy, but only if necessary 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..dd0b75bbfb 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -209,7 +209,6 @@ static void on_redraw_event(void **argv) redraw_all_later(NOT_VALID); } - /// Sends input-keys to Nvim, subject to various quirks controlled by `mode` /// flags. This is a blocking call, unlike |nvim_input()|. /// @@ -441,7 +440,6 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, Bool return cstr_as_string(ptr); } - /// Execute Lua code. Parameters (if any) are available as `...` inside the /// chunk. The chunk can return a value. /// @@ -570,7 +568,6 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E return runtime_get_named(is_lua, pat, all); } - /// Changes the global working directory. /// /// @param dir Directory path @@ -775,11 +772,15 @@ end: /// |:set|: for global-local options, both the global and local value are set /// unless otherwise specified with {scope}. /// +/// Note the options {win} and {buf} cannot be used together. +/// /// @param name Option name /// @param value New option value /// @param opts Optional parameters /// - scope: One of 'global' or 'local'. Analogous to /// |:setglobal| and |:setlocal|, respectively. +/// - win: |window-ID|. Used for setting window local option. +/// - buf: Buffer number. Used for setting buffer local option. /// @param[out] err Error details, if any void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error *err) FUNC_API_SINCE(9) @@ -799,6 +800,36 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error return; } + int opt_type = SREQ_GLOBAL; + void *to = NULL; + + if (opts->win.type == kObjectTypeInteger) { + opt_type = SREQ_WIN; + to = find_window_by_handle((int)opts->win.data.integer, err); + } else if (HAS_KEY(opts->win)) { + api_set_error(err, kErrorTypeValidation, "invalid value for key: win"); + return; + } + + if (opts->buf.type == kObjectTypeInteger) { + scope = OPT_LOCAL; + opt_type = SREQ_BUF; + to = find_buffer_by_handle((int)opts->buf.data.integer, err); + } else if (HAS_KEY(opts->buf)) { + api_set_error(err, kErrorTypeValidation, "invalid value for key: buf"); + return; + } + + if (HAS_KEY(opts->scope) && HAS_KEY(opts->buf)) { + api_set_error(err, kErrorTypeValidation, "scope and buf cannot be used together"); + return; + } + + if (HAS_KEY(opts->win) && HAS_KEY(opts->buf)) { + api_set_error(err, kErrorTypeValidation, "buf and win cannot be used together"); + return; + } + long numval = 0; char *stringval = NULL; @@ -820,10 +851,7 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error return; } - char *e = set_option_value(name.data, numval, stringval, scope); - if (e) { - api_set_error(err, kErrorTypeException, "%s", e); - } + set_option_value_for(name.data, numval, stringval, scope, opt_type, to, err); } /// Gets the option information for all options. @@ -1214,7 +1242,6 @@ static void term_close(void *data) channel_decref(chan); } - /// Send data to channel `id`. For a job, it writes it to the /// stdin of the process. For the stdio channel |channel-stdio|, /// it writes to Nvim's stdout. For an internal terminal instance @@ -1904,13 +1931,13 @@ static void write_msg(String message, bool to_err) static char out_line_buf[LINE_BUFFER_SIZE], err_line_buf[LINE_BUFFER_SIZE]; #define PUSH_CHAR(i, pos, line_buf, msg) \ - if (message.data[i] == NL || pos == LINE_BUFFER_SIZE - 1) { \ - line_buf[pos] = NUL; \ + if (message.data[i] == NL || (pos) == LINE_BUFFER_SIZE - 1) { \ + (line_buf)[pos] = NUL; \ msg(line_buf); \ - pos = 0; \ + (pos) = 0; \ continue; \ } \ - line_buf[pos++] = message.data[i]; + (line_buf)[(pos)++] = message.data[i]; no_wait_return++; for (uint32_t i = 0; i < message.size; i++) { @@ -2140,8 +2167,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; @@ -2161,7 +2188,6 @@ void nvim__screenshot(String path) ui_call_screenshot(path); } - /// Deletes an uppercase/file named mark. See |mark-motions|. /// /// @note fails with error if a lowercase or buffer local named mark is used. @@ -2274,8 +2300,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 +2321,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 +2341,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 +2350,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 +2357,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 +2371,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 +2384,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 +2391,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 +2408,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 +2443,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 +2457,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 42101af7f0..e71f1a11ec 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -34,7 +34,7 @@ /// Unlike |nvim_command()| this function supports heredocs, script-scope (s:), /// etc. /// -/// On execution error: fails with VimL error, does not update v:errmsg. +/// On execution error: fails with VimL error, updates v:errmsg. /// /// @see |execute()| /// @see |nvim_command()| @@ -98,7 +98,7 @@ theend: /// Executes an Ex command. /// -/// On execution error: fails with VimL error, does not update v:errmsg. +/// On execution error: fails with VimL error, updates v:errmsg. /// /// Prefer using |nvim_cmd()| or |nvim_exec()| over this. To evaluate multiple lines of Vim script /// or an Ex command directly, use |nvim_exec()|. To construct an Ex command using a structured @@ -118,7 +118,7 @@ void nvim_command(String command, Error *err) /// Evaluates a VimL |expression|. /// Dictionaries and Lists are recursively expanded. /// -/// On execution error: fails with VimL error, does not update v:errmsg. +/// On execution error: fails with VimL error, updates v:errmsg. /// /// @param expr VimL expression string /// @param[out] err Error details, if any @@ -226,7 +226,7 @@ free_vim_args: /// Calls a VimL function with the given arguments. /// -/// On execution error: fails with VimL error, does not update v:errmsg. +/// On execution error: fails with VimL error, updates v:errmsg. /// /// @param fn Function to call /// @param args Function arguments packed in an Array @@ -240,7 +240,7 @@ Object nvim_call_function(String fn, Array args, Error *err) /// Calls a VimL |Dictionary-function| with the given arguments. /// -/// On execution error: fails with VimL error, does not update v:errmsg. +/// On execution error: fails with VimL error, updates v:errmsg. /// /// @param dict Dictionary, or String evaluating to a VimL |self| dict /// @param fn Name of the function defined on the VimL dict @@ -996,6 +996,8 @@ end: /// such as having spaces inside a command argument, expanding filenames in a command that otherwise /// doesn't expand filenames, etc. /// +/// On execution error: fails with VimL error, updates v:errmsg. +/// /// @see |nvim_exec()| /// @see |nvim_command()| /// @@ -1302,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/api/win_config.c b/src/nvim/api/win_config.c index 0d8bdbec61..898d95f49a 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -22,7 +22,6 @@ # include "api/win_config.c.generated.h" #endif - /// Open a new window. /// /// Currently this is used to open floating and external windows. @@ -590,7 +589,6 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, return false; } - if (HAS_KEY(config->focusable)) { fconfig->focusable = api_object_to_bool(config->focusable, "'focusable' key", false, err); if (ERROR_SET(err)) { diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 3a3a65f812..9f2afc67a6 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -373,7 +373,6 @@ Boolean nvim_win_is_valid(Window window) return ret; } - /// Closes the window and hide the buffer it contains (like |:hide| with a /// |window-ID|). /// diff --git a/src/nvim/arabic.c b/src/nvim/arabic.c index e76a75d37a..130ce65b86 100644 --- a/src/nvim/arabic.c +++ b/src/nvim/arabic.c @@ -244,7 +244,6 @@ #define a_BYTE_ORDER_MARK 0xfeff - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "arabic.c.generated.h" #endif diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h index 692db40c0d..b1241166bf 100644 --- a/src/nvim/ascii.h +++ b/src/nvim/ascii.h @@ -75,7 +75,6 @@ #define Ctrl_HAT 30 // ^ #define Ctrl__ 31 - // Character that separates dir names in a path. #ifdef BACKSLASH_IN_FILENAME # define PATHSEP psepc 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..31efce13f6 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -126,7 +126,6 @@ static void augroup_map_del(int id, char *name) } } - static inline const char *get_deleted_augroup(void) FUNC_ATTR_ALWAYS_INLINE { if (deleted_augroup == NULL) { @@ -190,7 +189,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); } @@ -377,7 +387,6 @@ static void au_cleanup(void) au_need_clean = false; } - // Get the first AutoPat for a particular event. AutoPat *au_get_autopat_for_event(event_T event) FUNC_ATTR_PURE @@ -657,7 +666,6 @@ const char *event_nr2name(event_T event) return "Unknown"; } - /// Return true if "event" is included in 'eventignore'. /// /// @param event event to check @@ -1006,7 +1014,6 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group findgroup = group; } - // detect special <buffer[=X]> buffer-local patterns int is_buflocal = aupat_is_buflocal(pat, patlen); int buflocal_nr = 0; @@ -1136,8 +1143,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 +1225,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 +1510,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 +1527,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 +1551,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 +1600,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 +1816,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) { @@ -1841,7 +1849,6 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force reset_lnums(); } - if (eap != NULL) { (void)set_cmdarg(NULL, save_cmdarg); set_vim_var_nr(VV_CMDBANG, save_cmdbang); @@ -2026,6 +2033,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 +2122,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 +2476,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"; } @@ -2636,7 +2646,6 @@ static bool arg_autocmd_flag_get(bool *flag, char **cmd_ptr, char *pattern, int return false; } - // UI Enter void do_autocmd_uienter(uint64_t chanid, bool attached) { diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h index d3503672fd..a085a03455 100644 --- a/src/nvim/autocmd.h +++ b/src/nvim/autocmd.h @@ -57,10 +57,10 @@ 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; - // Set by the apply_autocmds_group function if the given event is equal to // EVENT_FILETYPE. Used by the readfile function in order to determine if // EVENT_BUFREADPOST triggered the EVENT_FILETYPE. @@ -69,7 +69,6 @@ typedef struct AutoPatCmd { // apply_autocmds_group. EXTERN bool au_did_filetype INIT(= false); - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "autocmd.h.generated.h" #endif diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 4b1aea5720..4c3f1308b3 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1025,11 +1025,9 @@ char *do_bufdel(int command, char_u *arg, int addr_count, int start_bnr, int end } } - return errormsg; } - /// Make the current buffer empty. /// Used when it is wiped out and it's the last buffer. static int empty_curbuf(int close_others, int forceit, int action) @@ -1180,7 +1178,6 @@ int do_buffer(int action, int start, int dir, int count, int forceit) return FAIL; } - // delete buffer "buf" from memory and/or the list if (unload) { int forward; @@ -1425,7 +1422,6 @@ int do_buffer(int action, int start, int dir, int count, int forceit) return OK; } - /// Set current buffer to "buf". Executes autocommands and closes current /// buffer. /// @@ -1585,7 +1581,6 @@ void enter_buffer(buf_T *buf) scroll_cursor_halfway(false); // redisplay at correct position } - // Change directories when the 'acd' option is set. do_autochdir(); @@ -1932,7 +1927,6 @@ void free_buf_options(buf_T *buf, int free_p_ff) clear_string_option(&buf->b_p_menc); } - /// Get alternate file "n". /// Set linenr to "lnum" or altfpos.lnum if "lnum" == 0. /// Also set cursor column to altfpos.col if 'startofline' is not set. @@ -2357,7 +2351,6 @@ int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options) return count == 0 ? FAIL : OK; } - /// Check for a match on the file name for buffer "buf" with regprog "prog". /// /// @param ignore_case When true, ignore case. Use 'fic' otherwise. @@ -2491,7 +2484,6 @@ void buflist_setfpos(buf_T *const buf, win_T *const win, linenr_T lnum, colnr_T } } - /// Check that "wip" has 'diff' set and the diff is only for another tab page. /// That's because a diff is local to a tab page. static bool wininfo_other_tab_diff(wininfo_T *wip) @@ -3113,7 +3105,6 @@ void col_print(char_u *buf, size_t buflen, int col, int vcol) static char_u *lasttitle = NULL; static char_u *lasticon = NULL; - /// Put the title name in the title bar and icon of the window. void maketitle(void) { @@ -3331,7 +3322,6 @@ static bool value_change(char_u *str, char_u **last) return false; } - /// Set current window title void resettitle(void) { @@ -3356,7 +3346,6 @@ typedef enum { kNumBaseHexadecimal = 16, } NumberBase; - /// Build a string from the status line items in "fmt". /// Return length of string in screen cells. /// @@ -3473,7 +3462,6 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san // so any user-visible characters must occur before here. char *out_end_p = (out + outlen) - 1; - // Proceed character by character through the statusline format string // fmt_p is the current position in the input buffer for (char *fmt_p = usefmt; *fmt_p;) { @@ -3915,7 +3903,6 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san } } - // If the output of the expression needs to be evaluated // replace the %{} block with the result of evaluation if (reevaluate && str != NULL && *str != 0 @@ -4698,7 +4685,6 @@ void do_arg_all(int count, int forceit, int keep_tabs) old_curwin = curwin; old_curtab = curtab; - // Try closing all windows that are not in the argument list. // Also close windows that are not full width; // When 'hidden' or "forceit" set the buffer becomes hidden. @@ -4947,7 +4933,6 @@ void ex_buffer_all(exarg_T *eap) setpcmark(); - // Close superfluous windows (two windows for the same buffer). // Also close windows that are not full-width. if (had_tab > 0) { @@ -5098,7 +5083,6 @@ void ex_buffer_all(exarg_T *eap) } } - /// do_modelines() - process mode lines for the current file /// /// @param flags 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/buffer_updates.c b/src/nvim/buffer_updates.c index 57f052ced0..cb08ba0cfb 100644 --- a/src/nvim/buffer_updates.c +++ b/src/nvim/buffer_updates.c @@ -186,7 +186,6 @@ void buf_updates_unload(buf_T *buf, bool can_reload) } } - void buf_updates_send_changes(buf_T *buf, linenr_T firstline, int64_t num_added, int64_t num_removed, bool send_tick) { diff --git a/src/nvim/change.c b/src/nvim/change.c index 94e5a19edc..9fd5083fd3 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -615,7 +615,6 @@ void ins_char_bytes(char_u *buf, size_t charlen) oldlen = (size_t)utfc_ptr2len((char *)oldp + col); } - // Push the replaced bytes onto the replace stack, so that they can be // put back when BS is used. The bytes of a multi-byte character are // done the other way around, so that the first byte is popped off @@ -1033,8 +1032,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 +1187,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 +1480,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 +1523,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 +1641,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 +1758,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 +1767,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/channel.c b/src/nvim/channel.c index 6278f84190..7a71be58c1 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -279,13 +279,11 @@ static void channel_destroy_early(Channel *chan) multiqueue_put(main_loop.events, free_channel_event, 1, chan); } - static void close_cb(Stream *stream, void *data) { channel_decref(data); } - /// Starts a job and returns the associated channel /// /// @param[in] argv Arguments vector specifying the command to run, @@ -416,7 +414,6 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader return chan; } - uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader on_output, int timeout, const char **error) { @@ -555,7 +552,6 @@ size_t channel_send(uint64_t id, char *data, size_t len, bool data_owned, const goto retfree; } - Stream *in = channel_instream(chan); if (in->closed) { *error = _("Can't send data to closed stream"); @@ -756,7 +752,6 @@ static void channel_callback_call(Channel *chan, CallbackReader *reader) tv_clear(&rettv); } - /// Open terminal for channel /// /// Channel `chan` is assumed to be an open pty channel, diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 5cec5731eb..0f1b481792 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -149,5 +149,4 @@ static inline Stream *channel_outstream(Channel *chan) abort(); } - #endif // NVIM_CHANNEL_H diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 082791ffd1..e20c0e3f3f 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -34,7 +34,6 @@ # include "charset.c.generated.h" #endif - static bool chartab_initialized = false; // b_chartab[] is an array with 256 bits, each bit representing one of the @@ -495,7 +494,6 @@ char_u *str_foldcase(char_u *str, int orglen, char_u *buf, int buflen) i += utfc_ptr2len((char *)STR_PTR(i)); } - if (buf == NULL) { return (char_u *)ga.ga_data; } @@ -1558,10 +1556,10 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, cons } \ const uvarnumber_T digit = (uvarnumber_T)(conv); \ /* avoid ubsan error for overflow */ \ - if (un < UVARNUMBER_MAX / base \ - || (un == UVARNUMBER_MAX / base \ - && (base != 10 || digit <= UVARNUMBER_MAX % 10))) { \ - un = base * un + digit; \ + if (un < UVARNUMBER_MAX / (base) \ + || (un == UVARNUMBER_MAX / (base) \ + && ((base) != 10 || digit <= UVARNUMBER_MAX % 10))) { \ + un = (base) * un + digit; \ } else { \ un = UVARNUMBER_MAX; \ } \ diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c index b69505d7c9..0248c25dfa 100644 --- a/src/nvim/cursor_shape.c +++ b/src/nvim/cursor_shape.c @@ -315,7 +315,6 @@ bool cursor_mode_uses_syn_id(int syn_id) return false; } - /// Return the index into shape_table[] for the current mode. int cursor_get_mode_idx(void) FUNC_ATTR_PURE diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index b2ac28629c..30d6ea2505 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -74,7 +74,6 @@ void do_debug(char_u *cmd) #define CMD_UP 9 #define CMD_DOWN 10 - RedrawingDisabled++; // don't redisplay the window no_wait_return++; // don't wait for return did_emsg = false; // don't use error from debugged stuff @@ -445,7 +444,7 @@ bool dbg_check_skipped(exarg_T *eap) static garray_T dbg_breakp = { 0, 0, sizeof(struct debuggy), 4, NULL }; #define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx]) -#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx]) +#define DEBUGGY(gap, idx) (((struct debuggy *)(gap)->ga_data)[idx]) static int last_breakp = 0; // nr of last defined breakpoint // Profiling uses file and func names similar to breakpoints. diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 28257dd7b5..b1a22b3294 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -180,7 +180,6 @@ static bool decor_virt_pos(Decoration decor) return kv_size(decor.virt_text) || decor.ui_watched; } - bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state) { state->top_row = top_row; @@ -530,7 +529,6 @@ void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col, decor_add(&decor_state, start_row, start_col, end_row, end_col, decor, true, ns_id, mark_id); } - int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines) { buf_T *buf = wp->w_buffer; diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 9a82af8661..8f28442d41 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -31,10 +31,8 @@ EXTERN const char *const hl_mode_str[] INIT(= { "", "replace", "combine", "blend typedef kvec_t(VirtTextChunk) VirtText; #define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE) - typedef kvec_t(struct virt_line { VirtText line; bool left_col; }) VirtLines; - struct Decoration { VirtText virt_text; VirtLines virt_lines; diff --git a/src/nvim/decoration_provider.c b/src/nvim/decoration_provider.c index ef27b2af1c..0f6a260247 100644 --- a/src/nvim/decoration_provider.c +++ b/src/nvim/decoration_provider.c @@ -140,7 +140,6 @@ void providers_invoke_line(win_T *wp, DecorProviders *providers, int row, bool * } } - /// For each provider invoke the 'buf' callback for a given buffer. /// /// @param buf Buffer @@ -158,7 +157,6 @@ void decor_providers_invoke_buf(buf_T *buf, DecorProviders *providers, char **er } } - /// For each provider invoke the 'end' callback /// /// @param providers Decoration providers diff --git a/src/nvim/diff.c b/src/nvim/diff.c index e8d54d7030..8c98c1ef23 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1371,7 +1371,6 @@ static void set_diff_option(win_T *wp, int value) curbuf = curwin->w_buffer; } - /// Set options in window "wp" for diff mode. /// /// @param addbuf Add buffer to diff. @@ -2036,7 +2035,6 @@ void diff_set_topline(win_T *fromwin, win_T *towin) } towin->w_topfill = 0; - // search for a change that includes "lnum" in the list of diffblocks. for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) { if (lnum <= dp->df_lnum[fromidx] + dp->df_count[fromidx]) { diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 1b536bdde6..b461082be0 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1832,7 +1832,6 @@ static void printdigraph(const digr_T *dp, result_T *previous) msg_putchar('\n'); } - // Make msg_col a multiple of list_width by using spaces. if (msg_col % list_width != 0) { int spaces = (msg_col / list_width + 1) * list_width - msg_col; @@ -2016,7 +2015,6 @@ typedef struct { #define KMAP_MAXLEN 20 // maximum length of "from" or "to" - /// Set up key mapping tables for the 'keymap' option. /// /// @return NULL if OK, an error message for failure. This only needs to be diff --git a/src/nvim/edit.c b/src/nvim/edit.c index aa77c03b48..41fa34c31e 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -245,7 +245,6 @@ typedef struct insert_state { char_u *ptr; } InsertState; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "edit.c.generated.h" #endif @@ -459,9 +458,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 +471,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 +552,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 } @@ -576,7 +574,6 @@ static int insert_check(VimState *state) // When emsg() was called msg_scroll will have been set. msg_scroll = false; - // Open fold at the cursor line, according to 'foldopen'. if (fdo_flags & FDO_INSERT) { foldOpenCursor(); @@ -756,7 +753,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 +766,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(); @@ -842,17 +836,6 @@ static int insert_execute(VimState *state, int key) return insert_handle_key(s); } - -/// 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 +867,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) { @@ -934,17 +901,12 @@ static int insert_handle_key(InsertState *s) case K_SELECT: // end of Select mode mapping - ignore break; - case K_HELP: // Help key works like <ESC> <Help> case K_F1: case K_XF1: stuffcharReadbuff(K_HELP); - if (p_im) { - need_start_insertmode = true; - } return 0; // exit insert mode - case ' ': if (mod_mask != MOD_MASK_CTRL) { goto normalchar; @@ -956,7 +918,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; @@ -1190,7 +1152,6 @@ check_pum: } break; - case K_S_TAB: // When not mapped, use like a normal TAB s->c = TAB; FALLTHROUGH; @@ -1236,7 +1197,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 +1249,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 +1586,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 +1713,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; } @@ -2111,7 +2065,6 @@ bool ctrl_x_mode_not_defined_yet(void) return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET; } - /// Check that the "dict" or "tsr" option can be used. /// /// @param dict_opt check "dict" when true, "tsr" when false. @@ -2398,9 +2351,9 @@ static int ins_compl_add(char_u *const str, int len, char_u *const fname, } #define FREE_CPTEXT(cptext, cptext_allocated) \ do { \ - if (cptext != NULL && cptext_allocated) { \ + if ((cptext) != NULL && (cptext_allocated)) { \ for (size_t i = 0; i < CPT_COUNT; i++) { \ - xfree(cptext[i]); \ + xfree((cptext)[i]); \ } \ } \ } while (0) @@ -2648,7 +2601,6 @@ void completeopt_was_set(void) } } - /* * Start completion for the complete() function. * "startcol" is where the matched text starts (1 is first column). @@ -2712,13 +2664,11 @@ void set_completion(colnr_T startcol, list_T *list) ui_flush(); } - /* "compl_match_array" points the currently displayed list of entries in the * popup menu. It is NULL when there is no popup menu. */ static pumitem_T *compl_match_array = NULL; static int compl_match_arraysize; - /* * Remove any popup menu. */ @@ -3383,7 +3333,6 @@ static char_u *ins_compl_mode(void) return (char_u *)""; } - /* * Delete one character before the cursor and show the subset of the matches * that match the word that is now before the cursor. @@ -3799,6 +3748,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) { @@ -3968,7 +3918,6 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag) return buf; } - /// Get the user-defined completion function name for completion 'type' static char_u *get_complete_funcname(int type) { @@ -5432,7 +5381,6 @@ static int ins_complete(int c, bool enable_pum) save_w_leftcol = curwin->w_leftcol; n = ins_compl_next(true, ins_compl_key2count(c), insert_match, false); - if (n > 1) { // all matches have been found compl_matches = n; } @@ -6285,6 +6233,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); @@ -7792,7 +7741,6 @@ static void ins_reg(void) add_to_showcmd_c(Ctrl_R); } - // Don't map the register name. This also prevents the mode message to be // deleted when ESC is hit. no_mapping++; @@ -7963,10 +7911,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); } /* @@ -8039,7 +7985,6 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) } } - State = MODE_NORMAL; may_trigger_modechanged(); // need to position cursor again when on a TAB @@ -8242,7 +8187,6 @@ static void ins_del(void) AppendCharToRedobuff(K_DEL); } - /* * Delete one character for ins_bs(). */ @@ -8412,9 +8356,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); @@ -8670,7 +8612,6 @@ static void ins_mousescroll(int dir) } } - static void ins_left(void) { pos_T tpos; @@ -9196,7 +9137,6 @@ static int ins_digraph(void) add_to_showcmd_c(Ctrl_K); } - // don't map the digraph chars. This also prevents the // mode message to be deleted when ESC is hit no_mapping++; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9c2069663d..02dc5ec954 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -53,12 +53,10 @@ #include "nvim/version.h" #include "nvim/window.h" - // TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead #define DICT_MAXNEST 100 // maximum nesting of lists and dicts - static char *e_letunexp = N_("E18: Unexpected characters in :let"); static char *e_missbrac = N_("E111: Missing ']'"); static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); @@ -126,13 +124,13 @@ typedef struct { #define VV(idx, name, type, flags) \ [idx] = { \ - .vv_name = name, \ + .vv_name = (name), \ .vv_di = { \ - .di_tv = { .v_type = type }, \ + .di_tv = { .v_type = (type) }, \ .di_flags = 0, \ .di_key = { 0 }, \ }, \ - .vv_flags = flags, \ + .vv_flags = (flags), \ } #define VIMVAR_KEY_LEN 16 // Maximum length of the key of v:variables @@ -1067,7 +1065,6 @@ int get_spellword(list_T *const list, const char **ret_word) return tv_list_find_nr(list, -1, NULL); } - // Call some vim script function and return the result in "*rettv". // Uses argv[0] to argv[argc-1] for the function arguments. argv[argc] // should have type VAR_UNKNOWN. @@ -1209,7 +1206,6 @@ void prof_child_exit(proftime_T *tm) script_prof_restore(tm); } - /// Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding /// it in "*cp". Doesn't give error messages. int eval_foldexpr(char *arg, int *cp) @@ -2701,7 +2697,6 @@ void free_for_info(void *fi_void) xfree(fi); } - void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) FUNC_ATTR_NONNULL_ALL { @@ -3146,7 +3141,6 @@ void del_menutrans_vars(void) * get_user_var_name(). */ - static char *varnamebuf = NULL; static size_t varnamebuflen = 0; @@ -5636,7 +5630,6 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack return abort; } - /// Mark all lists and dicts referenced in given mark /// /// @return true if setting references failed somehow. @@ -5683,7 +5676,6 @@ static inline bool set_ref_dict(dict_T *dict, int copyID) return false; } - /// Get the key for *{key: val} into "tv" and advance "arg". /// /// @return FAIL when there is no valid key. @@ -6405,7 +6397,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 +6857,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 +6878,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 +6889,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 +6980,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; } } @@ -7284,7 +7279,6 @@ static bool set_ref_in_callback(Callback *callback, int copyID, ht_stack_T **ht_ return set_ref_in_item(&tv, copyID, ht_stack, list_stack); break; - default: abort(); } @@ -10245,7 +10239,6 @@ repeat: *usedlen += 2; } - // ":t" - tail, just the basename if (src[*usedlen] == ':' && src[*usedlen + 1] == 't') { *usedlen += 2; @@ -10486,7 +10479,6 @@ bool common_job_callbacks(dict_T *vopts, CallbackReader *on_stdout, CallbackRead return false; } - Channel *find_job(uint64_t id, bool show_error) { Channel *data = find_channel(id); @@ -10504,7 +10496,6 @@ Channel *find_job(uint64_t id, bool show_error) return data; } - void script_host_eval(char *name, typval_T *argvars, typval_T *rettv) { if (check_secure()) { diff --git a/src/nvim/eval.h b/src/nvim/eval.h index 101f6d9176..fa02b1ea0f 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -199,7 +199,6 @@ typedef struct { hashtab_T sve_hashtab; } save_v_event_T; - /// trans_function_name() flags typedef enum { TFN_INT = 1, ///< May use internal function name diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index 2dd18c0942..7b975ce775 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -414,9 +414,9 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, bool hasnul = false; #define PUT_FST_IN_PAIR(fst_in_pair, str_end) \ do { \ - if (fst_in_pair != 0) { \ - str_end += utf_char2bytes(fst_in_pair, str_end); \ - fst_in_pair = 0; \ + if ((fst_in_pair) != 0) { \ + (str_end) += utf_char2bytes(fst_in_pair, (str_end)); \ + (fst_in_pair) = 0; \ } \ } while (0) for (const char *t = s; t < p; t++) { diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index de93ddc70d..090939666d 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -293,8 +293,8 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ do { \ - const char *const buf_ = (const char *)buf; \ - if (buf == NULL) { \ + const char *const buf_ = (const char *)(buf); \ + if ((buf) == NULL) { \ ga_concat(gap, "''"); \ } else { \ const size_t len_ = (len); \ @@ -383,14 +383,14 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) \ do { \ - if (len != 0) { \ + if ((len) != 0) { \ ga_concat(gap, ", "); \ } \ } while (0) #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) \ do { \ - if ((ptrdiff_t)len != -1) { \ + if ((ptrdiff_t)(len) != -1) { \ ga_concat(gap, ", "); \ } \ } while (0) @@ -452,12 +452,12 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s size_t backref = 0; \ for (; backref < kv_size(*mpstack); backref++) { \ const MPConvStackVal mpval = kv_A(*mpstack, backref); \ - if (mpval.type == conv_type) { \ - if (conv_type == kMPConvDict) { \ + if (mpval.type == (conv_type)) { \ + if ((conv_type) == kMPConvDict) { \ if ((void *)mpval.data.d.dict == (void *)(val)) { \ break; \ } \ - } else if (conv_type == kMPConvList) { \ + } else if ((conv_type) == kMPConvList) { \ if ((void *)mpval.data.l.list == (void *)(val)) { \ break; \ } \ @@ -487,19 +487,19 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s size_t backref = 0; \ for (; backref < kv_size(*mpstack); backref++) { \ const MPConvStackVal mpval = kv_A(*mpstack, backref); \ - if (mpval.type == conv_type) { \ - if (conv_type == kMPConvDict) { \ - if ((void *)mpval.data.d.dict == (void *)val) { \ + if (mpval.type == (conv_type)) { \ + if ((conv_type) == kMPConvDict) { \ + if ((void *)mpval.data.d.dict == (void *)(val)) { \ break; \ } \ - } else if (conv_type == kMPConvList) { \ - if ((void *)mpval.data.l.list == (void *)val) { \ + } else if ((conv_type) == kMPConvList) { \ + if ((void *)mpval.data.l.list == (void *)(val)) { \ break; \ } \ } \ } \ } \ - if (conv_type == kMPConvDict) { \ + if ((conv_type) == kMPConvDict) { \ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{...@%zu}", backref); \ } else { \ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "[...@%zu]", backref); \ @@ -609,7 +609,7 @@ static inline int convert_to_json_string(garray_T *const gap, const char *const // This is done to make resulting values displayable on screen also not from // Neovim. #define ENCODE_RAW(ch) \ - (ch >= 0x20 && utf_printable(ch)) + ((ch) >= 0x20 && utf_printable(ch)) for (size_t i = 0; i < utf_len;) { const int ch = utf_ptr2char(utf_buf + i); const size_t shift = (ch == 0 ? 1 : ((size_t)utf_ptr2len(utf_buf + i))); @@ -788,7 +788,7 @@ bool encode_check_json_key(const typval_T *const tv) #undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK #define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, key) \ do { \ - if (!encode_check_json_key(&key)) { \ + if (!encode_check_json_key(&(key))) { \ emsg(_("E474: Invalid key in special dictionary")); \ goto label; \ } \ @@ -911,7 +911,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ do { \ - if (buf == NULL) { \ + if ((buf) == NULL) { \ msgpack_pack_bin(packer, 0); \ } else { \ const size_t len_ = (len); \ @@ -922,7 +922,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) \ do { \ - if (buf == NULL) { \ + if ((buf) == NULL) { \ msgpack_pack_str(packer, 0); \ } else { \ const size_t len_ = (len); \ @@ -933,11 +933,11 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) \ do { \ - if (buf == NULL) { \ - msgpack_pack_ext(packer, 0, (int8_t)type); \ + if ((buf) == NULL) { \ + msgpack_pack_ext(packer, 0, (int8_t)(type)); \ } else { \ const size_t len_ = (len); \ - msgpack_pack_ext(packer, len_, (int8_t)type); \ + msgpack_pack_ext(packer, len_, (int8_t)(type)); \ msgpack_pack_ext_body(packer, buf, len_); \ } \ } while (0) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 68c2e37f22..fc8c9ef445 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -90,14 +90,15 @@ 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 - static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); static char *e_invalwindow = N_("E957: Invalid window number"); static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); @@ -110,7 +111,6 @@ static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial val /// - using va_start() to initialize it gives "function with fixed args" error static va_list dummy_ap; - /// Function given to ExpandGeneric() to obtain the list of internal /// or user defined function names. char *get_function_name(expand_T *xp, int idx) @@ -343,7 +343,6 @@ static void f_and(typval_T *argvars, typval_T *rettv, FunPtr fptr) & tv_get_number_chk(&argvars[1], NULL); } - /// "api_info()" function static void f_api_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -470,7 +469,6 @@ static void f_browsedir(typval_T *argvars, typval_T *rettv, FunPtr fptr) f_browse(argvars, rettv, NULL); } - /// Find a buffer by number or exact name. static buf_T *find_buffer(typval_T *avar) { @@ -1634,6 +1632,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 +1648,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 +1692,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; } } @@ -2164,7 +2165,6 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) #endif } - /// "menu_get(path [, modes])" function static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -2202,7 +2202,6 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_string = (char *)cmdstr; } - /// "flatten(list[, {maxdepth}])" function static void f_flatten(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -2354,7 +2353,6 @@ static void f_filewritable(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = os_file_is_writable(filename); } - static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) { char_u *fresult = NULL; @@ -2413,7 +2411,6 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) } } - /// "filter()" function static void f_filter(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -2497,7 +2494,6 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr) xfree(fbuf); } - /// "foldclosed()" function static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end) { @@ -3565,7 +3561,6 @@ static void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr) get_qf_loc_list(false, wp, &argvars[1], rettv); } - /// "getmarklist()" function static void f_getmarklist(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -3611,8 +3606,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); @@ -4758,7 +4753,6 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = selected; } - static garray_T ga_userinput = { 0, 0, sizeof(tasave_T), 4, NULL }; /// "inputrestore()" function @@ -5000,7 +4994,6 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - Channel *data = find_job(argvars[0].vval.v_number, true); if (!data) { return; @@ -5165,7 +5158,6 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - dict_T *job_opts = NULL; bool detach = false; bool rpc = false; @@ -5655,7 +5647,6 @@ static void f_localtime(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = (varnumber_T)time(NULL); } - static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) { char *keys_buf = NULL; @@ -5769,7 +5760,6 @@ static void f_mapcheck(typval_T *argvars, typval_T *rettv, FunPtr fptr) get_maparg(argvars, rettv, FALSE); } - static void find_some_match(typval_T *const argvars, typval_T *const rettv, const SomeMatchType type) { @@ -7898,7 +7888,6 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) set_current_funccal((funccall_T *)(provider_caller_scope.funccalp)); } - Error err = ERROR_INIT; uint64_t chan_id = (uint64_t)argvars[0].vval.v_number; @@ -8047,8 +8036,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 +8054,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 +8070,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 +8137,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; @@ -9573,7 +9562,6 @@ static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - bool rpc = false; CallbackReader on_stdin = CALLBACK_READER_INIT; dict_T *opts = argvars[0].vval.v_dict; @@ -9597,7 +9585,6 @@ static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) semsg(e_stdiochan2, error); } - rettv->vval.v_number = (varnumber_T)id; rettv->v_type = VAR_NUMBER; } @@ -10385,7 +10372,6 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr) modec = 'c'; } - const char *p = NULL; switch (TOLOWER_ASC(what[0])) { case 'b': @@ -10533,7 +10519,6 @@ static void f_systemlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) get_system_output_as_rettv(argvars, rettv, true); } - /// "tabpagebuflist()" function static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -10579,7 +10564,6 @@ static void f_tabpagenr(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = nr; } - /// Common code for tabpagewinnr() and winnr(). static int get_winnr(tabpage_T *tp, typval_T *argvar) { @@ -10790,10 +10774,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); @@ -10887,7 +10877,6 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr) timer_start(tv_get_number(&argvars[0]), repeat, &callback); } - /// "timer_stop(timerid)" function static void f_timer_stop(typval_T *argvars, typval_T *rettv, FunPtr fptr) { diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 035bf6318a..2c76741891 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -879,9 +879,9 @@ void tv_list_reverse(list_T *const l) list_log(l, NULL, NULL, "reverse"); #define SWAP(a, b) \ do { \ - tmp = a; \ - a = b; \ - b = tmp; \ + tmp = (a); \ + (a) = (b); \ + (b) = tmp; \ } while (0) listitem_T *tmp; @@ -1515,7 +1515,6 @@ void tv_dict_free(dict_T *const d) } } - /// Unreference a dictionary /// /// Decrements the reference count and frees dictionary when it becomes zero. @@ -2263,36 +2262,36 @@ void tv_blob_copy(typval_T *const from, typval_T *const to) #define TYPVAL_ENCODE_CONV_NIL(tv) \ do { \ - tv->vval.v_special = kSpecialVarNull; \ - tv->v_lock = VAR_UNLOCKED; \ + (tv)->vval.v_special = kSpecialVarNull; \ + (tv)->v_lock = VAR_UNLOCKED; \ } while (0) #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ do { \ - tv->vval.v_bool = kBoolVarFalse; \ - tv->v_lock = VAR_UNLOCKED; \ + (tv)->vval.v_bool = kBoolVarFalse; \ + (tv)->v_lock = VAR_UNLOCKED; \ } while (0) #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ do { \ - (void)num; \ - tv->vval.v_number = 0; \ - tv->v_lock = VAR_UNLOCKED; \ + (void)(num); \ + (tv)->vval.v_number = 0; \ + (tv)->v_lock = VAR_UNLOCKED; \ } while (0) #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ do { \ - tv->vval.v_float = 0; \ - tv->v_lock = VAR_UNLOCKED; \ + (tv)->vval.v_float = 0; \ + (tv)->v_lock = VAR_UNLOCKED; \ } while (0) #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ do { \ xfree(buf); \ - tv->vval.v_string = NULL; \ - tv->v_lock = VAR_UNLOCKED; \ + (tv)->vval.v_string = NULL; \ + (tv)->v_lock = VAR_UNLOCKED; \ } while (0) #define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) @@ -2301,9 +2300,9 @@ void tv_blob_copy(typval_T *const from, typval_T *const to) #define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ do { \ - tv_blob_unref(tv->vval.v_blob); \ - tv->vval.v_blob = NULL; \ - tv->v_lock = VAR_UNLOCKED; \ + tv_blob_unref((tv)->vval.v_blob); \ + (tv)->vval.v_blob = NULL; \ + (tv)->v_lock = VAR_UNLOCKED; \ } while (0) static inline int _nothing_conv_func_start(typval_T *const tv, char_u *const fun) @@ -2360,9 +2359,9 @@ static inline void _nothing_conv_func_end(typval_T *const tv, const int copyID) #define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ do { \ - tv_list_unref(tv->vval.v_list); \ - tv->vval.v_list = NULL; \ - tv->v_lock = VAR_UNLOCKED; \ + tv_list_unref((tv)->vval.v_list); \ + (tv)->vval.v_list = NULL; \ + (tv)->v_lock = VAR_UNLOCKED; \ } while (0) static inline void _nothing_conv_empty_dict(typval_T *const tv, dict_T **const dictp) @@ -2376,8 +2375,8 @@ static inline void _nothing_conv_empty_dict(typval_T *const tv, dict_T **const d } #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ do { \ - assert((void *)&dict != (void *)&TYPVAL_ENCODE_NODICT_VAR); \ - _nothing_conv_empty_dict(tv, ((dict_T **)&dict)); \ + assert((void *)&(dict) != (void *)&TYPVAL_ENCODE_NODICT_VAR); \ + _nothing_conv_empty_dict(tv, ((dict_T **)&(dict))); \ } while (0) static inline int _nothing_conv_real_list_after_start(typval_T *const tv, @@ -2398,7 +2397,7 @@ static inline int _nothing_conv_real_list_after_start(typval_T *const tv, #define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) \ do { \ - if (_nothing_conv_real_list_after_start(tv, &mpsv) != NOTDONE) { \ + if (_nothing_conv_real_list_after_start(tv, &(mpsv)) != NOTDONE) { \ goto typval_encode_stop_converting_one_item; \ } \ } while (0) @@ -2438,8 +2437,9 @@ static inline int _nothing_conv_real_dict_after_start(typval_T *const tv, dict_T #define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) \ do { \ - if (_nothing_conv_real_dict_after_start(tv, (dict_T **)&dict, (void *)&TYPVAL_ENCODE_NODICT_VAR, \ - &mpsv) != NOTDONE) { \ + if (_nothing_conv_real_dict_after_start(tv, (dict_T **)&(dict), \ + (void *)&TYPVAL_ENCODE_NODICT_VAR, &(mpsv)) \ + != NOTDONE) { \ goto typval_encode_stop_converting_one_item; \ } \ } while (0) @@ -2458,7 +2458,7 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic } } #define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \ - _nothing_conv_dict_end(tv, (dict_T **)&dict, \ + _nothing_conv_dict_end(tv, (dict_T **)&(dict), \ (void *)&TYPVAL_ENCODE_NODICT_VAR) #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) @@ -2640,9 +2640,9 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock, const boo // lock/unlock the item itself #define CHANGE_LOCK(lock, var) \ do { \ - var = ((VarLockStatus[]) { \ - [VAR_UNLOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \ - [VAR_LOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \ + (var) = ((VarLockStatus[]) { \ + [VAR_UNLOCKED] = ((lock) ? VAR_LOCKED : VAR_UNLOCKED), \ + [VAR_LOCKED] = ((lock) ? VAR_LOCKED : VAR_UNLOCKED), \ [VAR_FIXED] = VAR_FIXED, \ })[var]; \ } while (0) diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index e5f48501f7..9938dc5012 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -200,7 +200,6 @@ static void register_closure(ufunc_T *fp) [current_funccal->fc_funcs.ga_len++] = fp; } - /// @return a name for a lambda. Returned in static memory. char_u *get_lambda_name(void) { @@ -3598,5 +3597,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..f40573a0bc 100644 --- a/src/nvim/event/loop.c +++ b/src/nvim/event/loop.c @@ -13,7 +13,6 @@ # include "event/loop.c.generated.h" #endif - void loop_init(Loop *loop, void *data) { uv_loop_init(&loop->uv); @@ -143,7 +142,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/event/loop.h b/src/nvim/event/loop.h index b3cd60f53d..c0c5bc527f 100644 --- a/src/nvim/event/loop.h +++ b/src/nvim/event/loop.h @@ -82,7 +82,6 @@ typedef struct loop { } \ } while (0) - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/loop.h.generated.h" #endif diff --git a/src/nvim/event/multiqueue.c b/src/nvim/event/multiqueue.c index a90cbc4e80..40d20033e0 100644 --- a/src/nvim/event/multiqueue.c +++ b/src/nvim/event/multiqueue.c @@ -82,7 +82,6 @@ typedef struct { int refcount; } MulticastEvent; ///< Event present on multiple queues. - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/multiqueue.c.generated.h" #endif diff --git a/src/nvim/event/multiqueue.h b/src/nvim/event/multiqueue.h index dc60fbb4c7..2c5ba9d436 100644 --- a/src/nvim/event/multiqueue.h +++ b/src/nvim/event/multiqueue.h @@ -12,7 +12,6 @@ typedef void (*PutCallback)(MultiQueue *multiq, void *data); #define multiqueue_put(q, h, ...) \ multiqueue_put_event(q, event_create(h, __VA_ARGS__)); - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/multiqueue.h.generated.h" #endif diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h index c20feb2c7a..30254bfe07 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/process.h @@ -33,7 +33,6 @@ struct process { MultiQueue *events; }; - static inline Process process_init(Loop *loop, ProcessType type, void *data) { return (Process) { diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c index 26b5ce3b75..2847788ef8 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -42,7 +42,6 @@ void rstream_init(Stream *stream, size_t bufsize) stream->buffer->nonfull_cb = on_rbuffer_nonfull; } - /// Starts watching for events from a `Stream` instance. /// /// @param stream The `Stream` instance diff --git a/src/nvim/event/rstream.h b/src/nvim/event/rstream.h index 77418c59a2..23ed00bfea 100644 --- a/src/nvim/event/rstream.h +++ b/src/nvim/event/rstream.h @@ -8,7 +8,6 @@ #include "nvim/event/loop.h" #include "nvim/event/stream.h" - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/rstream.h.generated.h" #endif diff --git a/src/nvim/event/signal.c b/src/nvim/event/signal.c index fec46da4ff..4a45a2ec2f 100644 --- a/src/nvim/event/signal.c +++ b/src/nvim/event/signal.c @@ -10,7 +10,6 @@ # include "event/signal.c.generated.h" #endif - void signal_watcher_init(Loop *loop, SignalWatcher *watcher, void *data) FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) { diff --git a/src/nvim/event/time.c b/src/nvim/event/time.c index aa7b9cf2a1..c997e3c558 100644 --- a/src/nvim/event/time.c +++ b/src/nvim/event/time.c @@ -11,7 +11,6 @@ # include "event/time.c.generated.h" #endif - void time_watcher_init(Loop *loop, TimeWatcher *watcher, void *data) FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) { diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 8369db7de1..f6bdfc6175 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -73,7 +73,6 @@ #include "nvim/vim.h" #include "nvim/window.h" - /// Case matching style to use for :substitute typedef enum { kSubHonorOptions = 0, ///< Honor the user's 'ignorecase'/'smartcase' options @@ -971,7 +970,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 +1008,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); @@ -1501,7 +1506,6 @@ void do_shell(char *cmd, int flags) return; } - /* * For autocommands we want to get the output on the current screen, to * avoid having to type return below. @@ -2874,14 +2878,9 @@ 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(); - theend: if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->terminal != NULL) { terminal_check_size(old_curbuf.br_buf->terminal); @@ -4063,7 +4062,6 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle goto skip; } - // 3. Substitute the string. During 'inccommand' preview only do this if // there is a replace pattern. if (!preview || has_second_delim) { @@ -4141,7 +4139,6 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle } replaced_bytes += end.col - start.col; - // Now the trick is to replace CTRL-M chars with a real line // break. This would make it impossible to insert a CTRL-M in // the text. The line break can be avoided by preceding the @@ -4197,7 +4194,6 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle lnum - lnum_start, subcols, sublen - 1, kExtmarkUndo); } - // 4. If subflags.do_all is set, find next match. // Prevent endless loop with patterns that match empty // strings, e.g. :s/$/pat/g or :s/[a-z]* /(&)/g. @@ -4749,7 +4745,6 @@ bool prepare_tagpreview(bool undo_sync) return false; } - /// ":help": open a read-only window on a help file void ex_help(exarg_T *eap) { @@ -4903,9 +4898,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; @@ -4931,7 +4925,6 @@ erret: xfree(tag); } - /// In an argument search for a language specifiers in the form "@xx". /// Changes the "@" to NUL if found, and returns a pointer to "xx". /// @@ -5519,7 +5512,6 @@ void ex_viusage(exarg_T *eap) do_cmdline_cmd("help normal-index"); } - /// Generate tags in one help directory /// /// @param dir Path to the doc directory diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index a6cafb2628..0a91072036 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -537,7 +537,6 @@ bool check_changed(buf_T *buf, int flags) return false; } - /// Ask the user what to do when abandoning a changed buffer. /// Must check 'write' option first! /// @@ -625,7 +624,6 @@ bool can_abandon(buf_T *buf, int forceit) || forceit; } - /// Add a buffer number to "bufnrs", unless it's already there. static void add_bufnum(int *bufnrs, int *bufnump, int nr) { @@ -878,7 +876,6 @@ int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig) return i; } - /// @param str /// @param what /// AL_SET: Redefine the argument list to 'str'. @@ -1637,7 +1634,6 @@ void ex_compiler(exarg_T *eap) } } - /// ":options" void ex_options(exarg_T *eap) { @@ -2146,7 +2142,6 @@ theend: return retval; } - /// Check if fname was sourced before to finds its SID. /// If it's new, generate a new SID. /// @@ -2192,7 +2187,6 @@ scriptitem_T *get_current_script_id(char_u *fname, sctx_T *ret_sctx) return si; } - /// ":scriptnames" void ex_scriptnames(exarg_T *eap) { @@ -2291,7 +2285,6 @@ linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie) : sourcing_lnum; } - /// Get one full line from a sourced file. /// Called by do_cmdline() when it's called from do_source(). /// @@ -2619,7 +2612,6 @@ void do_finish(exarg_T *eap, int reanimate) } } - /// @return true when a sourced file had the ":finish" command: Don't give error /// message for missing ":endif". /// false when not sourcing a file. @@ -2721,7 +2713,6 @@ static char *get_mess_env(void) #endif - /// Set the "v:lang" variable according to the current locale setting. /// Also do "v:lc_time"and "v:ctype". void set_lang_var(void) @@ -2869,7 +2860,6 @@ void ex_language(exarg_T *eap) } } - static char **locales = NULL; // Array of all available locales # ifndef WIN32 @@ -2971,7 +2961,6 @@ char *get_locales(expand_T *xp, int idx) #endif - static void script_host_execute(char *name, exarg_T *eap) { size_t len; diff --git a/src/nvim/ex_cmds2.h b/src/nvim/ex_cmds2.h index d426ff28f8..74e52dfb4b 100644 --- a/src/nvim/ex_cmds2.h +++ b/src/nvim/ex_cmds2.h @@ -6,7 +6,6 @@ #include "nvim/ex_docmd.h" #include "nvim/runtime.h" - // // flags for check_changed() // diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index e845073c12..4b7958efa5 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -115,7 +115,6 @@ struct loop_cookie { void *cookie; }; - // Struct to save a few things while debugging. Used in do_cmdline() only. struct dbg_stuff { int trylevel; @@ -345,7 +344,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); @@ -624,7 +623,6 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) next_cmdline = cmdline_copy; } - // reset did_emsg for a function that is not aborted by an error if (did_emsg && !force_abort && getline_equal(fgetline, cookie, get_func_line) @@ -1109,7 +1107,6 @@ static int current_tab_nr(tabpage_T *tab) #define CURRENT_TAB_NR current_tab_nr(curtab) #define LAST_TAB_NR current_tab_nr(NULL) - /// Figure out the address type for ":wincmd". static void get_wincmd_addr_type(char *arg, exarg_T *eap) { @@ -1583,13 +1580,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 +1646,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 +1681,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 +1704,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 } @@ -4669,7 +4672,6 @@ static void correct_range(exarg_T *eap) } } - /// For a ":vimgrep" or ":vimgrepadd" command return a pointer past the /// pattern. Otherwise return eap->arg. static char *skip_grep_pat(exarg_T *eap) @@ -5522,6 +5524,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) @@ -5624,7 +5631,6 @@ fail: return FAIL; } - static struct { cmd_addr_T expand; char *name; @@ -6947,7 +6953,6 @@ static void ex_highlight(exarg_T *eap) do_highlight((const char *)eap->arg, eap->forceit, false); } - /// Call this function if we thought we were going to exit, but we won't /// (because of an error). May need to restore the terminal mode. void not_exiting(void) @@ -7154,7 +7159,6 @@ void ex_win_close(int forceit, win_T *win, tabpage_T *tp) } } - // free buffer when not hiding it or when it's a scratch buffer if (tp == NULL) { win_close(win, !need_hide && !buf_hide(buf), forceit); @@ -7421,7 +7425,7 @@ static void ex_goto(exarg_T *eap) /// Clear an argument list: free all file names and reset it to zero entries. void alist_clear(alist_T *al) { -#define FREE_AENTRY_FNAME(arg) xfree(arg->ae_fname) +#define FREE_AENTRY_FNAME(arg) xfree((arg)->ae_fname) GA_DEEP_CLEAR(&al->al_ga, aentry_T, FREE_AENTRY_FNAME); } @@ -7431,7 +7435,6 @@ void alist_init(alist_T *al) ga_init(&al->al_ga, (int)sizeof(aentry_T), 5); } - /// Remove a reference from an argument list. /// Ignored when the argument list is the global one. /// If the argument list is no longer used by any window, free it. @@ -7672,7 +7675,6 @@ void ex_splitview(exarg_T *eap) do_exedit(eap, old_curwin); } - theend: xfree(fname); } @@ -7790,7 +7792,6 @@ static void ex_tabs(exarg_T *eap) } } - /// ":mode": /// If no argument given, get the screen size and redraw. static void ex_mode(exarg_T *eap) @@ -8000,7 +8001,6 @@ static void ex_nogui(exarg_T *eap) eap->errmsg = N_("E25: Nvim does not have a built-in GUI"); } - static void ex_swapname(exarg_T *eap) { if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) { @@ -8043,7 +8043,6 @@ static void ex_syncbind(exarg_T *eap) topline = 1; } - /* * Set all scrollbind windows to the same topline. */ @@ -8078,7 +8077,6 @@ static void ex_syncbind(exarg_T *eap) } } - static void ex_read(exarg_T *eap) { int i; @@ -8831,7 +8829,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 +8845,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 +8966,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 +8973,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 +8995,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; @@ -9237,7 +9231,6 @@ static void ex_findpat(exarg_T *eap) } } - /// ":ptag", ":ptselect", ":ptjump", ":ptnext", etc. static void ex_ptag(exarg_T *eap) { 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_eval.c b/src/nvim/ex_eval.c index fa70f762a2..46b9528546 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -439,7 +439,6 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, int * return ret; } - /// Throw a new exception. "value" is the exception string for a /// user or interrupt exception, or points to a message list in case of an /// error exception. @@ -1140,7 +1139,6 @@ void ex_endwhile(exarg_T *eap) } } - /// Handle ":throw expr" void ex_throw(exarg_T *eap) { @@ -1868,7 +1866,6 @@ void leave_cleanup(cleanup_T *csp) } } - /// Make conditionals inactive and discard what's pending in finally clauses /// until the conditional type searched for or a try conditional not in its /// finally clause is reached. If this is in an active catch clause, finish @@ -2009,7 +2006,6 @@ static char *get_end_emsg(cstack_T *cstack) return e_endif; } - /// Rewind conditionals until index "idx" is reached. "cond_type" and /// "cond_level" specify a conditional type and the address of a level variable /// which is to be decremented with each skipped conditional of the specified diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 114f1e2ae5..13cfd76adf 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; @@ -910,7 +916,6 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init apply_autocmds(EVENT_CMDLINEENTER, firstcbuf, firstcbuf, false, curbuf); restore_v_event(dict, &save_v_event); - tl_ret = try_leave(&tstate, &err); if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); @@ -995,12 +1000,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 +1335,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 +1397,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 @@ -1603,7 +1605,6 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ int search_flags = SEARCH_NOOF; char_u save; - if (search_delim == ccline.cmdbuff[skiplen]) { pat = last_search_pattern(); if (pat == NULL) { @@ -1997,7 +1998,6 @@ static int command_line_handle_key(CommandLineState *s) // Ignore mouse event or open_cmdwin() result. return command_line_not_changed(s); - case K_MIDDLEDRAG: case K_MIDDLERELEASE: return command_line_not_changed(s); // Ignore mouse @@ -2007,7 +2007,6 @@ static int command_line_handle_key(CommandLineState *s) redrawcmd(); return command_line_changed(s); - case K_LEFTDRAG: case K_LEFTRELEASE: case K_RIGHTDRAG: @@ -2057,7 +2056,6 @@ static int command_line_handle_key(CommandLineState *s) case K_MOUSEMOVE: return command_line_not_changed(s); - case K_SELECT: // end of Select mode mapping - ignore return command_line_not_changed(s); @@ -2281,7 +2279,6 @@ static int command_line_handle_key(CommandLineState *s) return command_line_changed(s); } - static int command_line_not_changed(CommandLineState *s) { // Incremental searches for "/" and "?": @@ -2551,7 +2548,6 @@ static int cmd_startcol(void) return ccline.cmdindent + ((ccline.cmdfirstc != NUL) ? 1 : 0); } - /// Compute the column position for a byte position on the command line. static int cmd_screencol(int bytepos) { @@ -2614,7 +2610,6 @@ bool cmdline_overstrike(void) return ccline.overstrike; } - /// Return true if the cursor is at the end of the cmdline. bool cmdline_at_end(void) FUNC_ATTR_PURE @@ -3438,7 +3433,6 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) return FAIL; } - // Need to set "textlock" to avoid nasty things like going to another // buffer when evaluating an expression. textlock++; @@ -5584,7 +5578,6 @@ static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file) return OK; } - /// Expand `file` for all comma-separated directories in `path`. /// Adds matches to `ga`. void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options) @@ -5625,7 +5618,6 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options) xfree(buf); } - /********************************* * Command line history stuff * *********************************/ @@ -5915,7 +5907,6 @@ void add_to_history(int histype, char_u *new_entry, int in_map, int sep) } } - /* * Get identifier of newest history entry. * "histype" may be one of the HIST_ values. @@ -5930,7 +5921,6 @@ int get_history_idx(int histype) return history[histype][hisidx[histype]].hisnum; } - /// Get pointer to the command line info to use. save_cmdline() may clear /// ccline and put the previous value in ccline.prev_ccline. static struct cmdline_info *get_ccline_ptr(void) 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/extmark.c b/src/nvim/extmark.c index f367bc66e0..72c7640d3d 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -53,7 +53,6 @@ static uint32_t *buf_ns_ref(buf_T *buf, uint32_t ns_id, bool put) return map_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, put); } - /// Create or update an extmark /// /// must not be used during iteration! @@ -361,7 +360,6 @@ ExtmarkInfo extmark_from_id(buf_T *buf, uint32_t ns_id, uint32_t id) return ret; } - /// free extmarks from the buffer void extmark_free_all(buf_T *buf) { @@ -391,7 +389,6 @@ void extmark_free_all(buf_T *buf) map_init(uint32_t, uint32_t, buf->b_extmark_ns); } - /// Save info for undo/redo of set marks static void u_extmark_set(buf_T *buf, uint64_t mark, int row, colnr_T col) { @@ -501,7 +498,6 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo) } } - /// Adjust extmark row for inserted/deleted rows (columns stay fixed). void extmark_adjust(buf_T *buf, linenr_T line1, linenr_T line2, long amount, long amount_after, ExtmarkOp undo) @@ -593,7 +589,6 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t u_extmark_copy(buf, start_row, start_col, end_row, end_col); } - marktree_splice(buf->b_marktree, (int32_t)start_row, start_col, old_row, old_col, new_row, new_col); @@ -684,7 +679,6 @@ void extmark_move_region(buf_T *buf, int start_row, colnr_T start_col, bcount_t 0, 0, 0, extent_row, extent_col, extent_byte); - if (undo == kExtmarkUndo) { u_header_T *uhp = u_force_get_undo_header(buf); if (!uhp) { diff --git a/src/nvim/extmark.h b/src/nvim/extmark.h index b856a1148f..c144504076 100644 --- a/src/nvim/extmark.h +++ b/src/nvim/extmark.h @@ -26,7 +26,6 @@ typedef kvec_t(ExtmarkInfo) ExtmarkInfoArray; // TODO(bfredl): good enough name for now. typedef ptrdiff_t bcount_t; - // delete the columns between mincol and endcol typedef struct { int start_row; @@ -80,7 +79,6 @@ struct undo_object { } data; }; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "extmark.h.generated.h" #endif diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 47e20d58a3..e327b97fbe 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -146,7 +146,6 @@ typedef struct ff_visited_list_hdr { ff_visited_T *ffvl_visited_list; } ff_visited_list_hdr_T; - /* * '**' can be expanded to several directory levels. * Set the default maximum depth. diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 06d72f3395..8d8c10f823 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -147,7 +147,6 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr) msg_scrolled_ign = false; } - /// Read lines from file "fname" into the buffer after line "from". /// /// 1. We allocate blocks with try_malloc, as big as possible. @@ -839,7 +838,6 @@ retry: fio_flags = get_fio_flags((char_u *)fenc); } - #ifdef HAVE_ICONV // Try using iconv() if we can't convert internally. if (fio_flags == 0 @@ -1293,7 +1291,6 @@ retry: size -= conv_restlen; } - while (p > (uint8_t *)ptr) { if (fio_flags & FIO_LATIN1) { u8c = *--p; @@ -1995,7 +1992,6 @@ bool is_dev_fd_file(char_u *fname) } #endif - /// From the current line count and characters read after that, estimate the /// line number where we are now. /// Used for error messages that include a line number. @@ -2146,7 +2142,6 @@ static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp) return tmpname; } - /// Read marks for the current buffer from the ShaDa file, when we support /// buffer marks and the buffer has a name. static void check_marks_read(void) @@ -2200,11 +2195,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en linenr_T lnum; long nchars; #define SET_ERRMSG_NUM(num, msg) \ - errnum = num, errmsg = msg, errmsgarg = 0 + errnum = (num), errmsg = (msg), errmsgarg = 0 #define SET_ERRMSG_ARG(msg, error) \ - errnum = NULL, errmsg = msg, errmsgarg = error + errnum = NULL, errmsg = (msg), errmsgarg = error #define SET_ERRMSG(msg) \ - errnum = NULL, errmsg = msg, errmsgarg = 0 + errnum = NULL, errmsg = (msg), errmsgarg = 0 const char *errnum = NULL; char *errmsg = NULL; int errmsgarg = 0; @@ -3053,7 +3048,6 @@ nobackup: } } - // Default: write the file directly. May write to a temp file for // multi-byte conversion. wfname = fname; @@ -3089,7 +3083,6 @@ nobackup: } } - if (converted && wb_flags == 0) { #ifdef HAVE_ICONV // Use iconv() conversion when conversion is needed and it's not done @@ -4109,7 +4102,6 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL bool error = false; int cc; - if (flags & FIO_UCS4) { if (flags & FIO_ENDIAN_L) { *p++ = c; @@ -4238,7 +4230,6 @@ static int get_fio_flags(const char_u *name) return 0; } - /// Check for a Unicode BOM (Byte Order Mark) at the start of p[size]. /// "size" must be at least 2. /// @@ -5493,7 +5484,6 @@ char_u *vim_tempname(void) return vim_strsave(template); } - /// Tries matching a filename with a "pattern" ("prog" is NULL), or use the /// precompiled regprog "prog" ("pattern" is NULL). That avoids calling /// vim_regcomp() often. diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 090f754e93..234c11227d 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -660,7 +660,6 @@ void foldCreate(win_T *wp, pos_T start, pos_T end) } } - // deleteFold() {{{2 /// @param start delete all folds from start to end when not 0 /// @param end delete all folds from start to end when not 0 @@ -775,7 +774,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 +784,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 +1935,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 +2002,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 +2010,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 +2322,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..788e1113e2 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -54,7 +54,6 @@ #include "nvim/undo.h" #include "nvim/vim.h" - /// Index in scriptin static int curscript = 0; FileDescriptor *scriptin[NSCRIPT] = { NULL }; @@ -1352,14 +1351,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 +1370,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 +1877,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 +2509,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; @@ -3441,7 +3432,6 @@ theend: return retval; } - /// Set or remove a mapping or an abbreviation in the current buffer, OR /// display (matching) mappings/abbreviations. /// @@ -3809,7 +3799,7 @@ bool map_to_exists(const char *const str, const char *const modechars, const boo #define MAPMODE(mode, modechars, chr, modeflags) \ do { \ if (strchr(modechars, chr) != NULL) { \ - mode |= modeflags; \ + (mode) |= (modeflags); \ } \ } while (0) MAPMODE(mode, modechars, 'n', MODE_NORMAL); @@ -4724,7 +4714,6 @@ char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapb return NULL; } - /// Add a mapping. Unlike @ref do_map this copies the {map} argument, so /// static or read-only strings can be used. /// @@ -4866,7 +4855,6 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat) c1 = TO_SPECIAL(c1, c2); } - if (got_int) { aborted = true; } else if (c1 == '\r' || c1 == '\n') { diff --git a/src/nvim/globals.h b/src/nvim/globals.h index e34e3983db..b0006ebaca 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). @@ -96,7 +96,6 @@ EXTERN int Columns INIT(= DFLT_COLS); // nr of columns in the screen EXTERN NS ns_hl_active INIT(= 0); // current ns that defines highlights EXTERN bool ns_hl_changed INIT(= false); // highlight need update - // We use 64-bit file functions here, if available. E.g. ftello() returns // off_t instead of long, which helps if long is 32 bit and off_t is 64 bit. // We assume that when fseeko() is available then ftello() is too. @@ -202,7 +201,6 @@ EXTERN bool msg_scrolled_ign INIT(= false); // is reset before the screen is redrawn, so we need to keep track of this. EXTERN bool msg_did_scroll INIT(= false); - EXTERN char_u *keep_msg INIT(= NULL); // msg to be shown after redraw EXTERN int keep_msg_attr INIT(= 0); // highlight attr for keep_msg EXTERN bool need_fileinfo INIT(= false); // do fileinfo() after redraw @@ -315,7 +313,6 @@ EXTERN bool suppress_errthrow INIT(= false); /// cstacks; the pending exceptions, however, are not on the caught stack. EXTERN except_T *caught_stack INIT(= NULL); - /// /// Garbage collection can only take place when we are sure there are no Lists /// or Dictionaries being used internally. This is flagged with @@ -361,7 +358,6 @@ EXTERN struct caller_scope { } provider_caller_scope; EXTERN int provider_call_nesting INIT(= 0); - EXTERN int t_colors INIT(= 256); // int value of T_CCO // Flags to indicate an additional string for highlight name completion. @@ -421,10 +417,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. @@ -482,7 +474,6 @@ EXTERN buf_T *curbuf INIT(= NULL); // currently active buffer #define FOR_ALL_SIGNS_IN_BUF(buf, sign) \ for ((sign) = (buf)->b_signlist; (sign) != NULL; (sign) = (sign)->se_next) // NOLINT - // List of files being edited (global argument list). curwin->w_alist points // to this when the window is using the global argument list. EXTERN alist_T global_alist; // global argument list @@ -797,7 +788,6 @@ enum { WM_LIST = 3, ///< cmdline CTRL-D }; - // Some file names are stored in pathdef.c, which is generated from the // Makefile to make their value depend on the Makefile. #ifdef HAVE_PATHDEF @@ -846,7 +836,6 @@ EXTERN bool no_hlsearch INIT(= false); // Page number used for %N in 'pageheader' and 'guitablabel'. EXTERN linenr_T printer_page_num; - EXTERN bool typebuf_was_filled INIT(= false); // received text from client // or from feedkeys() @@ -877,7 +866,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..7d407bd3d1 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" @@ -16,7 +17,6 @@ // Per-cell attributes static size_t linebuf_size = 0; - /// Determine if dedicated window grid should be used or the default_grid /// /// If UI did not request multigrid support, draw all windows on the @@ -63,7 +63,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 +92,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,14 +128,13 @@ 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]); } } - /// put string '*text' on the window grid at position 'row' and 'col', with /// attributes 'attr', and update chars[] and attrs[]. /// Note: only outputs within one row, message is truncated at grid boundary! @@ -202,8 +201,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 +224,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 +258,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 = '>'; @@ -271,7 +270,6 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col schar_T buf; schar_from_cc(buf, u8c, u8cc); - need_redraw = schar_cmp(grid->chars[off], buf) || (mbyte_cells == 2 && grid->chars[off + 1][0] != 0) || grid->attrs[off] != attr @@ -338,7 +336,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 +369,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 +389,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 +441,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 +489,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 +507,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 +615,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 +644,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 +658,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 +703,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..1571340849 100644 --- a/src/nvim/grid_defs.h +++ b/src/nvim/grid_defs.h @@ -21,7 +21,6 @@ enum { kZIndexCmdlinePopupMenu = 250, }; - /// ScreenGrid represents a resizable rectuangular grid displayed by UI clients. /// /// chars[] contains the UTF-8 text that is currently displayed on the grid. @@ -58,8 +57,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 +110,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/hardcopy.c b/src/nvim/hardcopy.c index fb174baef8..00a3c3cdab 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -116,7 +116,6 @@ static option_table_T printer_opts[OPT_PRINT_NUM_OPTIONS] } ; - static const uint32_t cterm_color_8[8] = { 0x000000, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff @@ -366,7 +365,6 @@ static char *parse_list_options(char_u *option_str, option_table_T *table, size_ return ret; } - /* * If using a dark background, the colors will probably be too bright to show * up well on white paper, so reduce their brightness. @@ -970,7 +968,6 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T return col; } - /* * PS printer stuff. * @@ -1242,7 +1239,6 @@ static struct prt_ps_mbfont_S prt_ps_mbfonts[] = #define PRT_RESOURCE_ENCODING "Encoding" #define PRT_RESOURCE_CMAP "CMap" - /* Data for table based DSC comment recognition, easy to extend if VIM needs to * read more comments. */ #define PRT_DSC_MISC_TYPE (-1) @@ -1254,7 +1250,6 @@ static struct prt_ps_mbfont_S prt_ps_mbfonts[] = #define PRT_DSC_VERSION "%%Version:" #define PRT_DSC_ENDCOMMENTS "%%EndComments:" - #define SIZEOF_CSTR(s) (sizeof(s) - 1) static struct prt_dsc_comment_S prt_dsc_table[] = { @@ -1265,7 +1260,6 @@ static struct prt_dsc_comment_S prt_dsc_table[] = PRT_DSC_ENDCOMMENTS_TYPE } }; - /* * Variables for the output PostScript file. */ @@ -2053,7 +2047,6 @@ static void prt_font_metrics(int font_scale) prt_char_width = PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx); } - static int prt_get_cpl(void) { if (prt_use_number()) { @@ -2168,7 +2161,6 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) struct prt_ps_encoding_S *p_mbenc_first; struct prt_ps_charset_S *p_mbchar = NULL; - /* * Set up font and encoding. */ diff --git a/src/nvim/hardcopy.h b/src/nvim/hardcopy.h index 16119c5d2d..7b28169a5b 100644 --- a/src/nvim/hardcopy.h +++ b/src/nvim/hardcopy.h @@ -80,7 +80,6 @@ typedef struct { #define PRINT_NUMBER_WIDTH 8 - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "hardcopy.h.generated.h" #endif diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 90ca0047bd..3bcd72fc39 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -229,7 +229,6 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault) } } - bool win_check_ns_hl(win_T *wp) { if (ns_hl_changed) { @@ -760,7 +759,6 @@ Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb) PUT(hl, "underdash", BOOLEAN_OBJ(true)); } - if (mask & HL_ITALIC) { PUT(hl, "italic", BOOLEAN_OBJ(true)); } diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 0515842b61..caf345386d 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,9 +174,10 @@ EXTERN const char *hlf_names[] INIT(= { [HLF_NFLOAT] = "NormalFloat", [HLF_MSG] = "MsgArea", [HLF_BORDER] = "FloatBorder", + [HLF_WBR] = "WinBar", + [HLF_WBRNC] = "WinBarNC", }); - EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context. EXTERN int highlight_attr_last[HLF_COUNT]; // copy for detecting changed groups EXTERN int highlight_user[9]; // User[1-9] attributes @@ -218,5 +221,4 @@ typedef struct { #define COLOR_ITEM_INITIALIZER { .attr_id = -1, .link_id = -1, \ .version = -1, .is_default = false } - #endif // NVIM_HIGHLIGHT_DEFS_H diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 240a96cb4b..05781dd7e2 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", @@ -1833,7 +1835,6 @@ int syn_get_final_id(int hl_id) continue; } - if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) { break; } diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 7174e58986..af0d32ad9c 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -68,7 +68,6 @@ static void cs_usage_msg(csid_e x) (void)semsg(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage); } - static enum { EXP_CSCOPE_SUBCMD, // expand ":cscope" sub-commands EXP_SCSCOPE_SUBCMD, // expand ":scscope" sub-commands @@ -169,7 +168,6 @@ void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx) } } - /// Find the command, print help if invalid, and then call the corresponding /// command function. /// @@ -274,7 +272,6 @@ void ex_cstag(exarg_T *eap) } } - /// This simulates a vim_fgets(), but for cscope, returns the next line /// from the cscope output. should only be called from find_tags() /// @@ -292,7 +289,6 @@ bool cs_fgets(char_u *buf, int size) return false; } - /// Called only from do_tag(), when popping the tag stack. void cs_free_tags(void) { @@ -380,7 +376,6 @@ bool cs_connection(int num, char_u *dbpath, char_u *ppath) return false; } // cs_connection - /* * PRIVATE functions ****************************************************************************/ @@ -408,7 +403,6 @@ static void cs_stat_emsg(char *fname) (void)semsg(_("E563: stat(%s) error: %d"), fname, err); } - /// The common routine to add a new cscope connection. Called by /// cs_add() and cs_reset(). I really don't like to do this, but this /// routine uses a number of goto statements. @@ -520,7 +514,6 @@ add_err: return CSCOPE_FAILURE; } - static bool cs_check_for_connections(void) { return cs_cnt_connections() > 0; @@ -613,7 +606,6 @@ static int cs_cnt_matches(size_t idx) return nlines; } - /// Creates the actual cscope command query from what the user entered. static char *cs_create_cmd(char *csoption, char *pattern) { @@ -680,7 +672,6 @@ static char *cs_create_cmd(char *csoption, char *pattern) return cmd; } - /// This piece of code was taken/adapted from nvi. do we need to add /// the BSD license notice? static int cs_create_connection(size_t i) @@ -879,7 +870,6 @@ err_closing: return CSCOPE_SUCCESS; } - /// Query cscope using command line interface. Parse the output and use tselect /// to allow choices. Like Nvi, creates a pipe to send to/from query/cscope. /// @@ -918,7 +908,6 @@ static int cs_find(exarg_T *eap) eap->cmdidx == CMD_lcscope, (char_u *)(*eap->cmdlinep)); } - /// Common code for cscope find, shared by cs_find() and ex_cstag(). static bool cs_find_common(char *opt, char *pat, int forceit, int verbose, bool use_ll, char_u *cmdline) @@ -1119,7 +1108,6 @@ static int cs_help(exarg_T *eap) return CSCOPE_SUCCESS; } - static void clear_csinfo(size_t i) { csinfo[i].fname = NULL; @@ -1193,7 +1181,6 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, FileInfo *f return (int)i; } - /// Find cscope command in command table. static cscmd_T *cs_lookup_cmd(exarg_T *eap) { @@ -1221,7 +1208,6 @@ static cscmd_T *cs_lookup_cmd(exarg_T *eap) return NULL; } - /// Nuke em. static int cs_kill(exarg_T *eap) { @@ -1281,7 +1267,6 @@ static int cs_kill(exarg_T *eap) return CSCOPE_SUCCESS; } - /// Actually kills a specific cscope connection. /// /// @param i cscope table index @@ -1296,7 +1281,6 @@ static void cs_kill_execute(size_t i, char *cname) cs_release_csp(i, TRUE); } - /// Convert the cscope output into a ctags style entry (as might be found /// in a ctags tags file). there's one catch though: cscope doesn't tell you /// the type of the tag you are looking for. for example, in Darren Hiebert's @@ -1343,7 +1327,6 @@ static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, ch return buf; } - /// This is kind of hokey, but i don't see an easy way round this. /// /// Store: keep a ptr to the (malloc'd) memory of matches originally @@ -1415,7 +1398,6 @@ static char *cs_manage_matches(char **matches, char **contexts, size_t totmatche return p; } - /// Parse cscope output. static char *cs_parse_results(size_t cnumber, char *buf, int bufsize, char **context, char **linenumber, char **search) @@ -1581,7 +1563,6 @@ static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a, xfree(buf); } - // get the requested path components static char *cs_pathcomponents(char *path) { @@ -1929,7 +1910,6 @@ static void cs_release_csp(size_t i, bool freefnpp) clear_csinfo(i); } - /// Calls cs_kill on all cscope connections then reinits. static int cs_reset(exarg_T *eap) { @@ -1980,7 +1960,6 @@ static int cs_reset(exarg_T *eap) return CSCOPE_SUCCESS; } - /// Construct the full pathname to a file found in the cscope database. /// (Prepends ppath, if there is one and if it's not already prepended, /// otherwise just uses the name found.) @@ -2031,7 +2010,6 @@ static char *cs_resolve_file(size_t i, char *name) return fullname; } - /// Show all cscope connections. static int cs_show(exarg_T *eap) { @@ -2059,7 +2037,6 @@ static int cs_show(exarg_T *eap) return CSCOPE_SUCCESS; } - /// Only called when VIM exits to quit any cscope sessions. void cs_end(void) { diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 882a10e1e8..010d2fe869 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -26,7 +26,6 @@ #include "nvim/strings.h" #include "nvim/undo.h" - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "indent.c.generated.h" #endif @@ -40,7 +39,6 @@ int get_indent(void) false); } - // Count the size (in window cells) of the indent in line "lnum". int get_indent_lnum(linenr_T lnum) { @@ -50,7 +48,6 @@ int get_indent_lnum(linenr_T lnum) false); } - // Count the size (in window cells) of the indent in line "lnum" of buffer // "buf". int get_indent_buf(buf_T *buf, linenr_T lnum) @@ -61,7 +58,6 @@ int get_indent_buf(buf_T *buf, linenr_T lnum) false); } - /// Count the size (in window cells) of the indent in line "ptr", with /// 'tabstop' at "ts". /// If @param list is true, count only screen size for tabs. @@ -387,7 +383,6 @@ int set_indent(int size, int flags) return retval; } - // Return the indent of the current line after a number. Return -1 if no // number was found. Used for 'n' in 'formatoptions': numbered list. // Since a pattern is used it can actually handle more than numbers. @@ -580,7 +575,6 @@ int get_expr_indent(void) return indent; } - // When 'p' is present in 'cpoptions, a Vi compatible method is used. // The incompatible newer method is quite a bit better at indenting // code in lisp-like languages than the traditional one; it's still @@ -766,7 +760,6 @@ int get_lisp_indent(void) return amount; } - static int lisp_match(char_u *p) { char_u buf[LSIZE]; diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index e6dc985726..29d3c5f95b 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -212,7 +212,6 @@ int is_pos_in_string(const char_u *line, colnr_T col) * Below "XXX" means that this function may unlock the current line. */ - /* * Return true if the string "line" starts with a word from 'cinwords'. */ @@ -238,7 +237,6 @@ bool cin_is_cinword(const char_u *line) return retval; } - /* * Skip over white space and C comments within the line. * Also skip over Perl/shell comments if desired. @@ -1422,7 +1420,6 @@ static int cin_is_cpp_extern_c(const char_u *s) return false; } - /* * Skip strings, chars and comments until at or past "trypos". * Return the column found. @@ -1553,7 +1550,6 @@ static pos_T *find_match_paren_after_brace(int ind_maxparen) return trypos; } - /* * Return ind_maxparen corrected for the difference in line number between the * cursor position and "startpos". This makes sure that searching for a @@ -3746,7 +3742,6 @@ term_again: amount += curbuf->b_ind_comment; } - // add extra indent if the previous line ended in a backslash: // "asdfasdf{backslash} // here"; diff --git a/src/nvim/lib/kbtree.h b/src/nvim/lib/kbtree.h index 2edec527ff..99f79952d7 100644 --- a/src/nvim/lib/kbtree.h +++ b/src/nvim/lib/kbtree.h @@ -224,7 +224,6 @@ kb_putp_##name(b, &k); \ } - #define __KB_DEL(name, key_t, kbnode_t, T) \ static inline key_t __kb_delp_aux_##name(kbtree_##name##_t *b, kbnode_t *x, key_t * __restrict k, \ int s) \ diff --git a/src/nvim/lib/khash.h b/src/nvim/lib/khash.h index e81db43038..57a41f9c13 100644 --- a/src/nvim/lib/khash.h +++ b/src/nvim/lib/khash.h @@ -113,7 +113,6 @@ * Added destructor */ - #ifndef NVIM_LIB_KHASH_H #define NVIM_LIB_KHASH_H diff --git a/src/nvim/lib/klist.h b/src/nvim/lib/klist.h index c8489e298b..a9abbc6dc2 100644 --- a/src/nvim/lib/klist.h +++ b/src/nvim/lib/klist.h @@ -32,7 +32,6 @@ #include "nvim/func_attr.h" #include "nvim/memory.h" - #define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \ typedef struct { \ size_t cnt, n, max; \ diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h index 68841e0af8..4238088b1c 100644 --- a/src/nvim/lib/kvec.h +++ b/src/nvim/lib/kvec.h @@ -121,7 +121,6 @@ #define kv_push(v, x) \ (*kv_pushp(v) = (x)) - #define kv_a(v, i) \ (*(((v).capacity <= (size_t)(i) \ ? ((v).capacity = (v).size = (i) + 1, \ diff --git a/src/nvim/lib/queue.h b/src/nvim/lib/queue.h index e5574094bc..c6d3f74ec1 100644 --- a/src/nvim/lib/queue.h +++ b/src/nvim/lib/queue.h @@ -44,7 +44,6 @@ typedef struct _queue { (q) = next; \ } - // ffi.cdef is unable to swallow `bool` in place of `int` here. static inline int QUEUE_EMPTY(const QUEUE *const q) FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT diff --git a/src/nvim/log.h b/src/nvim/log.h index 81e39d1cdd..724d073d02 100644 --- a/src/nvim/log.h +++ b/src/nvim/log.h @@ -16,7 +16,6 @@ # define NVIM_PROBE(name, n, ...) #endif - #define TRACE_LOG_LEVEL 0 #define DEBUG_LOG_LEVEL 1 #define INFO_LOG_LEVEL 2 diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 782fc425fc..4d6e6090b8 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -49,7 +49,6 @@ typedef struct { #define LUA_PUSH_STATIC_STRING(lstate, s) \ lua_pushlstring(lstate, s, sizeof(s) - 1) - static LuaTableProps nlua_traverse_table(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { @@ -674,7 +673,6 @@ static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, lua_rawset(lstate, -3); } - /// Convert given String to lua string /// /// Leaves converted string on top of the stack. @@ -808,7 +806,6 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special) } } - /// Convert lua value to string /// /// Always pops one value from the stack. @@ -1297,7 +1294,6 @@ void nlua_init_types(lua_State *const lstate) lua_rawset(lstate, -3); } - void nlua_pop_keydict(lua_State *L, void *retval, field_hash hashy, Error *err) { if (!lua_istable(L, -1)) { diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index c2d76e3ce8..0009420281 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -135,7 +135,6 @@ static int nlua_pcall(lua_State *lstate, int nargs, int nresults) return status; } - /// Gets the version of the current Nvim build. /// /// @param lstate Lua interpreter state. @@ -147,7 +146,6 @@ static int nlua_nvim_version(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } - static void nlua_luv_error_event(void **argv) { char *error = (char *)argv[0]; @@ -1051,7 +1049,6 @@ static int nlua_empty_dict_tostring(lua_State *lstate) return 1; } - #ifdef WIN32 /// os.getenv: override os.getenv to maintain coherency. #9681 /// @@ -1065,7 +1062,6 @@ static int nlua_getenv(lua_State *lstate) } #endif - /// add the value to the registry /// The current implementation does not support calls from threads. LuaRef nlua_ref(lua_State *lstate, nlua_ref_state_t *ref_state, int index) @@ -1084,7 +1080,6 @@ LuaRef nlua_ref(lua_State *lstate, nlua_ref_state_t *ref_state, int index) return ref; } - LuaRef nlua_ref_global(lua_State *lstate, int index) { return nlua_ref(lstate, nlua_global_refs, index); @@ -1110,7 +1105,6 @@ void nlua_unref_global(lua_State *lstate, LuaRef ref) nlua_unref(lstate, nlua_global_refs, ref); } - void api_free_luaref(LuaRef ref) { nlua_unref_global(global_lstate, ref); @@ -1122,7 +1116,6 @@ void nlua_pushref(lua_State *lstate, LuaRef ref) lua_rawgeti(lstate, LUA_REGISTRYINDEX, ref); } - /// Gets a new reference to an object stored at original_ref /// /// NOTE: It does not copy the value, it creates a new ref to the lua object. @@ -1140,7 +1133,6 @@ LuaRef api_new_luaref(LuaRef original_ref) return new_ref; } - /// Evaluate lua string /// /// Used for luaeval(). @@ -1754,7 +1746,6 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) char_u *name = register_cfunc(&nlua_CFunction_func_call, &nlua_CFunction_func_free, state); - lua_pop(lstate, 1); // [] assert(top == lua_gettop(lstate)); diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 79e21e518c..432cb25adc 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -349,7 +349,6 @@ static dict_T *nlua_get_var_scope(lua_State *lstate) return dict; } - int nlua_setvar(lua_State *lstate) { // non-local return if not found @@ -470,7 +469,6 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } - void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) { if (!is_thread) { diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index d3693207ec..6ec9cfd21d 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -529,7 +529,6 @@ static int parser_set_ranges(lua_State *L) size_t tbl_len = lua_objlen(L, 2); TSRange *ranges = xmalloc(sizeof(TSRange) * tbl_len); - // [ parser, ranges ] for (size_t index = 0; index < tbl_len; index++) { lua_rawgeti(L, 2, index + 1); // [ parser, ranges, range ] @@ -558,7 +557,6 @@ static int parser_get_ranges(lua_State *L) return 1; } - // Tree methods /// push tree interface on lua stack. @@ -656,7 +654,6 @@ static bool node_check(lua_State *L, int index, TSNode *res) return false; } - static int node_tostring(lua_State *L) { TSNode node; @@ -1059,7 +1056,6 @@ static int query_next_match(lua_State *L) return 0; } - static int query_next_capture(lua_State *L) { // Upvalues are: @@ -1205,7 +1201,6 @@ int tslua_parse_query(lua_State *L) return 1; } - static const char *query_err_string(TSQueryError err) { switch (err) { diff --git a/src/nvim/macros.h b/src/nvim/macros.h index c9c424568d..a896a406d1 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -94,7 +94,6 @@ #define REPLACE_NORMAL(s) (((s) & REPLACE_FLAG) && !((s) & VREPLACE_FLAG)) - // MB_PTR_ADV(): advance a pointer to the next character, taking care of // multi-byte characters if needed. Skip over composing chars. #define MB_PTR_ADV(p) (p += utfc_ptr2len((char *)p)) diff --git a/src/nvim/main.c b/src/nvim/main.c index 80a856e91a..936b42be23 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"); @@ -815,7 +810,6 @@ static void init_locale(void) } #endif - static uint64_t server_connect(char *server_addr, const char **errmsg) { if (server_addr == NULL) { @@ -922,7 +916,6 @@ static void remote_request(mparm_T *params, int remote_args, char *server_addr, } } - /// Decides whether text (as opposed to commands) will be read from stdin. /// @see EDIT_STDIN static bool edit_stdin(bool explicit, mparm_T *parmp) @@ -1498,7 +1491,6 @@ static void set_window_layout(mparm_T *paramp) } } - /* * "-q errorfile": Load the error file now. * If the error file can't be read, exit before doing anything else. @@ -2180,7 +2172,6 @@ static void usage(void) mch_msg(_("\nSee \":help startup-options\" for all options.\n")); } - /* * Check the result of the ATTENTION dialog: * When "Quit" selected, exit Vim. diff --git a/src/nvim/map.c b/src/nvim/map.c index b3f48ad5d6..05ad113008 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -32,13 +32,12 @@ #define handle_T_hash kh_int_hash_func #define handle_T_eq kh_int_hash_equal - #if defined(ARCH_64) -# define ptr_t_hash(key) uint64_t_hash((uint64_t)key) -# define ptr_t_eq(a, b) uint64_t_eq((uint64_t)a, (uint64_t)b) +# define ptr_t_hash(key) uint64_t_hash((uint64_t)(key)) +# define ptr_t_eq(a, b) uint64_t_eq((uint64_t)(a), (uint64_t)(b)) #elif defined(ARCH_32) -# define ptr_t_hash(key) uint32_t_hash((uint32_t)key) -# define ptr_t_eq(a, b) uint32_t_eq((uint32_t)a, (uint32_t)b) +# define ptr_t_hash(key) uint32_t_hash((uint32_t)(key)) +# define ptr_t_eq(a, b) uint32_t_eq((uint32_t)(a), (uint32_t)(b)) #endif #define INITIALIZER(T, U) T##_##U##_initializer @@ -163,7 +162,6 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2) return memcmp(&ae1, &ae2, sizeof(ae1)) == 0; } - MAP_IMPL(int, int, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER) diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 6de8d5dfd5..35000ce39a 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1016,7 +1016,6 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, long amount, lo ONE_ADJUST(&(curbuf->b_last_cursor.mark.lnum)); } - // list of change positions for (i = 0; i < curbuf->b_changelistlen; i++) { ONE_ADJUST_NODEL(&(curbuf->b_changelist[i].mark.lnum)); @@ -1586,7 +1585,6 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) } } - // Add information about mark 'mname' to list 'l' static int add_mark(list_T *l, const char *mname, const pos_T *pos, int bufnr, const char *fname) FUNC_ATTR_NONNULL_ARG(1, 2, 3) @@ -1614,7 +1612,6 @@ static int add_mark(list_T *l, const char *mname, const pos_T *pos, int bufnr, c return OK; } - /// Get information about marks local to a buffer. /// /// @param[in] buf Buffer to get the marks from diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index fb2fa6bc7d..03340a99d6 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -58,7 +58,7 @@ #define ID_INCR (((uint64_t)1) << 2) -#define rawkey(itr) (itr->node->key[itr->i]) +#define rawkey(itr) ((itr)->node->key[(itr)->i]) static bool pos_leq(mtpos_t a, mtpos_t b) { @@ -575,7 +575,6 @@ void marktree_move(MarkTree *b, MarkTreeIter *itr, int row, int col) marktree_del_itr(b, itr, false); key.pos = (mtpos_t){ row, col }; - marktree_put_key(b, key); itr->node = NULL; // itr might become invalid by put } @@ -799,7 +798,6 @@ bool marktree_itr_node_done(MarkTreeIter *itr) return !itr->node || itr->i == itr->node->n - 1; } - mtpos_t marktree_itr_pos(MarkTreeIter *itr) { mtpos_t pos = rawkey(itr).pos; @@ -961,7 +959,6 @@ past_continue_same_node: } } - while (itr->node) { unrelative(oldbase[itr->lvl], &rawkey(itr).pos); int realrow = rawkey(itr).pos.row; diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h index 5b3171d9aa..e2e05eebd5 100644 --- a/src/nvim/marktree.h +++ b/src/nvim/marktree.h @@ -32,7 +32,6 @@ typedef struct { iterstate_t s[MT_MAX_DEPTH]; } MarkTreeIter; - // Internal storage // // NB: actual marks have flags > 0, so we can use (row,col,0) pseudo-key for @@ -109,7 +108,6 @@ static inline uint16_t mt_flags(bool right_gravity, uint8_t decor_level) | (decor_level << MT_FLAG_DECOR_OFFSET)); } - struct mtnode_s { int32_t n; int32_t level; @@ -130,7 +128,6 @@ typedef struct { PMap(uint64_t) id2node[1]; } MarkTree; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "marktree.h.generated.h" #endif diff --git a/src/nvim/math.c b/src/nvim/math.c index 63a29509bd..b427688083 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> @@ -29,10 +31,12 @@ int xfpclassify(double d) return m ? FP_NAN : FP_INFINITE; } } + int xisinf(double d) { return FP_INFINITE == xfpclassify(d); } + int xisnan(double d) { return FP_NAN == xfpclassify(d); diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 3868d65ab9..24d079ea2c 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -344,7 +344,6 @@ static int enc_canon_search(const char_u *name) return -1; } - /* * Find canonical encoding "name" in the list and return its properties. * Returns 0 if not found. @@ -473,27 +472,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 +1045,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 +1055,6 @@ bool utf_printable(int c) }; return !intable(nonprint, ARRAY_SIZE(nonprint), c); -#endif } /* @@ -1547,7 +1524,6 @@ ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len, size_t index, bool us return -1; } - /* * Version of strnicmp() that handles multi-byte characters. * Needed for Big5, Shift-JIS and UTF-8 encoding. Other DBCS encodings can @@ -1889,7 +1865,6 @@ int mb_tail_off(const char_u *base, const char_u *p) return i; } - /// Return the offset from "p" to the first byte of the character it points /// into. Can start anywhere in a stream of bytes. /// Unlike utf_head_off() this doesn't include composing characters and returns a negative value. @@ -2151,7 +2126,6 @@ const char *mb_unescape(const char **const pp) return NULL; } - /* * Skip the Vim specific head of a 'encoding' name. */ @@ -2247,7 +2221,6 @@ static int enc_alias_search(const char_u *name) return -1; } - #ifdef HAVE_LANGINFO_H # include <langinfo.h> #endif @@ -2321,7 +2294,6 @@ enc_locale_copy_enc: #if defined(HAVE_ICONV) - /* * Call iconv_open() with a check if iconv() works properly (there are broken * versions). @@ -2451,7 +2423,6 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen #endif // HAVE_ICONV - /* * Setup "vcp" for conversion from "from" to "to". * The names must have been made canonical with enc_canonize(). diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 28337803ac..c828334eaf 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -60,7 +60,6 @@ #define MEMFILE_PAGE_SIZE 4096 /// default page size - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "memfile.c.generated.h" #endif diff --git a/src/nvim/memline.c b/src/nvim/memline.c index ac6bdfa1a4..81d89ef3df 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -288,7 +288,6 @@ int ml_open(buf_T *buf) buf->b_ml.ml_line_count = 1; curwin->w_nrwidth_line_count = 0; - /* * fill block0 struct and write page 0 */ @@ -732,7 +731,6 @@ static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf) } } - /// Try to recover curbuf from the .swp file. /// /// @param checkext if true, check the extension and detect whether it is a @@ -2445,7 +2443,6 @@ void ml_add_deleted_len_buf(buf_T *buf, char_u *ptr, ssize_t len) } } - int ml_replace(linenr_T lnum, char *line, bool copy) { return ml_replace_buf(curbuf, lnum, (char_u *)line, copy); @@ -3304,7 +3301,6 @@ char_u *get_file_in_dir(char_u *fname, char_u *dname) return retval; } - /// Print the ATTENTION message: info about an existing swap file. /// /// @param buf buffer being edited @@ -3351,7 +3347,6 @@ static void attention_message(buf_T *buf, char_u *fname) --no_wait_return; } - /// Trigger the SwapExists autocommands. /// /// @return a value for equivalent to do_dialog() (see below): diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 8a65188f22..19a520636e 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -661,7 +661,6 @@ void free_all_mem(void) ResetRedobuff(); ResetRedobuff(); - // highlight info free_highlight(); diff --git a/src/nvim/menu.c b/src/nvim/menu.c index c1ce2eefe3..01a44224e8 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -31,12 +31,10 @@ #define MENUDEPTH 10 // maximum depth of menus - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "menu.c.generated.h" #endif - /// The character for each menu mode static char menu_mode_chars[] = { 'n', 'v', 's', 'o', 'i', 'c', 't' }; @@ -98,7 +96,6 @@ void ex_menu(exarg_T *eap) break; } - // Locate an optional "icon=filename" argument // TODO(nvim): Currently this is only parsed. Should expose it to UIs. if (STRNCMP(arg, "icon=", 5) == 0) { @@ -162,7 +159,6 @@ void ex_menu(exarg_T *eap) return; } - menu_path = arg; if (*menu_path == '.') { semsg(_(e_invarg2), menu_path); @@ -268,7 +264,6 @@ theend: ; } - /// Add the menu with the given name to the menu hierarchy /// /// @param[out] menuarg menu entry @@ -398,7 +393,6 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const } } - menup = &menu->children; parent = menu; name = next_name; @@ -543,7 +537,6 @@ static int menu_enable_recurse(vimmenu_T *menu, char *name, int modes, int enabl return FAIL; } - return OK; } @@ -615,7 +608,6 @@ static int remove_menu(vimmenu_T **menup, char *name, int modes, bool silent) return FAIL; } - // Recalculate modes for menu based on the new updated children menu->modes &= ~modes; child = menu->children; @@ -645,7 +637,6 @@ static void free_menu(vimmenu_T **menup) menu = *menup; - // Don't change *menup until after calling gui_mch_destroy_menu(). The // MacOS code needs the original structure to properly delete the menu. *menup = menu->next; @@ -749,7 +740,6 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes) return dict; } - /// Export menus matching path \p path_name /// /// @param path_name @@ -776,7 +766,6 @@ bool menu_get(char *const path_name, int modes, list_T *list) return true; } - /// Find menu matching `name` and `modes`. /// /// @param menu top menu to start looking from @@ -913,7 +902,6 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) } } - /* * Used when expanding menu names. */ @@ -937,7 +925,6 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for xp->xp_context = EXPAND_UNSUCCESSFUL; - // Check for priority numbers, enable and disable for (p = arg; *p; ++p) { if (!ascii_isdigit(*p) && *p != '.') { @@ -1146,7 +1133,6 @@ char *get_menu_names(expand_T *xp, int idx) return str; } - /// Skip over this element of the menu path and return the start of the next /// element. Any \ and ^Vs are removed from the current element. /// @@ -1197,7 +1183,6 @@ static bool menu_namecmp(const char *const name, const char *const mname) && (mname[i] == NUL || mname[i] == TAB); } - /// Returns the \ref MENU_MODES specified by menu command `cmd`. /// (eg :menu! returns MENU_CMDLINE_MODE | MENU_INSERT_MODE) /// @@ -1281,7 +1266,6 @@ static char *popup_mode_name(char *name, int idx) return p; } - /// Duplicate the menu item text and then process to see if a mnemonic key /// and/or accelerator text has been identified. /// @@ -1346,7 +1330,6 @@ bool menu_is_popup(const char *const name) return STRNCMP(name, "PopUp", 5) == 0; } - // Return true if "name" is a toolbar menu name. bool menu_is_toolbar(const char *const name) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL @@ -1363,7 +1346,6 @@ int menu_is_separator(char *name) return name[0] == '-' && name[STRLEN(name) - 1] == '-'; } - /// True if a popup menu or starts with \ref MNU_HIDDEN_CHAR /// /// @return true if the menu is hidden diff --git a/src/nvim/message.c b/src/nvim/message.c index 9ab086f1ea..2e57d11fb6 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -114,7 +114,6 @@ bool keep_msg_more = false; // keep_msg was set by msgmore() * This is an allocated string or NULL when not used. */ - // Extended msg state, currently used for external UIs with ext_messages static const char *msg_ext_kind = NULL; static Array msg_ext_chunks = ARRAY_DICT_INIT; @@ -125,6 +124,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 +163,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 +175,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; @@ -263,7 +264,6 @@ void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clea } } - /// @param keep set keep_msg if it doesn't scroll bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) FUNC_ATTR_NONNULL_ALL @@ -758,7 +758,6 @@ bool semsg_multiline(const char *const fmt, ...) bool ret; va_list ap; - static char errbuf[MULTILINE_BUFSIZE]; if (emsg_not_now()) { return true; @@ -1008,7 +1007,6 @@ void ex_messages(void *const eap_p) return; } - p = first_msg_hist; if (eap->addr_count != 0) { @@ -1025,6 +1023,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 +1041,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) { @@ -1161,7 +1164,6 @@ void wait_return(int redraw) reg_recording = save_reg_recording; scriptout = save_scriptout; - /* * Allow scrolling back in the messages. * Also accept scroll-down commands when messages fill the screen, @@ -1336,7 +1338,6 @@ void msgmore(long n) } } - void msg_ext_set_kind(const char *msg_kind) { // Don't change the label of an existing batch: @@ -2320,10 +2321,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 +2357,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 +2375,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 +2401,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 { @@ -2735,7 +2736,6 @@ static int do_more_prompt(int typed_char) c = get_keystroke(resize_events); } - toscroll = 0; switch (c) { case BS: // scroll one line back @@ -3126,6 +3126,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; @@ -3429,7 +3433,6 @@ int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfl return dfltbutton; // return default option } - int save_msg_silent = msg_silent; int oldState = State; @@ -3496,7 +3499,6 @@ int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfl return retval; } - /// Copy one character from "*from" to "*to", taking care of multi-byte /// characters. Return the length of the character in bytes. /// @@ -3567,7 +3569,6 @@ static char_u *console_dialog_alloc(const char_u *message, char_u *buttons, bool len += 2; // "x" -> "[x]" } - // Now allocate space for the strings xfree(confirm_msg); confirm_msg = xmalloc(len); diff --git a/src/nvim/message.h b/src/nvim/message.h index 316b2df7a4..b402ee8b60 100644 --- a/src/nvim/message.h +++ b/src/nvim/message.h @@ -69,7 +69,6 @@ EXTERN ScreenGrid msg_grid_adj INIT(= SCREEN_GRID_INIT); // value of msg_scrolled at latest msg_scroll_flush. EXTERN int msg_scrolled_at_flush INIT(= 0); - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "message.h.generated.h" #endif diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 8038ba2cad..fc5ecbc6a0 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. @@ -468,7 +480,6 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp) return NULL; } - frame_T *fp; fp = topframe; @@ -497,6 +508,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 +524,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) { @@ -560,7 +572,6 @@ void setmouse(void) ui_check_mouse(); } - // Set orig_topline. Used when jumping to another window, so that a double // click still works. void set_mouse_topline(win_T *wp) @@ -784,8 +795,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/mouse.h b/src/nvim/mouse.h index 04acb88bb3..08261e4a30 100644 --- a/src/nvim/mouse.h +++ b/src/nvim/mouse.h @@ -41,7 +41,6 @@ #define MSCR_LEFT (-1) #define MSCR_RIGHT (-2) - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mouse.h.generated.h" #endif diff --git a/src/nvim/move.c b/src/nvim/move.c index 11feb497ea..9f72b36638 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -45,7 +45,6 @@ typedef struct { # include "move.c.generated.h" #endif - /* * Compute wp->w_botline for the current wp->w_topline. Can be called after * wp->w_topline changed. @@ -1016,7 +1015,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 +1026,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; @@ -1863,7 +1862,6 @@ void cursor_correct(void) curwin->w_viewport_invalid = true; } - /* * move screen 'count' pages up or down and update screen * diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 48ecd5d0ea..79ecd9f827 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -49,7 +49,6 @@ void rpc_init(void) msgpack_sbuffer_init(&out_buffer); } - void rpc_start(Channel *channel) { channel_incref(channel); @@ -73,7 +72,6 @@ void rpc_start(Channel *channel) } } - static Channel *find_rpc_channel(uint64_t id) { Channel *chan = find_channel(id); @@ -359,7 +357,6 @@ static void handle_request(Channel *channel, msgpack_object *request) } } - /// Handles a message, depending on the type: /// - Request: invokes method and writes the response (or error). /// - Notification: invokes method (emits `nvim_error_event` on error). @@ -413,7 +410,6 @@ static bool channel_write(Channel *channel, WBuffer *buffer) success = wstream_write(in, buffer); } - if (!success) { // If the write failed for any reason, close the channel char buf[256]; @@ -535,7 +531,6 @@ static void unsubscribe(Channel *channel, char *event) xfree(event_string); } - /// Mark rpc state as closed, and release its reference to the channel. /// Don't call this directly, call channel_close(id, kChannelPartRpc, &error) void rpc_close(Channel *channel) diff --git a/src/nvim/msgpack_rpc/channel.h b/src/nvim/msgpack_rpc/channel.h index eb0de47437..ac7911bb2c 100644 --- a/src/nvim/msgpack_rpc/channel.h +++ b/src/nvim/msgpack_rpc/channel.h @@ -17,7 +17,6 @@ /// of os_inchar(), so they are processed "just-in-time". EXTERN MultiQueue *ch_before_blocking_events INIT(= NULL); - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "msgpack_rpc/channel.h.generated.h" #endif diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c index 32014fcf2b..488321be42 100644 --- a/src/nvim/msgpack_rpc/helpers.c +++ b/src/nvim/msgpack_rpc/helpers.c @@ -22,7 +22,6 @@ static msgpack_zone zone; static msgpack_sbuffer sbuffer; - void msgpack_rpc_helpers_init(void) { msgpack_zone_init(&zone, 0xfff); @@ -252,7 +251,6 @@ bool msgpack_rpc_to_dictionary(const msgpack_object *const obj, Dictionary *cons arg->size = obj->via.array.size; arg->items = xcalloc(obj->via.map.size, sizeof(KeyValuePair)); - for (uint32_t i = 0; i < obj->via.map.size; i++) { if (!msgpack_rpc_to_string(&obj->via.map.ptr[i].key, &arg->items[i].key)) { diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 2826b7dad1..d806741175 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" @@ -85,7 +86,6 @@ typedef struct normal_state { static int VIsual_mode_orig = NUL; // saved Visual mode - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "normal.c.generated.h" #endif @@ -431,15 +431,15 @@ static int find_command(int cmdchar) return idx; } -// Normal state entry point. This is called on: -// -// - Startup, In this case the function never returns. -// - The command-line window is opened(`q:`). Returns when `cmdwin_result` != 0. -// - The :visual command is called from :global in ex mode, `:global/PAT/visual` -// for example. Returns when re-entering ex mode(because ex mode recursion is -// not allowed) -// -// This used to be called main_loop on main.c +/// Normal state entry point. This is called on: +/// +/// - Startup, In this case the function never returns. +/// - The command-line window is opened(`q:`). Returns when `cmdwin_result` != 0. +/// - The :visual command is called from :global in ex mode, `:global/PAT/visual` +/// for example. Returns when re-entering ex mode(because ex mode recursion is +/// not allowed) +/// +/// This used to be called main_loop on main.c void normal_enter(bool cmdwin, bool noexmode) { NormalState state; @@ -1126,9 +1126,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 +1175,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 +1269,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) { @@ -1325,11 +1315,12 @@ static void normal_redraw(NormalState *s) setcursor(); } -// Function executed before each iteration of normal mode. -// Return: -// 1 if the iteration should continue normally -// -1 if the iteration should be skipped -// 0 if the main loop must exit +/// Function executed before each iteration of normal mode. +/// +/// @return: +/// 1 if the iteration should continue normally +/// -1 if the iteration should be skipped +/// 0 if the main loop must exit static int normal_check(VimState *state) { NormalState *s = (NormalState *)state; @@ -1428,8 +1419,8 @@ static void set_vcount_ca(cmdarg_T *cap, bool *set_prevcount) *set_prevcount = false; // only set v:prevcount once } -// Move the current tab to tab in same column as mouse or to end of the -// tabline if there is no tab there. +/// Move the current tab to tab in same column as mouse or to end of the +/// tabline if there is no tab there. static void move_tab_to_mouse(void) { int tabnr = tab_page_click_defs[mouse_col].tabnr; @@ -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 @@ -1556,7 +1605,6 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) } } - // CTRL right mouse button does CTRL-T if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT) { if (State & MODE_INSERT) { @@ -1721,66 +1769,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) { @@ -1788,7 +1780,6 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) return false; } - // When 'mousemodel' is "popup" or "popup_setpos", translate mouse events: // right button up -> pop-up menu // shift-left button -> right button @@ -1851,9 +1842,41 @@ 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); + if (wp == NULL) { + return false; + } + + 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. @@ -1877,7 +1900,6 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) } } - // Set global flag that we are extending the Visual area with mouse dragging; // temporarily minimize 'scrolloff'. if (VIsual_active && is_drag && get_scrolloff_value(curwin)) { @@ -2250,12 +2272,14 @@ void restore_visual_mode(void) } } -// Check for a balloon-eval special item to include when searching for an -// identifier. When "dir" is BACKWARD "ptr[-1]" must be valid! -// Returns true if the character at "*ptr" should be included. -// "dir" is FORWARD or BACKWARD, the direction of searching. -// "*colp" is in/decremented if "ptr[-dir]" should also be included. -// "bnp" points to a counter for square brackets. +/// Check for a balloon-eval special item to include when searching for an +/// identifier. When "dir" is BACKWARD "ptr[-1]" must be valid! +/// +/// @return true if the character at "*ptr" should be included. +/// +/// @param dir the direction of searching, is either FORWARD or BACKWARD +/// @param *colp is in/decremented if "ptr[-dir]" should also be included. +/// @param bnp points to a counter for square brackets. static bool find_is_eval_item(const char_u *const ptr, int *const colp, int *const bnp, const int dir) { @@ -2284,25 +2308,26 @@ static bool find_is_eval_item(const char_u *const ptr, int *const colp, int *con return false; } -// Find the identifier under or to the right of the cursor. -// "find_type" can have one of three values: -// FIND_IDENT: find an identifier (keyword) -// FIND_STRING: find any non-white text -// FIND_IDENT + FIND_STRING: find any non-white text, identifier preferred. -// FIND_EVAL: find text useful for C program debugging -// -// There are three steps: -// 1. Search forward for the start of an identifier/text. Doesn't move if -// already on one. -// 2. Search backward for the start of this identifier/text. -// This doesn't match the real Vi but I like it a little better and it -// shouldn't bother anyone. -// 3. Search forward to the end of this identifier/text. -// When FIND_IDENT isn't defined, we backup until a blank. -// -// Returns the length of the text, or zero if no text is found. -// If text is found, a pointer to the text is put in "*text". This -// points into the current buffer line and is not always NUL terminated. +/// Find the identifier under or to the right of the cursor. +/// "find_type" can have one of three values: +/// FIND_IDENT: find an identifier (keyword) +/// FIND_STRING: find any non-white text +/// FIND_IDENT + FIND_STRING: find any non-white text, identifier preferred. +/// FIND_EVAL: find text useful for C program debugging +/// +/// There are three steps: +/// 1. Search forward for the start of an identifier/text. Doesn't move if +/// already on one. +/// 2. Search backward for the start of this identifier/text. +/// This doesn't match the real Vi but I like it a little better and it +/// shouldn't bother anyone. +/// 3. Search forward to the end of this identifier/text. +/// When FIND_IDENT isn't defined, we backup until a blank. +/// +/// @return the length of the text, or zero if no text is found. +/// +/// If text is found, a pointer to the text is put in "*text". This +/// points into the current buffer line and is not always NUL terminated. size_t find_ident_under_cursor(char_u **text, int find_type) FUNC_ATTR_NONNULL_ARG(1) { @@ -2531,7 +2556,6 @@ static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; // For push_showcmd() static bool showcmd_is_clear = true; static bool showcmd_visual = false; - void clear_showcmd(void) { if (!p_sc) { @@ -3791,7 +3815,6 @@ dozet: } break; - case 'u': // "zug" and "zuw": undo "zg" and "zw" no_mapping++; allow_keys++; // no mapping for nchar, but allow key codes @@ -3878,7 +3901,6 @@ dozet: } } - /// "Q" command. static void nv_regreplay(cmdarg_T *cap) { @@ -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); @@ -4009,8 +4019,8 @@ static void nv_ctrlo(cmdarg_T *cap) } } -// CTRL-^ command, short for ":e #". Works even when the alternate buffer is -// not named. +/// CTRL-^ command, short for ":e #". Works even when the alternate buffer is +/// not named. static void nv_hat(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) { @@ -5435,7 +5445,6 @@ static void n_swapchar(cmdarg_T *cap) } } - check_cursor(); curwin->w_set_curswant = true; if (did_change) { @@ -5792,7 +5801,6 @@ static void n_start_visual_mode(int c) } } - /// CTRL-W: Window commands static void nv_window(cmdarg_T *cap) { @@ -6365,7 +6373,7 @@ static void nv_dot(cmdarg_T *cap) } } -// CTRL-R: undo undo or specify register in select mode +/// CTRL-R: undo undo or specify register in select mode static void nv_redo_or_register(cmdarg_T *cap) { if (VIsual_select && VIsual_active) { @@ -6682,7 +6690,6 @@ static void nv_select(cmdarg_T *cap) } } - /// "G", "gg", CTRL-END, CTRL-HOME. /// cap->arg is true for "G". static void nv_goto(cmdarg_T *cap) @@ -6729,10 +6736,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 +6750,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 +6767,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,16 +6791,9 @@ 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. +/// Move the cursor for the "A" command. void set_cursor_for_append_to_line(void) { curwin->w_set_curswant = true; @@ -6831,8 +6825,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)) { @@ -7063,8 +7056,9 @@ static void nv_put(cmdarg_T *cap) nv_put_opt(cap, false); } -// "P", "gP", "p" and "gp" commands. -// "fix_indent" is true for "[p", "[P", "]p" and "]P". +/// "P", "gP", "p" and "gp" commands. +/// +/// @param fix_indent true for "[p", "[P", "]p" and "]P". static void nv_put_opt(cmdarg_T *cap, bool fix_indent) { int regname = 0; @@ -7214,7 +7208,7 @@ static void nv_open(cmdarg_T *cap) } } -// Handle an arbitrary event in normal mode +/// Handle an arbitrary event in normal mode static void nv_event(cmdarg_T *cap) { // Garbage collection should have been executed before blocking for events in @@ -7237,7 +7231,7 @@ static void nv_event(cmdarg_T *cap) } } -/// @return true when 'mousemodel' is set to "popup" or "popup_setpos". +/// @return true when 'mousemodel' is set to "popup" or "popup_setpos". static bool mouse_model_popup(void) { return p_mousem[0] == 'p'; diff --git a/src/nvim/normal.h b/src/nvim/normal.h index 0c2b8b4d8a..9bda70eacd 100644 --- a/src/nvim/normal.h +++ b/src/nvim/normal.h @@ -76,7 +76,6 @@ typedef struct cmdarg_S { #define CA_COMMAND_BUSY 1 // skip restarting edit() once #define CA_NO_ADJ_OP_END 2 // don't adjust operator end - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "normal.h.generated.h" #endif diff --git a/src/nvim/ops.c b/src/nvim/ops.c index c3d7742307..6e6f478166 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -453,7 +453,6 @@ static void shift_block(oparg_T *oap, int amount) non_white_col += incr; } - const colnr_T block_space_width = non_white_col - oap->start_vcol; // We will shift by "total" or "block_space_width", whichever is less. const colnr_T shift_amount = block_space_width < total @@ -2105,7 +2104,6 @@ static int op_replace(oparg_T *oap, int c) return OK; } - /* * Handle the (non-standard vi) tilde operator. Also for "gu", "gU" and "g?". */ @@ -2629,7 +2627,6 @@ void clear_registers(void) #endif - /// Free contents of yankreg `reg`. /// Called for normal freeing and in case of error. /// `reg` must not be NULL (but `reg->y_array` might be) @@ -3699,8 +3696,11 @@ error: len = STRLEN(y_array[y_size - 1]); col = (colnr_T)len - lendiff; if (col > 1) { - curbuf->b_op_end.col = col - 1 - utf_head_off(y_array[y_size - 1], - y_array[y_size - 1] + len - 1); + curbuf->b_op_end.col = col - 1; + if (len > 0) { + curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1], + y_array[y_size - 1] + len - 1); + } } else { curbuf->b_op_end.col = 0; } @@ -3853,7 +3853,6 @@ void ex_display(exarg_T *eap) continue; // did not ask for this register } - if (i == -1) { if (y_previous != NULL) { yb = y_previous; @@ -4911,12 +4910,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 +4933,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 +4980,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); } @@ -5426,7 +5435,6 @@ void format_reg_type(MotionType reg_type, colnr_T reg_width, char *buf, size_t b } } - /// When `flags` has `kGRegList` return a list with text `s`. /// Otherwise just return `s`. /// @@ -5807,7 +5815,6 @@ void clear_oparg(oparg_T *oap) memset(oap, 0, sizeof(oparg_T)); } - /* * Count the number of bytes, characters and "words" in a line. * @@ -6276,7 +6283,6 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) int restart_edit_save; int lbr_saved = curwin->w_p_lbr; - // The visual area is remembered for redo static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V static linenr_T redo_VIsual_line_count; // number of lines @@ -6709,7 +6715,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; @@ -7266,7 +7272,6 @@ void restore_batch_count(int save_count) } } - /// Check whether register is empty static inline bool reg_empty(const yankreg_T *const reg) FUNC_ATTR_PURE diff --git a/src/nvim/option.c b/src/nvim/option.c index 8267bcf9da..5565e6f167 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -101,7 +101,6 @@ #define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x)) #define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x)) - // WV_ and BV_ values get typecasted to this for the "indir" field typedef enum { PV_NONE = 0, @@ -211,7 +210,6 @@ typedef struct vimoption { LastSet last_set; // script in which the option was last set } vimoption_T; - /* * Flags */ @@ -519,7 +517,6 @@ void set_init_1(bool clean_arg) */ set_options_default(0); - curbuf->b_p_initialized = true; curbuf->b_p_ar = -1; // no local 'autoread' value curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL; @@ -778,7 +775,6 @@ void free_all_options(void) } #endif - /// Initialize the options, part two: After getting Rows and Columns. void set_init_2(bool headless) { @@ -909,7 +905,6 @@ void set_helplang_default(const char *lang) } } - /// 'title' and 'icon' only default to true if they have not been set or reset /// in .vimrc and we can read the old value. /// When 'title' and 'icon' have been reset in .vimrc, we won't even check if @@ -2149,6 +2144,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: @@ -2166,7 +2163,6 @@ static uint32_t *insecure_flag(win_T *const wp, int opt_idx, int opt_flags) return &options[opt_idx].flags; } - /// Redraw the window title and/or tab page text later. static void redraw_titles(void) { @@ -2930,8 +2926,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 +2946,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 +3570,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 +3613,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 = '|'; } } @@ -3960,7 +3961,6 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va // Remember where the option was set. set_option_sctx_idx(opt_idx, opt_flags, current_sctx); - // May set global value for local option. if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value; @@ -4042,36 +4042,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); @@ -4215,7 +4188,6 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } } - /* * End of handling side effects for bool options. */ @@ -4585,7 +4557,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, check_blending(curwin); } - // Check the (new) bounds for Rows and Columns here. if (p_lines < min_rows() && full_screen) { if (errbuf != NULL) { @@ -4766,7 +4737,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 +5785,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 +5865,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 +5960,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 +6231,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 +6307,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 +6333,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 +6520,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 +6530,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..9268b1eff6 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -49,7 +49,6 @@ # define DFLT_FFS_VI "" #endif - // Possible values for 'encoding' #define ENC_UCSBOM "ucs-bom" // check for BOM at start of file @@ -334,9 +333,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 +484,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 +555,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 +615,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 +676,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 +894,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/env.c b/src/nvim/os/env.c index c03fd60f03..4bc003bc7f 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -878,7 +878,6 @@ const void *vim_env_iter_rev(const char delim, const char *const val, const void } } - /// @param[out] exe_name should be at least MAXPATHL in size void vim_get_prefix_from_exepath(char *exe_name) { @@ -1155,7 +1154,6 @@ char_u *home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET return dst; } - /// Function given to ExpandGeneric() to obtain an environment variable name. char *get_env_name(expand_T *xp, int idx) { diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 5fcae79a67..68da53c476 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -56,7 +56,6 @@ static const int kLibuvSuccess = 0; static uv_loop_t fs_loop; static uv_mutex_t fs_loop_mutex; - // Initialize the fs module void fs_init(void) { @@ -77,7 +76,6 @@ void fs_loop_unlock(void) uv_mutex_unlock(&fs_loop_mutex); } - /// Changes the current directory to `path`. /// /// @return 0 on success, or negative error code. 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..c47a891c18 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 @@ -223,7 +216,6 @@ void veryfast_breakcheck(void) } } - /// Test whether a file descriptor refers to a terminal. /// /// @param fd File descriptor. @@ -337,7 +329,6 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) return modifiers; } - // Mouse event handling code(Extract row/col if available and detect multiple // clicks) static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, unsigned int bufsize) diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c index 18e2e02b81..20b7f869f1 100644 --- a/src/nvim/os/os_win_console.c +++ b/src/nvim/os/os_win_console.c @@ -9,7 +9,6 @@ # include "os/os_win_console.c.generated.h" #endif - int os_get_conin_fd(void) { const HANDLE conin_handle = CreateFile("CONIN$", diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index d9f4fe9e37..396bf6986a 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -15,7 +15,6 @@ static uv_mutex_t delay_mutex; static uv_cond_t delay_cond; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/time.c.generated.h" #endif diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index 4803be20c3..9fe97dd5e4 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; } @@ -160,7 +160,6 @@ char *os_get_user_directory(const char *name) return NULL; } - #if defined(EXITFREE) void free_users(void) diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index 1398dba0e4..473bf5072c 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -48,7 +48,6 @@ # include <sys/access.h> # endif - // Return a pointer to the ACL of file "fname" in allocated memory. // Return NULL if the ACL is not available for whatever reason. vim_acl_T mch_get_acl(const char_u *fname) diff --git a/src/nvim/path.c b/src/nvim/path.c index fcb91a2783..7f47ce083d 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1107,7 +1107,6 @@ const char *gettail_dir(const char *const fname) return dir_end; } - /// Calls globpath() with 'path' values for the given pattern and stores the /// result in "gap". /// Returns the total number of matches. @@ -1143,7 +1142,6 @@ static int expand_in_path(garray_T *const gap, char_u *const pattern, const int return gap->ga_len; } - /* * Return TRUE if "p" contains what looks like an environment variable. * Allowing for escaping. diff --git a/src/nvim/plines.c b/src/nvim/plines.c index f940598bf8..35f2512ee3 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -45,7 +45,6 @@ int plines_win(win_T *wp, linenr_T lnum, bool winheight) return plines_win_nofill(wp, lnum, winheight) + win_get_fill(wp, lnum); } - /// Return the number of filler lines above "lnum". /// /// @param wp 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..a77463c9ca 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); } @@ -443,7 +443,6 @@ void pum_redraw(void) false, pum_grid.zindex); } - // Never display more than we have if (pum_first > pum_size - pum_height) { pum_first = pum_size - pum_height; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 883de85aee..f8d0d117e2 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -44,7 +44,6 @@ #include "nvim/vim.h" #include "nvim/window.h" - struct dir_stack_T { struct dir_stack_T *next; char *dirname; @@ -251,7 +250,6 @@ static char *e_no_more_items = N_("E553: No more items"); !got_int && (i) <= (qfl)->qf_count && (qfp) != NULL; \ (i)++, (qfp) = (qfp)->qf_next) - // Looking up a buffer can be slow if there are many. Remember the last one // to make this a lot faster if there are multiple matches in the same file. static char *qf_last_bufname = NULL; @@ -466,7 +464,6 @@ static const char *efm_analyze_prefix(const char *efmp, efm_T *efminfo) return efmp; } - // Converts a 'errorformat' string to regular expression pattern static int efm_to_regpat(const char *efm, int len, efm_T *fmt_ptr, char *regpat) FUNC_ATTR_NONNULL_ALL @@ -1107,7 +1104,6 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu } } - // Use the local value of 'errorformat' if it's set. if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) { efm = (char *)buf->b_p_efm; @@ -2213,7 +2209,6 @@ static char *qf_push_dir(char *dirbuf, struct dir_stack_T **stackptr, bool is_fi } } - // pop dirbuf from the directory stack and return previous directory or NULL if // stack is empty static char *qf_pop_dir(struct dir_stack_T **stackptr) @@ -2540,9 +2535,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; } @@ -3081,7 +3074,6 @@ theend: decr_quickfix_busy(); } - // Highlight attributes used for displaying entries from the quickfix list. static int qfFileAttr; static int qfSepAttr; @@ -3286,7 +3278,6 @@ static void qf_range_text(const qfline_T *qfp, char *buf, int bufsize) buf[len] = NUL; } - /// Display information (list number, list size and the title) about a /// quickfix/location list. static void qf_msg(qf_info_T *qi, int which, char *lead) @@ -5071,7 +5062,6 @@ void ex_cbelow(exarg_T *eap) } } - /// Return the autocmd name for the :cfile Ex commands static char *cfile_get_auname(cmdidx_T cmdidx) { @@ -5093,7 +5083,6 @@ static char *cfile_get_auname(cmdidx_T cmdidx) } } - // ":cfile"/":cgetfile"/":caddfile" commands. // ":lfile"/":lgetfile"/":laddfile" commands. void ex_cfile(exarg_T *eap) @@ -5203,7 +5192,6 @@ static void vgr_init_regmatch(regmmatch_T *regmatch, char *s) regmatch->rmm_maxcol = 0; } - /// Display a file name when vimgrep is running. static void vgr_display_fname(char *fname) { @@ -5266,7 +5254,6 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid, char *titl return true; } - /// Search for a pattern in all the lines in a buffer and add the matching lines /// to a quickfix list. static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *spat, diff --git a/src/nvim/rbuffer.h b/src/nvim/rbuffer.h index 09d6ba3d34..3ebbc9d82c 100644 --- a/src/nvim/rbuffer.h +++ b/src/nvim/rbuffer.h @@ -50,7 +50,6 @@ rbuffer_space(buf); \ wptr = rbuffer_write_ptr(buf, &wcnt)) - // Iteration #define RBUFFER_EACH(buf, c, i) \ for (size_t i = 0; /* NOLINT(readability/braces) */ \ diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index f0ccd19478..6b8c75e430 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -157,7 +157,6 @@ static char_u *reg_prev_sub = NULL; static char REGEXP_INRANGE[] = "]^-n\\"; static char REGEXP_ABBR[] = "nrtebdoxuU"; - /* * Translate '\x' to its control character, except "\n", which is Magic. */ @@ -376,7 +375,6 @@ typedef struct { int regnpar; } parse_state_T; - static regengine_T bt_regengine; static regengine_T nfa_regengine; @@ -384,7 +382,6 @@ static regengine_T nfa_regengine; # include "regexp.c.generated.h" #endif - // Return true if compiled regular expression "prog" can match a line break. int re_multiline(const regprog_T *prog) FUNC_ATTR_NONNULL_ALL @@ -414,7 +411,6 @@ static int get_equi_class(char_u **pp) return 0; } - /* * Check for a collating element "[.a.]". "pp" points to the '['. * Returns a character. Zero means that no item was recognized. Otherwise @@ -540,7 +536,6 @@ char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp) return p; } - // variables used for parsing static int prevchr_len; // byte length of previous char static int at_start; // True when on the first character @@ -591,7 +586,6 @@ static void restore_parse_state(parse_state_T *ps) regnpar = ps->regnpar; } - /* * Get the next character without advancing. */ @@ -898,7 +892,6 @@ static int64_t getoctchrs(void) return nr; } - /* * read_limits - Read two integers to be taken as a minimum and maximum. * If the first character is '-', then the range is reversed. @@ -1000,7 +993,6 @@ typedef struct { int need_clear_zsubexpr; ///< extmatch subexpressions still need to be ///< cleared - // Internal copy of 'ignorecase'. It is set at each call to vim_regexec(). // Normally it gets the value of "rm_ic" or "rmm_ic", but when the pattern // contains '\c' or '\C' the value is overruled. @@ -1112,7 +1104,6 @@ static int reg_prev_class(void) return -1; } - // Return true if the current rex.input position matches the Visual area. static bool reg_match_visual(void) { @@ -1245,7 +1236,6 @@ static void cleanup_zsubexpr(void) } } - // Advance rex.lnum, rex.line and rex.input to the next line. static void reg_nextline(void) { @@ -1254,7 +1244,6 @@ static void reg_nextline(void) fast_breakcheck(); } - /* * Check whether a backreference matches. * Returns RA_FAIL, RA_NOMATCH or RA_MATCH. @@ -1511,7 +1500,6 @@ static inline char_u *cstrchr(const char_u *const s, const int c) // This stuff below really confuses cc on an SGI -- webb - static fptr_T do_upper(int *d, int c) { *d = mb_toupper(c); @@ -2081,7 +2069,6 @@ exit: return (int)((dst - dest) + 1 - num_escaped); } - /* * Call reg_getline() with the line numbers from the submatch. If a * substitute() was used the reg_maxline and other values have been @@ -2378,7 +2365,6 @@ void vim_regfree(regprog_T *prog) } } - #if defined(EXITFREE) void free_regexp_stuff(void) { diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c index c13c2c6832..03e4d74f14 100644 --- a/src/nvim/regexp_bt.c +++ b/src/nvim/regexp_bt.c @@ -43,7 +43,6 @@ * Named character class support added by Walter Briscoe (1998 Jul 01) */ - /* * The "internal use only" fields in regexp_defs.h are present to pass info from * compile to execute that permits the execute phase to run lots faster on @@ -173,7 +172,6 @@ #define NEWL 18 // Match line-break #define BHPOS 19 // End position for BEHIND or NOBEHIND - // character classes: 20-48 normal, 50-78 include a line-break #define ADD_NL 30 #define FIRST_NL ANY + ADD_NL @@ -252,7 +250,6 @@ #define HASLOOKBH 0x10 // Contains "\@<=" or "\@<!". #define WORST 0 // Worst case. - static int prevchr_len; ///< byte length of previous char static int num_complex_braces; ///< Complex \{...} count static char_u *regcode; ///< Code-emit pointer, or JUST_CALC_SIZE @@ -346,7 +343,6 @@ typedef struct regitem_S { } rs_un; // room for saving rex.input } regitem_T; - // used for STAR, PLUS and BRACE_SIMPLE matching typedef struct regstar_S { int nextb; // next byte @@ -443,7 +439,6 @@ static char_u *reg(int paren, int *flagp); static void regdump(char_u *, bt_regprog_T *); #endif - #ifdef REGEXP_DEBUG static char_u *regprop(char_u *); @@ -454,7 +449,6 @@ static int regnarrate = 0; # include "regexp_bt.c.generated.h" #endif - /* * Setup to parse the regexp. Used once to get the length and once to do it. */ @@ -490,7 +484,6 @@ static bool use_multibytecode(int c) || utf_iscomposing(c)); } - /* * Emit (if appropriate) a byte of code */ @@ -515,7 +508,6 @@ static void regmbc(int c) } } - /* * Produce the bytes for equivalence class "c". * Currently only handles latin1, latin9 and utf-8. @@ -1489,7 +1481,6 @@ static void reg_equi_class(int c) regmbc(c); } - /* * Emit a node. * Return pointer to generated code. @@ -1596,7 +1587,6 @@ static void regoptail(char_u *p, char_u *val) regtail(OPERAND(p), val); } - /* * Insert an operator in front of already-emitted operand * @@ -2877,7 +2867,6 @@ static char_u *reg(int paren, int *flagp) return ret; } - /* * bt_regcomp() - compile a regular expression into internal code for the * traditional back track matcher. @@ -5223,7 +5212,6 @@ static int bt_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col, bool line_l return (int)r; } - /// Matches a regexp against multiple lines. /// "rmp->regprog" is a compiled regexp as returned by vim_regcomp(). /// Uses curbuf for line count and 'iskeyword'. diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index cad5e9df29..d867b5db95 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -2747,7 +2747,6 @@ static int nfa_regpiece(void) break; - default: break; } // end switch @@ -3485,7 +3484,6 @@ static nfa_state_T *alloc_state(int c, nfa_state_T *out, nfa_state_T *out1) * next state for this fragment. */ - /* * Initialize a Frag_T struct and return it. */ @@ -3523,7 +3521,6 @@ static void patch(Ptrlist *l, nfa_state_T *s) } } - /* * Join the two lists l1 and l2, returning the combination. */ @@ -4403,7 +4400,6 @@ static void nfa_postprocess(nfa_regprog_T *prog) #define NFA_PIM_MATCH 2 // pim executed, matches #define NFA_PIM_NOMATCH 3 // pim executed, no match - #ifdef REGEXP_DEBUG static void log_subsexpr(regsubs_T *subs) { @@ -4790,7 +4786,6 @@ static bool match_follows(const nfa_state_T *startstate, int depth) return false; } - /// @param l runtime state list /// @param state state to update /// @param subs pointers to subexpressions @@ -5460,7 +5455,6 @@ retempty: return false; } - /// Check for a match with \z subexpression "subidx". /// /// @param bytelen out: length of match in bytes @@ -5530,7 +5524,6 @@ static bool nfa_re_num_cmp(uintmax_t val, int op, uintmax_t pos) return val == pos; } - /* * Recursively call nfa_regmatch() * "pim" is NULL or contains info about a Postponed Invisible Match (start @@ -5684,7 +5677,6 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T return result; } - /* * Estimate the chance of a match with "state" failing. * empty match: 0 @@ -6035,7 +6027,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm #define ADD_STATE_IF_MATCH(state) \ if (result) { \ - add_state = state->out; \ + add_state = (state)->out; \ add_off = clen; \ } diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 8f81b79aff..9f6d129392 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -57,7 +57,6 @@ void ex_runtime(exarg_T *eap) source_runtime(arg, flags); } - static void source_callback(char *fname, void *cookie) { (void)do_source(fname, false, DOSO_NONE); @@ -160,7 +159,6 @@ int do_in_path(char_u *path, char *name, int flags, DoInRuntimepathCB callback, } } - return did_one ? OK : FAIL; } @@ -202,7 +200,6 @@ void runtime_search_path_unref(RuntimeSearchPath path, int *ref) } } - /// Find the file "name" in all directories in "path" and invoke /// "callback(fname, cookie)". /// "name" can contain wildcards. @@ -524,7 +521,6 @@ RuntimeSearchPath runtime_search_path_build(void) map_put(String, handle_T)(&pack_used, the_entry, 0); } - char *rtp_entry; for (rtp_entry = (char *)p_rtp; *rtp_entry != NUL;) { char *cur_entry = rtp_entry; @@ -612,7 +608,6 @@ void runtime_search_path_validate(void) } } - /// Just like do_in_path_and_pp(), using 'runtimepath' for "path". int do_in_runtimepath(char *name, int flags, DoInRuntimepathCB callback, void *cookie) { @@ -884,7 +879,6 @@ static void add_opt_pack_plugin(char *fname, void *cookie) add_pack_plugin(true, (char_u *)fname, cookie); } - /// Add all packages in the "start" directory to 'runtimepath'. void add_pack_start_dirs(void) { @@ -918,7 +912,6 @@ static void add_pack_start_dir(char *fname, void *cookie) } } - /// Load plugins from all packages in the "start" directory. void load_start_packages(void) { @@ -1049,7 +1042,6 @@ static inline size_t compute_double_env_sep_len(const char *const val, const siz return ret; } - #define NVIM_SIZE (sizeof("nvim") - 1) /// Add directories to a ENV_SEPCHAR-separated array from a colon-separated one /// diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h index 0550a082e9..d83ec00185 100644 --- a/src/nvim/runtime.h +++ b/src/nvim/runtime.h @@ -32,7 +32,6 @@ typedef kvec_t(char *) CharVec; #define DIP_LUA 0x100 // also use ".lua" files #define DIP_DIRFILE 0x200 // find both files and directories - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "runtime.h.generated.h" #endif diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 686516f17b..b0edad7740 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 { @@ -163,7 +160,6 @@ typedef struct { } WinExtmark; static kvec_t(WinExtmark) win_extmark_arr INIT(= KV_INITIAL_VALUE); - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "screen.c.generated.h" #endif @@ -276,21 +272,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 +369,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 +418,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; } } @@ -563,7 +550,6 @@ int update_screen(int type) bool did_one = false; search_hl.rm.regprog = NULL; - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_redr_type == CLEAR && wp->w_floating && wp->w_grid_alloc.chars) { grid_invalidate(&wp->w_grid_alloc); @@ -585,8 +571,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 +585,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) { @@ -623,7 +608,6 @@ int update_screen(int type) decor_providers_invoke_end(&providers, &provider_err); kvi_destroy(providers); - // either cmdline is cleared, not drawn or mode is last drawn cmdline_was_last_drawn = false; return OK; @@ -747,7 +731,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 +740,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 +939,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 +947,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 +966,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 +1020,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 +1036,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 +1061,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 +1259,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 +1312,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 +1417,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 +1429,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 +1467,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 +1481,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 +1513,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 +1528,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 +1547,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 +1565,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 +1619,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 +1662,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); } @@ -1734,7 +1718,6 @@ static void win_update(win_T *wp, DecorProviders *providers) } } - // restore got_int, unless CTRL-C was hit while redrawing if (!got_int) { got_int = save_got_int; @@ -1763,8 +1746,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,13 +1796,12 @@ 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); } - /// Advance **color_cols /// /// @return true when there are columns to draw. @@ -1837,7 +1819,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); @@ -1902,7 +1884,6 @@ done: return cells; } - /// Fills the foldcolumn at "p" for window "wp". /// Only to be called when 'foldcolumn' > 0. /// @@ -2621,7 +2602,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 +2784,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 +2799,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 +2873,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 +2909,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 +3050,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 +3164,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 +3369,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 +3572,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 +3644,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 +3726,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 +3798,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 +3866,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 +3904,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 +3937,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 +3946,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 +3972,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 @@ -4126,7 +4107,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc n_attr = 0; } - if (utf_char2cells(mb_c) > 1) { // Need to fill two screen columns. if (wp->w_p_rl) { @@ -4181,7 +4161,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 +4174,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 +4186,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 +4219,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 +4232,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; } @@ -4511,7 +4491,6 @@ static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_att } } - /* * Mirror text "str" for right-left displaying. * Only works for single-byte characters (e.g., numbers). @@ -4528,42 +4507,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 +4548,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 +5049,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 +5062,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 +5229,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 +5272,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 +5411,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; @@ -5414,7 +5460,6 @@ static void win_redr_border(win_T *wp) schar_T *chars = wp->w_float_config.border_chars; int *attrs = wp->w_float_config.border_attr; - int *adj = wp->w_border_adj; int irow = wp->w_height_inner, icol = wp->w_width_inner; @@ -5462,7 +5507,6 @@ static void win_redr_border(win_T *wp) } } - /* * Prepare for 'hlsearch' highlighting. */ @@ -5487,7 +5531,6 @@ static void end_search_hl(void) } } - /// Check if there should be a delay. Used before clearing or redrawing the /// screen or the command line. void check_for_delay(bool check_msg_scroll) @@ -5504,93 +5547,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 +5574,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 +5615,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 +5646,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 +5674,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 +5760,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); } } @@ -5820,7 +5783,6 @@ void win_scroll_lines(win_T *wp, int row, int line_count) * screen changes, and in the meantime, everything still works. */ - /// insert lines on the screen and move the existing lines down /// 'line_count' is the number of lines to be inserted. /// 'end' is the line after the scrolled part. Normally it is Rows. @@ -5845,7 +5807,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 +5825,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 +5856,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 +5875,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); } } @@ -5922,7 +5884,6 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col, } } - // Show the current mode and ruler. // // If clear_cmdline is true, clear the rest of the cmdline. @@ -6208,10 +6169,9 @@ void draw_tabline(void) return; } - // 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 +6180,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); @@ -6257,7 +6217,6 @@ void draw_tabline(void) wp = tp->tp_firstwin; } - if (tp->tp_topframe == topframe) { attr = win_hl_attr(cwp, HLF_TPS); } @@ -6279,7 +6238,6 @@ void draw_tabline(void) } } - if (modified || wincount > 1) { if (wincount > 1) { vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount); @@ -6474,6 +6432,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 +6477,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 +6715,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 +6739,7 @@ void screen_resize(int width, int height) return; } - recursive = true; + resizing_screen = true; Rows = height; Columns = width; @@ -6797,9 +6756,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 +6817,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..9eda5223f1 100644 --- a/src/nvim/screen.h +++ b/src/nvim/screen.h @@ -30,33 +30,22 @@ 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..3eb8d20ffc 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; @@ -3479,11 +3453,11 @@ int current_block(oparg_T *oap, long count, int include, int what, int other) } } - /* - * In Visual mode, when the resulting area is not bigger than what we - * started with, extend it to the next block, and then exclude again. - */ + // In Visual mode, when the resulting area is not bigger than what we + // started with, extend it to the next block, and then exclude again. + // Don't try to expand the area if the area is empty. if (!lt(start_pos, old_start) && !lt(old_end, curwin->w_cursor) + && !equalpos(start_pos, curwin->w_cursor) && VIsual_active) { curwin->w_cursor = old_start; decl(&curwin->w_cursor); @@ -3533,7 +3507,6 @@ int current_block(oparg_T *oap, long count, int include, int what, int other) return OK; } - /// @param end_tag when true, return true if the cursor is on "</aaa>". /// /// @return true if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". @@ -3951,7 +3924,6 @@ extend: return OK; } - /// Search quote char from string line[col]. /// Quote character escaped by one of the characters in "escape" is not counted /// as a quote. @@ -4270,7 +4242,6 @@ abort_search: return false; } - /// Find next search match under cursor, cursor at end. /// Used while an operator is pending, and in Visual mode. /// diff --git a/src/nvim/shada.c b/src/nvim/shada.c index abb6c68474..2693cb0273 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -512,8 +512,8 @@ static inline void hmll_init(HMLList *const hmll, const size_t size) /// /// @return `for` cycle header (use `HMLL_FORALL(hmll, cur_entry) {body}`). #define HMLL_FORALL(hmll, cur_entry, code) \ - for (HMLListEntry *cur_entry = (hmll)->first; cur_entry != NULL; \ - cur_entry = cur_entry->next) { \ + for (HMLListEntry *(cur_entry) = (hmll)->first; (cur_entry) != NULL; \ + (cur_entry) = (cur_entry)->next) { \ code \ } \ @@ -550,7 +550,6 @@ static inline void hmll_remove(HMLList *const hmll, HMLListEntry *const hmll_ent } } - /// Insert entry to the linked list /// /// @param[out] hmll List to insert to. @@ -1073,13 +1072,13 @@ static inline bool marks_equal(const pos_T a, const pos_T b) entry, fname_cond, free_func, fin_func, \ idxadj_func, afterfree_func) \ do { \ - const int jl_len = (int)jumps_size; \ + const int jl_len = (int)(jumps_size); \ int i; \ for (i = jl_len; i > 0; i--) { \ - const jumps_type jl_entry = jumps[i - 1]; \ - if (jl_entry.timestamp_attr <= entry.timestamp) { \ - if (marks_equal(jl_entry.mark_attr, entry.data.filemark.mark) \ - && fname_cond) { \ + const jumps_type jl_entry = (jumps)[i - 1]; \ + if (jl_entry.timestamp_attr <= (entry).timestamp) { \ + if (marks_equal(jl_entry.mark_attr, (entry).data.filemark.mark) \ + && (fname_cond)) { \ i = -1; \ } \ break; \ @@ -1087,30 +1086,30 @@ static inline bool marks_equal(const pos_T a, const pos_T b) } \ if (i > 0) { \ if (jl_len == JUMPLISTSIZE) { \ - free_func(jumps[0]); \ + free_func((jumps)[0]); \ i--; \ if (i > 0) { \ - memmove(&jumps[0], &jumps[1], sizeof(jumps[1]) * (size_t)i); \ + memmove(&(jumps)[0], &(jumps)[1], sizeof((jumps)[1]) * (size_t)i); \ } \ } else if (i != jl_len) { \ - memmove(&jumps[i + 1], &jumps[i], \ - sizeof(jumps[0]) * (size_t)(jl_len - i)); \ + memmove(&(jumps)[i + 1], &(jumps)[i], \ + sizeof((jumps)[0]) * (size_t)(jl_len - i)); \ } \ } else if (i == 0) { \ if (jl_len == JUMPLISTSIZE) { \ i = -1; \ } else if (jl_len > 0) { \ - memmove(&jumps[1], &jumps[0], sizeof(jumps[0]) * (size_t)jl_len); \ + memmove(&(jumps)[1], &(jumps)[0], sizeof((jumps)[0]) * (size_t)jl_len); \ } \ } \ if (i != -1) { \ - jumps[i] = fin_func(entry); \ + (jumps)[i] = fin_func(entry); \ if (jl_len < JUMPLISTSIZE) { \ - jumps_size++; \ + (jumps_size)++; \ } \ idxadj_func(i); \ } else { \ - shada_free_shada_entry(&entry); \ + shada_free_shada_entry(&(entry)); \ afterfree_func(entry); \ } \ } while (0) @@ -1305,7 +1304,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) } else { #define SDE_TO_XFMARK(entry) fm #define ADJUST_IDX(i) \ - if (curwin->w_jumplistidx >= i \ + if (curwin->w_jumplistidx >= (i) \ && curwin->w_jumplistidx + 1 <= curwin->w_jumplistlen) { \ curwin->w_jumplistidx++; \ } @@ -1548,7 +1547,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntr } \ } while (0) #define CHECK_DEFAULT(entry, attr) \ - (sd_default_values[entry.type].data.attr == entry.data.attr) + (sd_default_values[(entry).type].data.attr == (entry).data.attr) #define ONE_IF_NOT_DEFAULT(entry, attr) \ ((size_t)(!CHECK_DEFAULT(entry, attr))) switch (entry.type) { @@ -1638,7 +1637,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntr do { \ if (!CHECK_DEFAULT(entry, search_pattern.attr)) { \ PACK_STATIC_STR(name); \ - if (sd_default_values[entry.type].data.search_pattern.attr) { \ + if (sd_default_values[(entry).type].data.search_pattern.attr) { \ msgpack_pack_false(spacker); \ } else { \ msgpack_pack_true(spacker); \ @@ -2222,12 +2221,12 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re } else { #define FREE_POSSIBLY_FREED_SHADA_ENTRY(entry) \ do { \ - if (entry.can_free_entry) { \ - shada_free_shada_entry(&entry.data); \ + if ((entry).can_free_entry) { \ + shada_free_shada_entry(&(entry).data); \ } \ } while (0) #define SDE_TO_PFSDE(entry) \ - ((PossiblyFreedShadaEntry) { .can_free_entry = true, .data = entry }) + ((PossiblyFreedShadaEntry) { .can_free_entry = true, .data = (entry) }) #define AFTERFREE_DUMMY(entry) #define DUMMY_IDX_ADJ(i) MERGE_JUMPS(filemarks->changes_size, filemarks->changes, @@ -2815,8 +2814,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef #define PACK_WMS_ARRAY(wms_array) \ do { \ for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \ - if (wms_array[i_].data.type != kSDItemMissing) { \ - if (shada_pack_pfreed_entry(packer, wms_array[i_], max_kbyte) \ + if ((wms_array)[i_].data.type != kSDItemMissing) { \ + if (shada_pack_pfreed_entry(packer, (wms_array)[i_], max_kbyte) \ == kSDWriteFailed) { \ ret = kSDWriteFailed; \ goto shada_write_exit; \ @@ -2836,7 +2835,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef } #define PACK_WMS_ENTRY(wms_entry) \ do { \ - if (wms_entry.data.type != kSDItemMissing) { \ + if ((wms_entry).data.type != kSDItemMissing) { \ if (shada_pack_pfreed_entry(packer, wms_entry, max_kbyte) \ == kSDWriteFailed) { \ ret = kSDWriteFailed; \ @@ -3313,16 +3312,16 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const RERR "Error while reading ShaDa file: " \ entry_name " entry at position %" PRIu64 " " \ error_desc -#define CHECK_KEY(key, expected) ( \ - key.via.str.size == sizeof(expected) - 1 \ - && STRNCMP(key.via.str.ptr, expected, sizeof(expected) - 1) == 0) +#define CHECK_KEY(key, \ + expected) ((key).via.str.size == (sizeof(expected) - 1) \ + && STRNCMP((key).via.str.ptr, expected, (sizeof(expected) - 1)) == 0) #define CLEAR_GA_AND_ERROR_OUT(ga) \ do { \ - ga_clear(&ga); \ + ga_clear(&(ga)); \ goto shada_read_next_item_error; \ } while (0) #define ID(s) s -#define BINDUP(b) xmemdupz(b.ptr, b.size) +#define BINDUP(b) xmemdupz((b).ptr, (b).size) #define TOINT(s) ((int)(s)) #define TOLONG(s) ((long)(s)) #define TOCHAR(s) ((char)(s)) @@ -3335,28 +3334,31 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const semsg(_(READERR(entry_name, error_desc)), initial_fpos); \ CLEAR_GA_AND_ERROR_OUT(ad_ga); \ } \ - tgt = proc(obj.via.attr); \ + (tgt) = proc((obj).via.attr); \ } while (0) #define CHECK_KEY_IS_STR(un, entry_name) \ - if (un.data.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR) { \ + if ((un).data.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR) { \ semsg(_(READERR(entry_name, "has key which is not a string")), \ initial_fpos); \ CLEAR_GA_AND_ERROR_OUT(ad_ga); \ - } else if (un.data.via.map.ptr[i].key.via.str.size == 0) { \ + } else if ((un).data.via.map.ptr[i].key.via.str.size == 0) { \ semsg(_(READERR(entry_name, "has empty key")), initial_fpos); \ CLEAR_GA_AND_ERROR_OUT(ad_ga); \ } -#define CHECKED_KEY(un, entry_name, name, error_desc, tgt, condition, attr, \ - proc) \ - else if (CHECK_KEY( /* NOLINT(readability/braces) */ \ - un.data.via.map.ptr[i].key, name)) { \ - CHECKED_ENTRY(condition, "has " name " key value " error_desc, \ - entry_name, un.data.via.map.ptr[i].val, \ - tgt, attr, proc); \ +#define CHECKED_KEY(un, entry_name, name, error_desc, tgt, condition, attr, proc) \ + else if (CHECK_KEY((un).data.via.map.ptr[i].key, name)) /* NOLINT(readability/braces) */ \ + { \ + CHECKED_ENTRY(condition, \ + "has " name " key value " error_desc, \ + entry_name, \ + (un).data.via.map.ptr[i].val, \ + tgt, \ + attr, \ + proc); \ } #define TYPED_KEY(un, entry_name, name, type_name, tgt, objtype, attr, proc) \ CHECKED_KEY(un, entry_name, name, "which is not " type_name, tgt, \ - un.data.via.map.ptr[i].val.type == MSGPACK_OBJECT_##objtype, \ + (un).data.via.map.ptr[i].val.type == MSGPACK_OBJECT_##objtype, \ attr, proc) #define BOOLEAN_KEY(un, entry_name, name, tgt) \ TYPED_KEY(un, entry_name, name, "a boolean", tgt, BOOLEAN, boolean, ID) @@ -3367,9 +3369,9 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const BIN_CONVERTED) #define INT_KEY(un, entry_name, name, tgt, proc) \ CHECKED_KEY(un, entry_name, name, "which is not an integer", tgt, \ - ((un.data.via.map.ptr[i].val.type \ + (((un).data.via.map.ptr[i].val.type \ == MSGPACK_OBJECT_POSITIVE_INTEGER) \ - || (un.data.via.map.ptr[i].val.type \ + || ((un).data.via.map.ptr[i].val.type \ == MSGPACK_OBJECT_NEGATIVE_INTEGER)), \ i64, proc) #define INTEGER_KEY(un, entry_name, name, tgt) \ @@ -3380,12 +3382,12 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const else { /* NOLINT(readability/braces) */ \ ga_grow(&ad_ga, 1); \ memcpy(((char *)ad_ga.ga_data) + ((size_t)ad_ga.ga_len \ - * sizeof(*un.data.via.map.ptr)), \ - un.data.via.map.ptr + i, \ - sizeof(*un.data.via.map.ptr)); \ + * sizeof(*(un).data.via.map.ptr)), \ + (un).data.via.map.ptr + i, \ + sizeof(*(un).data.via.map.ptr)); \ ad_ga.ga_len++; \ } -#define BIN_CONVERTED(b) (xmemdupz((b.ptr), (b.size))) +#define BIN_CONVERTED(b) (xmemdupz(((b).ptr), ((b).size))) #define SET_ADDITIONAL_DATA(tgt, name) \ do { \ if (ad_ga.ga_len) { \ @@ -3408,7 +3410,7 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const tv_clear(&adtv); \ goto shada_read_next_item_error; \ } \ - tgt = adtv.vval.v_dict; \ + (tgt) = adtv.vval.v_dict; \ } \ ga_clear(&ad_ga); \ } while (0) diff --git a/src/nvim/sign.c b/src/nvim/sign.c index dd6fdf3cd5..f61dd53c2a 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -59,7 +59,6 @@ static char *cmds[] = { #define SIGNCMD_LAST 6 }; - static hashtab_T sg_table; // sign group (signgroup_T) hashtable static int next_sign_id = 1; // next sign id in the global group @@ -361,7 +360,6 @@ static void sign_sort_by_prio_on_line(buf_T *buf, sign_entry_T *sign) } } - /// Add the sign into the signlist. Find the right spot to do it though. /// /// @param buf buffer to store sign in @@ -586,7 +584,6 @@ static linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group) return lnum; } - /// Find the line number of the sign with the requested id in group 'group'. If /// the sign does not exist, return 0 as the line number. This will still let /// the correct file get loaded. diff --git a/src/nvim/sign.h b/src/nvim/sign.h index 6e75a4e62b..c61e5d20ef 100644 --- a/src/nvim/sign.h +++ b/src/nvim/sign.h @@ -8,7 +8,6 @@ #include "nvim/ex_cmds_defs.h" #include "nvim/sign_defs.h" - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "sign.h.generated.h" #endif diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h index 6d28c1849a..e4ece71846 100644 --- a/src/nvim/sign_defs.h +++ b/src/nvim/sign_defs.h @@ -55,5 +55,4 @@ typedef enum { SIGN_TEXT, } SignType; - #endif // NVIM_SIGN_DEFS_H diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 1ba29e3fc1..8f84204481 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -301,7 +301,6 @@ typedef struct { int score; } limitscore_T; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "spell.c.generated.h" #endif @@ -443,7 +442,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] = ' '; } @@ -1303,7 +1302,6 @@ static void find_prefix(matchinf_T *mip, int mode) mip->mi_word); find_word(mip, FIND_PREFIX); - if (len == 0) { break; // no children, word must end here } @@ -2550,7 +2548,6 @@ void spell_reload(void) } } - // Opposite of offset2bytes(). // "pp" points to the bytes and is advanced over it. // Returns the offset. @@ -3138,7 +3135,6 @@ static bool check_need_cap(linenr_T lnum, colnr_T col) return need_cap; } - // ":spellrepall" void ex_spellrepall(exarg_T *eap) { @@ -3523,7 +3519,7 @@ static void spell_suggest_intern(suginfo_T *su, bool interactive) // Free the info put in "*su" by spell_find_suggest(). static void spell_find_cleanup(suginfo_T *su) { -#define FREE_SUG_WORD(sug) xfree(sug->st_word) +#define FREE_SUG_WORD(sug) xfree((sug)->st_word) // Free the suggestions. GA_DEEP_CLEAR(&su->su_ga, suggest_T, FREE_SUG_WORD); GA_DEEP_CLEAR(&su->su_sga, suggest_T, FREE_SUG_WORD); @@ -4937,7 +4933,6 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so } } - // Go one level deeper in the tree. static void go_deeper(trystate_T *stack, int depth, int score_add) { @@ -5834,7 +5829,6 @@ static void check_suggestions(suginfo_T *su, garray_T *gap) } } - // Add a word to be banned. static void add_banned(suginfo_T *su, char_u *word) { @@ -5888,7 +5882,6 @@ static void rescore_one(suginfo_T *su, suggest_T *stp) } } - // Function given to qsort() to sort the suggestions on st_score. // First on "st_score", then "st_altscore" then alphabetically. static int sug_compare(const void *s1, const void *s2) @@ -6069,7 +6062,6 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) bool did_white = false; int wordlen; - // Convert the multi-byte string to a wide-character string. // Remove accents, if wanted. We actually remove all non-word characters. // But keep white space. diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h index 12e44cb7ff..7e85b5bf03 100644 --- a/src/nvim/spell_defs.h +++ b/src/nvim/spell_defs.h @@ -60,7 +60,6 @@ typedef int idx_T; #define WF_PFX_COMPFORBID (WFP_COMPFORBID << 24) // postponed prefix with // COMPOUNDFORBIDFLAG - // flags for <compoptions> #define COMP_CHECKDUP 1 // CHECKCOMPOUNDDUP #define COMP_CHECKREP 2 // CHECKCOMPOUNDREP diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index f8c01bc27f..2b6bb098d1 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -638,7 +638,6 @@ slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool sile goto endFAIL; } - // <SECTIONS>: <section> ... <sectionend> // <section>: <sectionID> <sectionflags> <sectionlen> (section contents) for (;;) { @@ -992,7 +991,6 @@ nextone: } } - // Read a length field from "fd" in "cnt_bytes" bytes. // Allocate memory, read the string into it and add a NUL at the end. // Returns NULL when the count is zero. @@ -3886,7 +3884,6 @@ static char_u *getroom_save(spellinfo_T *spin, char_u *s) return memcpy(getroom(spin, s_size, false), s, s_size); } - // Free the list of allocated sblock_T. static void free_blocks(sblock_T *bl) { @@ -4338,7 +4335,6 @@ static bool node_equal(wordnode_T *n1, wordnode_T *n2) return p1 == NULL && p2 == NULL; } - // Function given to qsort() to sort the REP items on "from" string. static int rep_compare(const void *s1, const void *s2) { @@ -4685,7 +4681,6 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) // end of <SECTIONS> putc(SN_END, fd); // <sectionend> - // <LWORDTREE> <KWORDTREE> <PREFIXTREE> spin->si_memtot = 0; for (unsigned int round = 1; round <= 3; ++round) { @@ -4753,7 +4748,6 @@ static void clear_node(wordnode_T *node) } } - /// Dump a word tree at node "node". /// /// This first writes the list of possible bytes (siblings). Then for each @@ -4872,7 +4866,6 @@ static int put_node(FILE *fd, wordnode_T *node, int idx, int regionmask, bool pr return newindex; } - // ":mkspell [-ascii] outfile infile ..." // ":mkspell [-ascii] addfile" void ex_mkspell(exarg_T *eap) @@ -5260,7 +5253,6 @@ theend: fclose(fd); } - /// Create a Vim spell file from one or more word lists. /// "fnames[0]" is the output file name. /// "fnames[fcount - 1]" is the last input file name. diff --git a/src/nvim/state.c b/src/nvim/state.c index 36789016a9..f6d9b535fc 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -24,7 +24,6 @@ # include "state.c.generated.h" #endif - void state_enter(VimState *s) { for (;;) { @@ -122,7 +121,6 @@ void state_handle_k_event(void) } } - /// Return true if in the current mode we need to use virtual. bool virtual_active(void) { diff --git a/src/nvim/strings.c b/src/nvim/strings.c index c0c942ffd2..5c2721536d 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -146,7 +146,7 @@ char *vim_strnsave_unquoted(const char *const string, const size_t length) FUNC_ATTR_NONNULL_RET { #define ESCAPE_COND(p, inquote, string_end) \ - (*p == '\\' && inquote && p + 1 < string_end && (p[1] == '\\' || p[1] == '"')) + (*(p) == '\\' && (inquote) && (p) + 1 < (string_end) && ((p)[1] == '\\' || (p)[1] == '"')) size_t ret_length = 0; bool inquote = false; const char *const string_end = string + length; @@ -553,7 +553,6 @@ char_u *concat_str(const char_u *restrict str1, const char_u *restrict str2) return dest; } - static const char *const e_printf = N_("E766: Insufficient arguments for printf()"); @@ -634,12 +633,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 +1495,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 +1507,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/syntax.c b/src/nvim/syntax.c index 6744e4445c..47305b6709 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -95,7 +95,6 @@ typedef struct syn_pattern { syn_time_T sp_time; } synpat_T; - typedef struct syn_cluster_S { char_u *scl_name; // syntax cluster name char_u *scl_name_u; // uppercase of scl_name @@ -178,7 +177,6 @@ static char *(spo_name_tab[SPO_COUNT]) = #define SPTYPE_END 3 // match a regexp, end of item #define SPTYPE_SKIP 4 // match a regexp, skip within item - #define SYN_ITEMS(buf) ((synpat_T *)((buf)->b_syn_patterns.ga_data)) #define NONE_IDX (-2) // value of sp_sync_idx for "NONE" @@ -2094,7 +2092,6 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con } } - /* * Check for end of current state (and the states before it) at the * next column. Don't do this for syncing, because we would miss a @@ -2140,7 +2137,6 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con return current_attr; } - /// @return true if we already matched pattern "idx" at the current column. static bool did_match_already(int idx, garray_T *gap) { @@ -3607,7 +3603,6 @@ static void syn_match_msg(void) static int last_matchgroup; - /// List one syntax item, for ":syntax" or "syntax list syntax_name". /// /// @param syncing when true: list syncing items @@ -5694,7 +5689,6 @@ bool syntax_present(win_T *win) || win->w_s->b_keywtab_ic.ht_used > 0; } - static enum { EXP_SUBCMD, // expand ":syn" sub-commands EXP_CASE, // expand ":syn case" arguments @@ -5788,7 +5782,6 @@ char *get_syntax_name(expand_T *xp, int idx) return NULL; } - /// Function called for expression evaluation: get syntax ID at file position. /// /// @param trans remove transparency @@ -5823,7 +5816,6 @@ int get_syntax_info(int *seqnrp) return current_flags; } - /// Get the sequence number of the concealed file position. /// /// @return seqnr if the file position is concealed, 0 otherwise. diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 8a21ec3e5d..73b5bb4058 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -99,7 +99,6 @@ static char *mt_names[MT_COUNT/2] = #define NOTAGFILE 99 // return value for jumpto_tag static char_u *nofile_fname = NULL; // fname for NOTAGFILE error - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "tag.c.generated.h" #endif @@ -603,7 +602,6 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) smsg(_("File \"%s\" does not exist"), nofile_fname); } - ic = (matches[cur_match][0] & MT_IC_OFF); if (type != DT_TAG && type != DT_SELECT && type != DT_JUMP && type != DT_CSCOPE @@ -1064,7 +1062,6 @@ void do_tags(exarg_T *eap) } } - /* * Compare two strings, for length "len", ignoring case the ASCII way. * return 0 for match, < 0 for smaller, > 0 for bigger @@ -1089,7 +1086,6 @@ static int tag_strnicmp(char_u *s1, char_u *s2, size_t len) return 0; // strings match } - /* * Extract info from the tag search pattern "pats->pat". */ @@ -1410,7 +1406,6 @@ int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int int matchoff = 0; int save_emsg_off; - char_u *mfp; garray_T ga_match[MT_COUNT]; // stores matches in sequence hashtab_T ht_match[MT_COUNT]; // stores matches by key @@ -1752,7 +1747,6 @@ line_read_in: } } - /* * When still at the start of the file, check for Emacs tags file * format, and for "not sorted" flag. @@ -2723,7 +2717,6 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) ++RedrawingDisabled; - if (l_g_do_tagpreview != 0) { postponed_split = 0; // don't split again below curwin_save = curwin; // Save current window @@ -3148,7 +3141,6 @@ int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file) return ret; } - /// Add a tag field to the dictionary "dict". /// Return OK or FAIL. /// diff --git a/src/nvim/tag.h b/src/nvim/tag.h index 902fe0c7ba..c8051e1dcc 100644 --- a/src/nvim/tag.h +++ b/src/nvim/tag.h @@ -41,7 +41,6 @@ typedef struct { void *tn_search_ctx; } tagname_T; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "tag.h.generated.h" #endif diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 2d3102707c..e4262c2ca9 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -359,7 +359,6 @@ void terminal_check_size(Terminal *term) vterm_get_size(term->vt, &curheight, &curwidth); uint16_t width = 0, height = 0; - FOR_ALL_TAB_WINDOWS(tp, wp) { if (wp->w_buffer && wp->w_buffer->terminal == term) { const uint16_t win_width = @@ -722,7 +721,6 @@ static int get_rgb(VTermState *state, VTermColor color) return RGB_(color.rgb.red, color.rgb.green, color.rgb.blue); } - void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *term_attrs) { int height, width; @@ -1364,7 +1362,6 @@ end: // }}} // terminal buffer refresh & misc {{{ - static void fetch_row(Terminal *term, int row, int end_col) { int col = 0; @@ -1374,26 +1371,21 @@ static void fetch_row(Terminal *term, int row, int end_col) while (col < end_col) { VTermScreenCell cell; fetch_cell(term, row, col, &cell); - int cell_len = 0; if (cell.chars[0]) { + int cell_len = 0; for (int i = 0; cell.chars[i]; i++) { cell_len += utf_char2bytes((int)cell.chars[i], ptr + cell_len); } - } else { - *ptr = ' '; - cell_len = 1; - } - char c = *ptr; - ptr += cell_len; - if (c != ' ') { - // only increase the line length if the last character is not whitespace + ptr += cell_len; line_len = (size_t)(ptr - term->textbuf); + } else { + *ptr++ = ' '; } col += cell.width; } - // trim trailing whitespace - term->textbuf[line_len] = 0; + // end of line + term->textbuf[line_len] = NUL; } static bool fetch_cell(Terminal *term, int row, int col, VTermScreenCell *cell) 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..4819c4877c 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'], @@ -150,7 +151,7 @@ let s:filename_checks = { \ 'diff': ['file.diff', 'file.rej'], \ 'dircolors': ['.dir_colors', '.dircolors', '/etc/DIR_COLORS', 'any/etc/DIR_COLORS'], \ 'dnsmasq': ['/etc/dnsmasq.conf', '/etc/dnsmasq.d/file', 'any/etc/dnsmasq.conf', 'any/etc/dnsmasq.d/file'], - \ 'dockerfile': ['Containerfile', 'Dockerfile', 'file.Dockerfile', 'Dockerfile.debian', 'Containerfile.something'], + \ 'dockerfile': ['Containerfile', 'Dockerfile', 'dockerfile', 'file.Dockerfile', 'file.dockerfile', 'Dockerfile.debian', 'Containerfile.something'], \ 'dosbatch': ['file.bat'], \ 'dosini': ['.editorconfig', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', '/etc/yum.repos.d/file', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap'], \ 'dot': ['file.dot', 'file.gv'], @@ -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,31 +238,20 @@ 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'], \ 'hog': ['file.hog', 'snort.conf', 'vision.conf'], \ 'hollywood': ['file.hws'], + \ 'hoon': ['file.hoon'], \ '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 +304,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 +330,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,8 +351,10 @@ 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'], + \ 'moonscript': ['file.moon'], \ 'mp': ['file.mp'], \ 'mplayerconf': ['mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'], \ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'], @@ -373,7 +367,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 +385,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 +395,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 +417,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 +436,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 +476,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 +484,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 +526,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 +540,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 +577,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 +601,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 +616,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 +845,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_put.vim b/src/nvim/testdir/test_put.vim index 65232175c6..ffdaa81e0b 100644 --- a/src/nvim/testdir/test_put.vim +++ b/src/nvim/testdir/test_put.vim @@ -203,3 +203,15 @@ func Test_multibyte_op_end_mark() call assert_equal([0, 2, 7, 0], getpos("']")) bwipe! endfunc + +" this was putting a mark before the start of a line +func Test_put_empty_register() + new + norm yy + norm [Pi00ggv)s0 + sil! norm [P + bwipe! +endfunc + + +" vim: shiftwidth=2 sts=2 expandtab 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/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim index 8f8dfdc46d..81f2fea026 100644 --- a/src/nvim/testdir/test_textobjects.vim +++ b/src/nvim/testdir/test_textobjects.vim @@ -42,6 +42,24 @@ func Test_inner_block_with_cpo_M_right_backslash() call CpoM('(red (blue\) green)', 1, ['red (blue\) green', 'blue\', 'red (blue\) green']) endfunc +func Test_inner_block_single_char() + new + call setline(1, "(a)") + + set selection=inclusive + let @" = '' + call assert_nobeep('norm! 0faviby') + call assert_equal('a', @") + + set selection=exclusive + let @" = '' + call assert_nobeep('norm! 0faviby') + call assert_equal('a', @") + + set selection& + bwipe! +endfunc + func Test_quote_selection_selection_exclusive() new call setline(1, "a 'bcde' f") @@ -50,11 +68,11 @@ func Test_quote_selection_selection_exclusive() exe "norm! fdvhi'y" call assert_equal('bcde', @") - let @"='dummy' + let @" = 'dummy' exe "norm! $gevi'y" call assert_equal('bcde', @") - let @"='dummy' + let @" = 'dummy' exe "norm! 0fbhvi'y" call assert_equal('bcde', @") diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index fbbd6f1bc2..c8083cddb1 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -1,7 +1,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/ascii.h" @@ -331,7 +330,6 @@ static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force) return force ? termkey_getkey_force(tk, key) : termkey_getkey(tk, key); } - static void tk_getkeys(TermInput *input, bool force) { TermKeyKey key; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 720abb1cec..6c1c1ade00 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -145,7 +145,6 @@ static bool cursor_style_enabled = false; # include "tui/tui.c.generated.h" #endif - UI *tui_start(void) { UI *ui = xcalloc(1, sizeof(UI)); // Freed by ui_bridge_stop(). @@ -713,7 +712,6 @@ static void update_attrs(UI *ui, int attr_id) } } - data->default_attr = fg == -1 && bg == -1 && !bold && !italic && !has_any_underline && !reverse && !standout && !strikethrough; diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 9e2d1f8e68..b40033296e 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -182,7 +182,6 @@ void ui_event(char *name, Array args) } } - void ui_refresh(void) { if (!ui_active()) { @@ -436,7 +435,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 +452,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); @@ -533,7 +532,6 @@ void ui_flush(void) ui_call_flush(); } - /// Check if 'mouse' is active for the current mode /// /// TODO(bfredl): precompute the State -> active mapping when 'mouse' changes, diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 7cc0bd9eff..1d278010e8 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -74,6 +74,5 @@ struct ui_t { # include "ui_events_call.h.generated.h" #endif - EXTERN MultiQueue *resize_events; #endif // NVIM_UI_H diff --git a/src/nvim/ui_bridge.h b/src/nvim/ui_bridge.h index a62ed15621..c18600a857 100644 --- a/src/nvim/ui_bridge.h +++ b/src/nvim/ui_bridge.h @@ -38,7 +38,6 @@ struct ui_bridge_data { uv_mutex_unlock(&d->mutex); \ } while (0) - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ui_bridge.h.generated.h" #endif diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index f76158ff12..3ce2b80ea9 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++) { @@ -462,7 +462,6 @@ static void compose_debug(Integer startrow, Integer endrow, Integer startcol, In (const sattr_T *)attrbuf); } - if (delay) { debug_delay(endrow - startrow); } @@ -476,12 +475,11 @@ static void debug_delay(Integer lines) os_microdelay(factor * wd * 1000u, true); } - 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 +495,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 +521,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 +579,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/undo.c b/src/nvim/undo.c index 529eef19a3..f496c4199a 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -611,7 +611,6 @@ int u_savecommon(buf_T *buf, linenr_T top, linenr_T bot, linenr_T newbot, int re return OK; } - // magic at start of undofile #define UF_START_MAGIC "Vim\237UnDo\345" #define UF_START_MAGIC_LEN 9 @@ -2472,7 +2471,6 @@ static void u_undoredo(int undo, bool do_buf_event) } // finish Adjusting extmarks - curhead->uh_entry = newlist; curhead->uh_flags = new_flags; if ((old_flags & UH_EMPTYBUF) && buf_is_empty(curbuf)) { diff --git a/src/nvim/version.c b/src/nvim/version.c index 1b520780d1..1c8fdce1eb 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -35,7 +35,6 @@ #endif #define NVIM_VERSION_LONG "NVIM " NVIM_VERSION_MEDIUM - char *Version = VIM_VERSION_SHORT; char *longVersion = NVIM_VERSION_LONG; char *version_buildtype = "Build type: " NVIM_VERSION_BUILD_TYPE; @@ -2194,7 +2193,6 @@ void list_version(void) version_msg("\nRun :checkhealth for more info"); } - /// Show the intro message when not editing a file. void maybe_intro_message(void) { diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 1c05387da3..7e82af2d93 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -10,7 +10,6 @@ #define SYS_OPTWIN_FILE "$VIMRUNTIME/optwin.vim" #define RUNTIME_DIRNAME "runtime" - #include "auto/config.h" #define HAVE_PATHDEF @@ -37,7 +36,6 @@ enum { NUMBUFLEN = 65, }; // special attribute addition: Put message in history #define MSG_HIST 0x1000 - // Values for State // // The lower bits up to 0x80 are used to distinguish normal/visual/op_pending @@ -74,7 +72,6 @@ enum { NUMBUFLEN = 65, }; #define MODE_CONFIRM 0x7000 // ":confirm" prompt #define MODE_CMDPREVIEW 0x8000 // Showing 'inccommand' command "live" preview. - /// Directions. typedef enum { kDirectionNotSet = 0, @@ -103,7 +100,6 @@ typedef enum { #define VAR_TYPE_SPECIAL 7 #define VAR_TYPE_BLOB 10 - // values for xp_context when doing command line completion enum { @@ -164,7 +160,6 @@ enum { EXPAND_LUA, }; - // Minimal size for block 0 of a swap file. // NOTE: This depends on size of struct block0! It's not done with a sizeof(), // because struct block0 is defined in memline.c (Sorry). @@ -173,7 +168,6 @@ enum { #define MIN_SWAP_PAGE_SIZE 1048 #define MAX_SWAP_PAGE_SIZE 50000 - // Boolean constants #ifndef TRUE @@ -186,7 +180,6 @@ enum { #define STATUS_HEIGHT 1 // height of a status line under a window #define QF_WINHEIGHT 10 // default height for quickfix window - // Buffer sizes #ifndef CMDBUFFSIZE @@ -199,7 +192,6 @@ enum { enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() - // Maximum length of key sequence to be mapped. // Must be able to hold an Amiga resize report. @@ -283,7 +275,6 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() (const char *)(y), \ (size_t)(n)) - // Enums need a typecast to be used as array index (for Ultrix). #define HL_ATTR(n) highlight_attr[(int)(n)] 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/viml/parser/parser.c b/src/nvim/viml/parser/parser.c index 8d26d08ea7..a41b750e76 100644 --- a/src/nvim/viml/parser/parser.c +++ b/src/nvim/viml/parser/parser.c @@ -7,7 +7,6 @@ # include "viml/parser/parser.c.generated.h" #endif - void parser_simple_get_line(void *cookie, ParserLine *ret_pline) { ParserLine **plines_p = (ParserLine **)cookie; diff --git a/src/nvim/window.c b/src/nvim/window.c index 2c27a5d6a5..f42ef874ef 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -53,12 +53,10 @@ #include "nvim/vim.h" #include "nvim/window.h" - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "window.c.generated.h" #endif - #define NOWIN ((win_T *)-1) // non-existing window #define ROWS_AVAIL (Rows - p_ch - tabline_height() - global_stl_height()) @@ -515,9 +513,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. @@ -528,7 +531,6 @@ wingotofile: } break; - // CTRL-W g extended commands case 'g': case Ctrl_G: @@ -695,6 +697,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; @@ -767,7 +770,6 @@ void win_config_float(win_T *wp, FloatConfig fconfig) wp->w_float_config.border_hl_ids, sizeof fconfig.border_hl_ids)); - wp->w_float_config = fconfig; bool has_border = wp->w_floating && wp->w_float_config.border; @@ -780,10 +782,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); @@ -1051,7 +1051,6 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) need_status = STATUS_HEIGHT; } - if (flags & WSP_VERT) { int wmw1; int minwidth; @@ -1138,15 +1137,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 +1151,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 +1334,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 +1412,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 +1448,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 +1478,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 @@ -1522,7 +1515,6 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) return OK; } - /* * Initialize window "newp" from window "oldp". * Used when splitting a window and when creating a new tab page. @@ -1675,10 +1667,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 +1679,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 +1697,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 @@ -1762,7 +1750,6 @@ static void win_exchange(long Prenum) return; } - /* * find window to exchange with */ @@ -1790,7 +1777,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 +1884,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 +1975,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 +2026,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 +2256,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 +2290,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 +2335,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 +3749,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 +3759,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) { @@ -3821,7 +3836,6 @@ static int frame_minwidth(frame_T *topfrp, win_T *next_curwin) return m; } - /// Try to close all windows except current one. /// Buffers in the other windows become hidden if 'hidden' is set, or '!' is /// used and the buffer was modified. @@ -3976,7 +3990,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 +4101,7 @@ int win_new_tabpage(int after, char_u *filename) newtp->tp_topframe = topframe; last_status(false); + set_winbar(); redraw_all_later(NOT_VALID); @@ -4537,7 +4552,6 @@ void tabpage_move(int nr) redraw_tabline = true; } - /* * Go to another window. * When jumping to another buffer, stop Visual mode. Do this before @@ -4575,7 +4589,6 @@ void win_goto(win_T *wp) } } - /* * Find the tabpage for window "win". */ @@ -5038,7 +5051,6 @@ static win_T *win_alloc(win_T *after, bool hidden) return new_wp; } - // Free one wininfo_T. void free_wininfo(wininfo_T *wip, buf_T *bp) { @@ -5049,7 +5061,6 @@ void free_wininfo(wininfo_T *wip, buf_T *bp) xfree(wip); } - /// Remove window 'wp' from the window list and free the structure. /// /// @param tp tab page "win" is in, NULL for current @@ -5096,6 +5107,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) { @@ -5254,7 +5271,6 @@ static void frame_remove(frame_T *frp) } } - /* * Called from win_new_shellsize() after Rows changed. * This only does the current tab page, others must be done when made active. @@ -5444,7 +5460,6 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col) } } - /* * Set current window height and take care of repositioning other windows to * fit around it. @@ -5460,16 +5475,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; @@ -5499,7 +5507,6 @@ void win_setheight_win(int height, win_T *win) } } - /* * Set the height of a frame to "height" and take care that all frames and * windows inside it are resized. Also resize frames on the left and right if @@ -6110,7 +6117,6 @@ void win_drag_vsep_line(win_T *dragwin, int offset) redraw_all_later(NOT_VALID); } - #define FRACTION_MULT 16384L // Set wp->w_fraction for the current w_wrow and w_height. @@ -6262,7 +6268,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 +6285,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 +6312,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 +6602,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 +6659,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 +6669,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 +6677,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 +6722,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/src/uncrustify.cfg b/src/uncrustify.cfg index 5f1165024a..731224fd8d 100644 --- a/src/uncrustify.cfg +++ b/src/uncrustify.cfg @@ -2219,7 +2219,7 @@ donot_add_nl_before_cpp_comment = false # true/false # # The maximum number of consecutive newlines (3 = 2 blank lines). -nl_max = 3 # unsigned number +nl_max = 2 # unsigned number # The maximum number of consecutive newlines in a function. nl_max_blank_in_func = 0 # unsigned number 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 fc09e4cde0..2728dcf74c 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -785,7 +785,8 @@ describe('API: buffer events:', function() local function lines_subset(first, second) for i = 1,#first do - if first[i] ~= second[i] then + -- need to ignore trailing spaces + if first[i]:gsub(' +$', '') ~= second[i]:gsub(' +$', '') then return false end end @@ -827,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..55535a92e5 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1439,6 +1439,24 @@ describe('API', function() nvim('set_option_value', 'autoread', NIL, {scope = 'local'}) eq(NIL, nvim('get_option_value', 'autoread', {scope = 'local'})) end) + + it('set window options', function() + -- Same as to nvim_win_set_option + nvim('set_option_value', 'colorcolumn', '4,3', {win=0}) + eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'})) + command("set modified hidden") + command("enew") -- edit new buffer, window option is preserved + eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'})) + end) + + it('set local window options', function() + -- Different to nvim_win_set_option + nvim('set_option_value', 'colorcolumn', '4,3', {win=0, scope='local'}) + eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'})) + command("set modified hidden") + command("enew") -- edit new buffer, window option is reset + eq('', nvim('get_option_value', 'colorcolumn', {scope = 'local'})) + end) end) describe('nvim_{get,set}_current_buf, nvim_list_bufs', function() @@ -3102,6 +3120,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 +3654,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 20ea3621f0..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,14 +491,14 @@ 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, 6) + screen = Screen.new(60, 7) screen:attach() command([[let g:id = termopen('"]]..nvim_prog.. [[" -u NONE -i NONE --cmd "set noruler" -D')]]) screen:expect([[ ^ | + | Entering Debug mode. Type "cont" to continue. | cmd: augroup nvim_terminal | > | @@ -512,6 +509,7 @@ describe('sysinit', function() screen:expect([[ ^ | ~ | + ~ | [No Name] | | <" -u NONE -i NONE --cmd "set noruler" -D 1,0-1 All| 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 3b905f1f56..6e06304acd 100644 --- a/test/functional/terminal/cursor_spec.lua +++ b/test/functional/terminal/cursor_spec.lua @@ -5,6 +5,7 @@ local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim local nvim_dir, command = helpers.nvim_dir, helpers.command local nvim_prog = helpers.nvim_prog local eq, eval = helpers.eq, helpers.eval +local matches = helpers.matches local feed_command = helpers.feed_command local hide_cursor = thelpers.hide_cursor local show_cursor = thelpers.show_cursor @@ -177,7 +178,6 @@ describe('cursor with customized highlighting', function() end) describe('buffer cursor position is correct in terminal without number column', function() - if helpers.pending_win32(pending) then return end local screen local function setup_ex_register(str) @@ -525,10 +525,36 @@ describe('buffer cursor position is correct in terminal without number column', eq({6, 1}, eval('nvim_win_get_cursor(0)')) end) end) + + it('at the end of a line with trailing spaces #16234', function() + setup_ex_register('aaaaaaaa ') + feed('<C-R>r') + screen:expect([[ + | + | + | + | + Entering Ex mode. Type "visual" to go to Normal mode. | + :aaaaaaaa {1: } | + {3:-- TERMINAL --} | + ]]) + matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()')) + eq({6, 13}, eval('nvim_win_get_cursor(0)')) + feed([[<C-\><C-N>]]) + screen:expect([[ + | + | + | + | + Entering Ex mode. Type "visual" to go to Normal mode. | + :aaaaaaaa ^ {2: } | + | + ]]) + eq({6, 12}, eval('nvim_win_get_cursor(0)')) + end) end) describe('buffer cursor position is correct in terminal with number column', function() - if helpers.pending_win32(pending) then return end local screen local function setup_ex_register(str) @@ -879,4 +905,31 @@ describe('buffer cursor position is correct in terminal with number column', fun eq({6, 1}, eval('nvim_win_get_cursor(0)')) end) end) + + it('at the end of a line with trailing spaces #16234', function() + setup_ex_register('aaaaaaaa ') + feed('<C-R>r') + screen:expect([[ + {7: 1 } | + {7: 2 } | + {7: 3 } | + {7: 4 } | + {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. | + {7: 6 }:aaaaaaaa {1: } | + {3:-- TERMINAL --} | + ]]) + matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()')) + eq({6, 13}, eval('nvim_win_get_cursor(0)')) + feed([[<C-\><C-N>]]) + screen:expect([[ + {7: 1 } | + {7: 2 } | + {7: 3 } | + {7: 4 } | + {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. | + {7: 6 }:aaaaaaaa ^ {2: } | + | + ]]) + eq({6, 12}, eval('nvim_win_get_cursor(0)')) + end) end) 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 36965a2e98..06c3d47104 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -93,6 +93,15 @@ if(CMAKE_GENERATOR MATCHES "Makefiles") set(MAKE_PRG "$(MAKE)") endif() +if(MINGW AND CMAKE_GENERATOR MATCHES "Ninja") + find_program(MAKE_PRG NAMES mingw32-make) + if(NOT MAKE_PRG) + message(FATAL_ERROR "GNU Make for mingw32 is required to build the dependencies.") + else() + message(STATUS "Found GNU Make for mingw32: ${MAKE_PRG}") + endif() +endif() + if(CMAKE_C_COMPILER_ARG1) set(DEPS_C_COMPILER "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}") else() @@ -130,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) diff --git a/third-party/cmake/BuildLibuv.cmake b/third-party/cmake/BuildLibuv.cmake index 9d0707201f..42650308a8 100644 --- a/third-party/cmake/BuildLibuv.cmake +++ b/third-party/cmake/BuildLibuv.cmake @@ -45,11 +45,24 @@ if(UNIX) CONFIGURE_COMMAND ${UNIX_CFGCMD} MAKE=${MAKE_PRG} INSTALL_COMMAND ${MAKE_PRG} V=1 install) +elseif(MINGW AND CMAKE_CROSSCOMPILING) + # Build libuv for the host + BuildLibuv(TARGET libuv_host + CONFIGURE_COMMAND sh ${DEPS_BUILD_DIR}/src/libuv_host/autogen.sh && ${DEPS_BUILD_DIR}/src/libuv_host/configure --with-pic --disable-shared --prefix=${HOSTDEPS_INSTALL_DIR} CC=${HOST_C_COMPILER} + INSTALL_COMMAND ${MAKE_PRG} V=1 install) + + # Build libuv for the target + BuildLibuv( + CONFIGURE_COMMAND ${UNIX_CFGCMD} --host=${CROSS_TARGET} + INSTALL_COMMAND ${MAKE_PRG} V=1 install) + elseif(WIN32) set(UV_OUTPUT_DIR ${DEPS_BUILD_DIR}/src/libuv/${CMAKE_BUILD_TYPE}) if(MSVC) set(BUILD_SHARED ON) + elseif(MINGW) + set(BUILD_SHARED OFF) else() message(FATAL_ERROR "Trying to build libuv in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}") endif() diff --git a/third-party/cmake/BuildLua.cmake b/third-party/cmake/BuildLua.cmake index 02f762234b..a40cb7dcb2 100644 --- a/third-party/cmake/BuildLua.cmake +++ b/third-party/cmake/BuildLua.cmake @@ -39,6 +39,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") set(LUA_TARGET freebsd) elseif(CMAKE_SYSTEM_NAME MATCHES "BSD") set(CMAKE_LUA_TARGET bsd) +elseif(CMAKE_SYSTEM_NAME MATCHES "^MINGW") + set(CMAKE_LUA_TARGET mingw) else() if(UNIX) set(LUA_TARGET posix) diff --git a/third-party/cmake/BuildLuajit.cmake b/third-party/cmake/BuildLuajit.cmake index 9c0a6cfba2..e02d7fe609 100644 --- a/third-party/cmake/BuildLuajit.cmake +++ b/third-party/cmake/BuildLuajit.cmake @@ -76,6 +76,57 @@ if(UNIX) CC=${DEPS_C_COMPILER} PREFIX=${DEPS_INSTALL_DIR} ${DEPLOYMENT_TARGET}) +elseif(MINGW AND CMAKE_CROSSCOMPILING) + + # Build luajit for the host + BuildLuaJit(TARGET luajit_host + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${INSTALLCMD_UNIX} + CC=${HOST_C_COMPILER} PREFIX=${HOSTDEPS_INSTALL_DIR}) + + # Build luajit for the target + BuildLuaJit( + # Similar to Unix + cross - fPIC + INSTALL_COMMAND + ${MAKE_PRG} PREFIX=${DEPS_INSTALL_DIR} + BUILDMODE=static install + TARGET_SYS=${CMAKE_SYSTEM_NAME} + CROSS=${CROSS_TARGET}- + HOST_CC=${HOST_C_COMPILER} HOST_CFLAGS=${HOST_C_FLAGS} + HOST_LDFLAGS=${HOST_EXE_LINKER_FLAGS} + FILE_T=luajit.exe + Q= + INSTALL_TSYMNAME=luajit.exe) + +elseif(MINGW) + + if(CMAKE_GENERATOR MATCHES "Ninja") + set(LUAJIT_MAKE_PRG ${MAKE_PRG}) + else() + set(LUAJIT_MAKE_PRG ${CMAKE_MAKE_PROGRAM}) + endif() + BuildLuaJit(BUILD_COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER} + PREFIX=${DEPS_INSTALL_DIR} + CFLAGS+=-DLUA_USE_APICHECK + CFLAGS+=-funwind-tables + CCDEBUG+=-g + BUILDMODE=static + # Build a DLL too + COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER} BUILDMODE=dynamic + + INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/luajit.exe ${DEPS_INSTALL_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/lua51.dll ${DEPS_INSTALL_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/lib + # Luarocks searches for lua51.dll in lib + COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/lua51.dll ${DEPS_INSTALL_DIR}/lib + COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/libluajit.a ${DEPS_INSTALL_DIR}/lib + COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/include/luajit-2.1 + COMMAND ${CMAKE_COMMAND} -DFROM_GLOB=${DEPS_BUILD_DIR}/src/luajit/src/*.h -DTO=${DEPS_INSTALL_DIR}/include/luajit-2.1 -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CopyFilesGlob.cmake + COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/bin/lua/jit + COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPS_BUILD_DIR}/src/luajit/src/jit ${DEPS_INSTALL_DIR}/bin/lua/jit + ) elseif(MSVC) BuildLuaJit( diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index 98783d533e..244d1d9fb8 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -56,7 +56,7 @@ endif() # Defaults to 5.1 for bundled LuaJIT/Lua. set(LUA_VERSION "5.1") -if(UNIX) +if(UNIX OR (MINGW AND CMAKE_CROSSCOMPILING)) if(USE_BUNDLED_LUAJIT) list(APPEND LUAROCKS_OPTS @@ -94,9 +94,13 @@ if(UNIX) CONFIGURE_COMMAND ${DEPS_BUILD_DIR}/src/luarocks/configure --prefix=${HOSTDEPS_INSTALL_DIR} --force-config ${LUAROCKS_OPTS} INSTALL_COMMAND ${MAKE_PRG} -j1 bootstrap) -elseif(MSVC) +elseif(MSVC OR MINGW) - set(COMPILER_FLAG /MSVC) + if(MINGW) + set(COMPILER_FLAG /MW) + elseif(MSVC) + set(COMPILER_FLAG /MSVC) + endif() # Ignore USE_BUNDLED_LUAJIT - always ON for native Win32 BuildLuarocks(INSTALL_COMMAND install.bat /FORCECONFIG /NOREG /NOADMIN /Q /F @@ -119,6 +123,9 @@ list(APPEND THIRD_PARTY_DEPS luarocks) if(USE_BUNDLED_LUAJIT) add_dependencies(luarocks luajit) + if(MINGW AND CMAKE_CROSSCOMPILING) + add_dependencies(luarocks luajit_host) + endif() elseif(USE_BUNDLED_LUA) add_dependencies(luarocks lua) endif() @@ -189,6 +196,9 @@ if(USE_BUNDLED_BUSTED) set(LUV_DEPS luacheck) if(USE_BUNDLED_LUV) list(APPEND LUV_DEPS luv-static lua-compat-5.3) + if(MINGW AND CMAKE_CROSSCOMPILING) + list(APPEND LUV_DEPS libuv_host) + endif() set(LUV_ARGS "CFLAGS=-O0 -g3 -fPIC") if(USE_BUNDLED_LIBUV) list(APPEND LUV_ARGS LIBUV_DIR=${HOSTDEPS_INSTALL_DIR}) diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake index 001f5a325a..99822249c2 100644 --- a/third-party/cmake/BuildLuv.cmake +++ b/third-party/cmake/BuildLuv.cmake @@ -91,7 +91,16 @@ if(USE_BUNDLED_LIBUV) -DCMAKE_PREFIX_PATH=${DEPS_INSTALL_DIR}) endif() -if(MSVC) +if(MINGW AND CMAKE_CROSSCOMPILING) + get_filename_component(TOOLCHAIN ${CMAKE_TOOLCHAIN_FILE} REALPATH) + set(LUV_CONFIGURE_COMMAND + ${LUV_CONFIGURE_COMMAND_COMMON} + # Pass toolchain + -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} + "-DCMAKE_C_FLAGS:STRING=${LUV_INCLUDE_FLAGS} -D_WIN32_WINNT=0x0600" + # Hack to avoid -rdynamic in Mingw + -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS="") +elseif(MSVC) set(LUV_CONFIGURE_COMMAND ${LUV_CONFIGURE_COMMAND_COMMON} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} diff --git a/third-party/cmake/BuildMsgpack.cmake b/third-party/cmake/BuildMsgpack.cmake index a89c1e34d0..f66a3bdd32 100644 --- a/third-party/cmake/BuildMsgpack.cmake +++ b/third-party/cmake/BuildMsgpack.cmake @@ -42,7 +42,18 @@ set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack set(MSGPACK_BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE}) set(MSGPACK_INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE}) -if(MSVC) +if(MINGW AND CMAKE_CROSSCOMPILING) + get_filename_component(TOOLCHAIN ${CMAKE_TOOLCHAIN_FILE} REALPATH) + set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack + -DMSGPACK_BUILD_TESTS=OFF + -DMSGPACK_BUILD_EXAMPLES=OFF + -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR} + # Pass toolchain + -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + # Hack to avoid -rdynamic in Mingw + -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS="") +elseif(MSVC) # Same as Unix without fPIC set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack -DMSGPACK_BUILD_TESTS=OFF |